[PATCH 1/2] gl-renderer: Track border damage and only repaint borders on an as-needed basis

Jason Ekstrand jason at jlekstrand.net
Sat Jan 11 10:34:35 PST 2014


Signed-off-by: Jason Ekstrand <jason at jlekstrand.net>
---
 src/gl-renderer.c | 110 ++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 81 insertions(+), 29 deletions(-)

diff --git a/src/gl-renderer.c b/src/gl-renderer.c
index 0e5afbe..c8dfa4b 100644
--- a/src/gl-renderer.c
+++ b/src/gl-renderer.c
@@ -50,18 +50,29 @@ struct gl_shader {
 
 #define BUFFER_DAMAGE_COUNT 2
 
+enum gl_border_status {
+	BORDER_STATUS_CLEAN = 0,
+	BORDER_TOP_DIRTY = 1 << GL_RENDERER_BORDER_TOP,
+	BORDER_LEFT_DIRTY = 1 << GL_RENDERER_BORDER_LEFT,
+	BORDER_RIGHT_DIRTY = 1 << GL_RENDERER_BORDER_RIGHT,
+	BORDER_BOTTOM_DIRTY = 1 << GL_RENDERER_BORDER_BOTTOM,
+	BORDER_ALL_DIRTY = 0xf,
+	BORDER_SIZE_CHANGED = 0x10
+};
+
 struct gl_border_image {
 	GLuint tex;
 	int32_t width, height;
 	int32_t tex_width;
-	int dirty;
 	void *data;
 };
 
 struct gl_output_state {
 	EGLSurface egl_surface;
 	pixman_region32_t buffer_damage[BUFFER_DAMAGE_COUNT];
+	enum gl_border_status border_damage[BUFFER_DAMAGE_COUNT];
 	struct gl_border_image borders[4];
+	enum gl_border_status border_status;
 };
 
 enum buffer_type {
@@ -597,9 +608,12 @@ repaint_views(struct weston_output *output, pixman_region32_t *damage)
 }
 
 static void
-draw_output_border_texture(struct gl_border_image *img, int32_t x, int32_t y,
+draw_output_border_texture(struct gl_output_state *go,
+			   enum gl_renderer_border_side side,
+			   int32_t x, int32_t y,
 			   int32_t width, int32_t height)
 {
+	struct gl_border_image *img = &go->borders[side];
 	static GLushort indices [] = { 0, 1, 3, 3, 1, 2 };
 
 	if (!img->data) {
@@ -627,7 +641,7 @@ draw_output_border_texture(struct gl_border_image *img, int32_t x, int32_t y,
 		glBindTexture(GL_TEXTURE_2D, img->tex);
 	}
 
-	if (img->dirty) {
+	if (go->border_status & (1 << side)) {
 #ifdef GL_EXT_unpack_subimage
 		glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0);
 		glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
@@ -636,7 +650,6 @@ draw_output_border_texture(struct gl_border_image *img, int32_t x, int32_t y,
 		glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT,
 			     img->tex_width, img->height, 0,
 			     GL_BGRA_EXT, GL_UNSIGNED_BYTE, img->data);
-		img->dirty = 0;
 	}
 
 	GLfloat texcoord[] = {
@@ -665,7 +678,8 @@ draw_output_border_texture(struct gl_border_image *img, int32_t x, int32_t y,
 }
 
 static void
-draw_output_border(struct weston_output *output)
+draw_output_borders(struct weston_output *output,
+		    enum gl_border_status border_status)
 {
 	struct gl_output_state *go = get_output_state(output);
 	struct gl_renderer *gr = get_renderer(output->compositor);
@@ -674,6 +688,9 @@ draw_output_border(struct weston_output *output)
 	struct weston_matrix matrix;
 	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];
@@ -696,23 +713,27 @@ draw_output_border(struct weston_output *output)
 	glUniform1f(shader->alpha_uniform, 1);
 	glActiveTexture(GL_TEXTURE0);
 
-	draw_output_border_texture(top,
-				   0, 0,
-				   full_width, top->height);
-	draw_output_border_texture(left,
-				   0, top->height,
-				   left->width, output->current_mode->height);
-	draw_output_border_texture(right,
-				   full_width - right->width, top->height,
-				   right->width, output->current_mode->height);
-	draw_output_border_texture(bottom,
-				   0, full_height - bottom->height,
-				   full_width, bottom->height);
+	if (border_status & BORDER_TOP_DIRTY)
+		draw_output_border_texture(go, GL_RENDERER_BORDER_TOP,
+					   0, 0,
+					   full_width, top->height);
+	if (border_status & BORDER_LEFT_DIRTY)
+		draw_output_border_texture(go, GL_RENDERER_BORDER_LEFT,
+					   0, top->height,
+					   left->width, output->current_mode->height);
+	if (border_status & BORDER_RIGHT_DIRTY)
+		draw_output_border_texture(go, GL_RENDERER_BORDER_RIGHT,
+					   full_width - right->width, top->height,
+					   right->width, output->current_mode->height);
+	if (border_status & BORDER_BOTTOM_DIRTY)
+		draw_output_border_texture(go, GL_RENDERER_BORDER_BOTTOM,
+					   0, full_height - bottom->height,
+					   full_width, bottom->height);
 }
 
 static void
-output_get_buffer_damage(struct weston_output *output,
-			 pixman_region32_t *buffer_damage)
+output_get_damage(struct weston_output *output,
+		  pixman_region32_t *buffer_damage, uint32_t *border_damage)
 {
 	struct gl_output_state *go = get_output_state(output);
 	struct gl_renderer *gr = get_renderer(output->compositor);
@@ -729,17 +750,31 @@ output_get_buffer_damage(struct weston_output *output,
 		}
 	}
 
-	if (buffer_age == 0 || buffer_age - 1 > BUFFER_DAMAGE_COUNT)
+	if (buffer_age == 0 || buffer_age - 1 > BUFFER_DAMAGE_COUNT) {
 		pixman_region32_copy(buffer_damage, &output->region);
-	else
+		*border_damage = BORDER_ALL_DIRTY;
+	} else {
 		for (i = 0; i < buffer_age - 1; i++)
-			pixman_region32_union(buffer_damage, buffer_damage,
-					      &go->buffer_damage[i]);
+			*border_damage |= go->border_damage[i];
+
+		if (*border_damage & BORDER_SIZE_CHANGED) {
+			/* If we've had a resize, we have to do a full
+			 * repaint. */
+			*border_damage |= BORDER_ALL_DIRTY;
+			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)
+		     pixman_region32_t *output_damage,
+		     enum gl_border_status border_status)
 {
 	struct gl_output_state *go = get_output_state(output);
 	struct gl_renderer *gr = get_renderer(output->compositor);
@@ -748,10 +783,13 @@ output_rotate_damage(struct weston_output *output,
 	if (!gr->has_egl_buffer_age)
 		return;
 
-	for (i = BUFFER_DAMAGE_COUNT - 1; i >= 1; i--)
+	for (i = BUFFER_DAMAGE_COUNT - 1; i >= 1; i--) {
+		go->border_damage[i] = go->border_damage[i - 1];
 		pixman_region32_copy(&go->buffer_damage[i],
 				     &go->buffer_damage[i - 1]);
+	}
 
+	go->border_damage[0] = border_status;
 	pixman_region32_copy(&go->buffer_damage[0], output_damage);
 }
 
@@ -765,6 +803,7 @@ gl_renderer_repaint_output(struct weston_output *output,
 	EGLBoolean ret;
 	static int errored;
 	pixman_region32_t buffer_damage, total_damage;
+	enum gl_border_status border_damage = BORDER_STATUS_CLEAN;
 
 	/* Calculate the viewport */
 	glViewport(go->borders[GL_RENDERER_BORDER_LEFT].width,
@@ -792,17 +831,18 @@ gl_renderer_repaint_output(struct weston_output *output,
 	pixman_region32_init(&total_damage);
 	pixman_region32_init(&buffer_damage);
 
-	output_get_buffer_damage(output, &buffer_damage);
-	output_rotate_damage(output, output_damage);
+	output_get_damage(output, &buffer_damage, &border_damage);
+	output_rotate_damage(output, output_damage, go->border_status);
 
 	pixman_region32_union(&total_damage, &buffer_damage, output_damage);
+	border_damage |= go->border_status;
 
 	repaint_views(output, &total_damage);
 
 	pixman_region32_fini(&total_damage);
 	pixman_region32_fini(&buffer_damage);
 
-	draw_output_border(output);
+	draw_output_borders(output, border_damage);
 
 	pixman_region32_copy(&output->previous_damage, output_damage);
 	wl_signal_emit(&output->frame_signal, output);
@@ -814,6 +854,7 @@ gl_renderer_repaint_output(struct weston_output *output,
 		gl_renderer_print_egl_error_state();
 	}
 
+	go->border_status = BORDER_STATUS_CLEAN;
 }
 
 static int
@@ -1527,11 +1568,22 @@ gl_renderer_output_set_border(struct weston_output *output,
 {
 	struct gl_output_state *go = get_output_state(output);
 
+	if (go->borders[side].width != width ||
+	    go->borders[side].height != height)
+		/* In this case, we have to blow everything and do a full
+		 * repaint. */
+		go->border_status |= BORDER_SIZE_CHANGED | BORDER_ALL_DIRTY;
+
+	if (data == NULL) {
+		width = 0;
+		height = 0;
+	}
+
 	go->borders[side].width = width;
 	go->borders[side].height = height;
 	go->borders[side].tex_width = tex_width;
 	go->borders[side].data = data;
-	go->borders[side].dirty = 1;
+	go->border_status |= 1 << side;
 }
 
 static int
-- 
1.8.4.2



More information about the wayland-devel mailing list