From e5512d4014c56a5f82fe17a27f018aadb74fcb12 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Tue, 4 Feb 2014 21:36:38 -0600 Subject: [PATCH] gl-renderer: Track border damage and only repaint borders on an as-needed basis Signed-off-by: Jason Ekstrand --- 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 -- 2.7.4