[PATCH 2/2] gl-renderer: Use eglSwapBuffersWithDamageEXT when available
Jason Ekstrand
jason at jlekstrand.net
Thu Jan 16 20:52:43 PST 2014
Signed-off-by: Jason Ekstrand <jason at jlekstrand.net>
---
The second version properly sets the EGL_SWAP_BEHAVIOR surface attribute to
EGL_BUFFER_PRESERVED.
src/gl-renderer.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 103 insertions(+), 1 deletion(-)
diff --git a/src/gl-renderer.c b/src/gl-renderer.c
index c8dfa4b..eddf481 100644
--- a/src/gl-renderer.c
+++ b/src/gl-renderer.c
@@ -124,6 +124,8 @@ struct gl_renderer {
PFNEGLCREATEIMAGEKHRPROC create_image;
PFNEGLDESTROYIMAGEKHRPROC destroy_image;
+ PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage;
+
int has_unpack_subimage;
PFNEGLBINDWAYLANDDISPLAYWL bind_display;
@@ -677,6 +679,17 @@ draw_output_border_texture(struct gl_output_state *go,
glDisableVertexAttribArray(0);
}
+static int
+output_has_borders(struct weston_output *output)
+{
+ struct gl_output_state *go = get_output_state(output);
+
+ return go->borders[GL_RENDERER_BORDER_TOP].data ||
+ go->borders[GL_RENDERER_BORDER_RIGHT].data ||
+ go->borders[GL_RENDERER_BORDER_BOTTOM].data ||
+ go->borders[GL_RENDERER_BORDER_LEFT].data;
+}
+
static void
draw_output_borders(struct weston_output *output,
enum gl_border_status border_status)
@@ -732,6 +745,43 @@ draw_output_borders(struct weston_output *output,
}
static void
+output_get_border_damage(struct weston_output *output,
+ enum gl_border_status border_status,
+ pixman_region32_t *damage)
+{
+ struct gl_output_state *go = get_output_state(output);
+ struct gl_border_image *top, *bottom, *left, *right;
+ int full_width, full_height;
+
+ if (border_status == BORDER_STATUS_CLEAN)
+ return; /* Clean. Nothing to do. */
+
+ top = &go->borders[GL_RENDERER_BORDER_TOP];
+ bottom = &go->borders[GL_RENDERER_BORDER_BOTTOM];
+ left = &go->borders[GL_RENDERER_BORDER_LEFT];
+ right = &go->borders[GL_RENDERER_BORDER_RIGHT];
+
+ full_width = output->current_mode->width + left->width + right->width;
+ full_height = output->current_mode->height + top->height + bottom->height;
+ if (border_status & BORDER_TOP_DIRTY)
+ pixman_region32_union_rect(damage, damage,
+ 0, 0,
+ full_width, top->height);
+ if (border_status & BORDER_LEFT_DIRTY)
+ pixman_region32_union_rect(damage, damage,
+ 0, top->height,
+ left->width, output->current_mode->height);
+ if (border_status & BORDER_RIGHT_DIRTY)
+ pixman_region32_union_rect(damage, damage,
+ full_width - right->width, top->height,
+ right->width, output->current_mode->height);
+ if (border_status & BORDER_BOTTOM_DIRTY)
+ pixman_region32_union_rect(damage, damage,
+ 0, full_height - bottom->height,
+ full_width, bottom->height);
+}
+
+static void
output_get_damage(struct weston_output *output,
pixman_region32_t *buffer_damage, uint32_t *border_damage)
{
@@ -802,6 +852,9 @@ gl_renderer_repaint_output(struct weston_output *output,
struct gl_renderer *gr = get_renderer(compositor);
EGLBoolean ret;
static int errored;
+ int i, nrects, buffer_height;
+ EGLint *egl_damage, *d;
+ pixman_box32_t *rects;
pixman_region32_t buffer_damage, total_damage;
enum gl_border_status border_damage = BORDER_STATUS_CLEAN;
@@ -847,7 +900,44 @@ gl_renderer_repaint_output(struct weston_output *output,
pixman_region32_copy(&output->previous_damage, output_damage);
wl_signal_emit(&output->frame_signal, output);
- ret = eglSwapBuffers(gr->egl_display, go->egl_surface);
+ if (gr->swap_buffers_with_damage && gr->has_egl_buffer_age) {
+ pixman_region32_init(&buffer_damage);
+ weston_transformed_region(output->width, output->height,
+ output->transform,
+ output->current_scale,
+ output_damage, &buffer_damage);
+
+ if (output_has_borders(output)) {
+ pixman_region32_translate(&buffer_damage,
+ go->borders[GL_RENDERER_BORDER_LEFT].width,
+ go->borders[GL_RENDERER_BORDER_TOP].height);
+ output_get_border_damage(output, go->border_status,
+ &buffer_damage);
+ }
+
+ rects = pixman_region32_rectangles(&buffer_damage, &nrects);
+ egl_damage = malloc(nrects * 4 * sizeof(EGLint));
+
+ buffer_height = go->borders[GL_RENDERER_BORDER_TOP].height +
+ output->current_mode->height +
+ go->borders[GL_RENDERER_BORDER_BOTTOM].height;
+
+ d = egl_damage;
+ for (i = 0; i < nrects; ++i) {
+ *d++ = rects[i].x1;
+ *d++ = buffer_height - rects[i].y2;
+ *d++ = rects[i].x2 - rects[i].x1;
+ *d++ = rects[i].y2 - rects[i].y1;
+ }
+ ret = gr->swap_buffers_with_damage(gr->egl_display,
+ go->egl_surface,
+ egl_damage, nrects);
+ free(egl_damage);
+ pixman_region32_fini(&buffer_damage);
+ } else {
+ ret = eglSwapBuffers(gr->egl_display, go->egl_surface);
+ }
+
if (ret == EGL_FALSE && !errored) {
errored = 1;
weston_log("Failed in eglSwapBuffers.\n");
@@ -1618,6 +1708,11 @@ gl_renderer_output_create(struct weston_output *output,
return -1;
}
+ if (gr->swap_buffers_with_damage && gr->has_egl_buffer_age) {
+ eglSurfaceAttrib(gr->egl_display, go->egl_surface,
+ EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
+ }
+
for (i = 0; i < BUFFER_DAMAGE_COUNT; i++)
pixman_region32_init(&go->buffer_damage[i]);
@@ -1958,6 +2053,13 @@ gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface)
weston_log("warning: EGL_EXT_buffer_age not supported. "
"Performance could be affected.\n");
+ if (strstr(extensions, "EGL_EXT_swap_buffers_with_damage"))
+ gr->swap_buffers_with_damage =
+ (void *) eglGetProcAddress("eglSwapBuffersWithDamageEXT");
+ else
+ weston_log("warning: EGL_EXT_swap_buffers_with_damage not "
+ "supported. Performance could be affected.\n");
+
glActiveTexture(GL_TEXTURE0);
if (compile_shaders(ec))
--
1.8.4.2
More information about the wayland-devel
mailing list