diff --git a/src/gl-renderer.c b/src/gl-renderer.c index 4c1bc233..fdde9ae4 100644 --- a/src/gl-renderer.c +++ b/src/gl-renderer.c @@ -46,10 +46,11 @@ struct gl_shader { GLint color_uniform; }; +#define BUFFER_DAMAGE_COUNT 2 + struct gl_output_state { EGLSurface egl_surface; - int current_buffer; - pixman_region32_t buffer_damage[2]; + pixman_region32_t buffer_damage[BUFFER_DAMAGE_COUNT]; }; struct gl_surface_state { @@ -95,6 +96,8 @@ struct gl_renderer { int has_egl_image_external; + int has_egl_buffer_age; + struct gl_shader texture_shader_rgba; struct gl_shader texture_shader_rgbx; struct gl_shader texture_shader_egl_external; @@ -742,12 +745,10 @@ draw_surface(struct weston_surface *es, struct weston_output *output, struct weston_compositor *ec = es->compositor; struct gl_renderer *gr = get_renderer(ec); struct gl_surface_state *gs = get_surface_state(es); - struct gl_output_state *go = get_output_state(output); /* repaint bounding region in global coordinates: */ pixman_region32_t repaint; /* non-opaque region in surface coordinates: */ pixman_region32_t surface_blend; - pixman_region32_t *buffer_damage; GLint filter; int i; @@ -759,9 +760,6 @@ draw_surface(struct weston_surface *es, struct weston_output *output, if (!pixman_region32_not_empty(&repaint)) goto out; - buffer_damage = &go->buffer_damage[go->current_buffer]; - pixman_region32_subtract(buffer_damage, buffer_damage, &repaint); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); if (ec->fan_debug) { @@ -947,6 +945,51 @@ draw_border(struct weston_output *output) ec->indices.size = 0; } +static void +output_get_buffer_damage(struct weston_output *output, + pixman_region32_t *buffer_damage) +{ + struct gl_output_state *go = get_output_state(output); + struct gl_renderer *gr = get_renderer(output->compositor); + EGLint buffer_age = 0; + EGLBoolean ret; + int i; + + if (gr->has_egl_buffer_age) { + ret = eglQuerySurface(gr->egl_display, go->egl_surface, + EGL_BUFFER_AGE_EXT, &buffer_age); + if (ret == EGL_FALSE) { + weston_log("buffer age query failed.\n"); + gl_renderer_print_egl_error_state(); + } + } + + if (buffer_age == 0 || buffer_age - 1 > BUFFER_DAMAGE_COUNT) + pixman_region32_copy(buffer_damage, &output->region); + else + for (i = 0; i < buffer_age - 1; i++) + pixman_region32_union(buffer_damage, buffer_damage, + &go->buffer_damage[i]); +} + +static void +output_rotate_damage(struct weston_output *output, + pixman_region32_t *output_damage) +{ + struct gl_output_state *go = get_output_state(output); + struct gl_renderer *gr = get_renderer(output->compositor); + int i; + + if (!gr->has_egl_buffer_age) + return; + + for (i = BUFFER_DAMAGE_COUNT - 1; i >= 1; i--) + pixman_region32_copy(&go->buffer_damage[i], + &go->buffer_damage[i - 1]); + + pixman_region32_copy(&go->buffer_damage[0], output_damage); +} + static void gl_renderer_repaint_output(struct weston_output *output, pixman_region32_t *output_damage) @@ -956,8 +999,8 @@ gl_renderer_repaint_output(struct weston_output *output, struct gl_renderer *gr = get_renderer(compositor); EGLBoolean ret; static int errored; - int32_t width, height, i; - pixman_region32_t total_damage; + int32_t width, height; + pixman_region32_t buffer_damage, total_damage; width = output->current->width + output->border.left + output->border.right; @@ -983,18 +1026,18 @@ gl_renderer_repaint_output(struct weston_output *output, pixman_region32_fini(&undamaged); } - for (i = 0; i < 2; i++) - pixman_region32_union(&go->buffer_damage[i], - &go->buffer_damage[i], - output_damage); - pixman_region32_init(&total_damage); - pixman_region32_copy(&total_damage, - &go->buffer_damage[go->current_buffer]); + pixman_region32_init(&buffer_damage); + + output_get_buffer_damage(output, &buffer_damage); + output_rotate_damage(output, output_damage); + + pixman_region32_union(&total_damage, &buffer_damage, output_damage); repaint_surfaces(output, &total_damage); pixman_region32_fini(&total_damage); + pixman_region32_fini(&buffer_damage); if (gr->border.texture) draw_border(output); @@ -1009,8 +1052,6 @@ gl_renderer_repaint_output(struct weston_output *output, gl_renderer_print_egl_error_state(); } - go->current_buffer ^= 1; - } static int @@ -1620,8 +1661,7 @@ gl_renderer_output_create(struct weston_output *output, return -1; } - go->current_buffer = 0; - for (i = 0; i < 2; i++) + for (i = 0; i < BUFFER_DAMAGE_COUNT; i++) pixman_region32_init(&go->buffer_damage[i]); output->renderer_state = go; @@ -1931,6 +1971,12 @@ gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface) gr->has_bind_display = 0; } + if (strstr(extensions, "EGL_EXT_buffer_age")) + gr->has_egl_buffer_age = 1; + else + weston_log("warning: EGL_EXT_buffer_age not supported. " + "Performance could be affected.\n"); + glActiveTexture(GL_TEXTURE0); if (compile_shaders(ec))