[PATCH weston 4/4] gl-renderer: Use EXT_buffer_age and don't assume double buffering

Ander Conselvan de Oliveira ander.conselvan.de.oliveira at intel.com
Tue Mar 5 07:30:30 PST 2013


Now that we have EXT_buffer_age in mesa, we should stop assuming double
buffering and use the buffer age instead.

Note: this will cause system without the extension to repaint the whole
screen every frame.
---
 src/gl-renderer.c |   86 ++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 66 insertions(+), 20 deletions(-)

diff --git a/src/gl-renderer.c b/src/gl-renderer.c
index 4c1bc23..fdde9ae 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) {
@@ -948,6 +946,51 @@ draw_border(struct weston_output *output)
 }
 
 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))
-- 
1.7.10.4



More information about the wayland-devel mailing list