rootston: don't submit too much damage

We only need to damage the parts of the screen that changed since last frame,
we don't need to accumulate damage from previous buffers.

We still need to re-render the accumulated damage.

Fixes https://github.com/swaywm/wlroots/issues/1665
This commit is contained in:
Simon Ser 2019-04-25 19:39:44 +03:00 committed by Drew DeVault
parent d6e250b389
commit 57d32d03a8
1 changed files with 31 additions and 23 deletions

View File

@ -58,7 +58,7 @@ static void render_texture(struct wlr_output *wlr_output,
pixman_region32_intersect(&damage, &damage, output_damage); pixman_region32_intersect(&damage, &damage, output_damage);
bool damaged = pixman_region32_not_empty(&damage); bool damaged = pixman_region32_not_empty(&damage);
if (!damaged) { if (!damaged) {
goto damage_finish; goto buffer_damage_finish;
} }
int nrects; int nrects;
@ -68,7 +68,7 @@ static void render_texture(struct wlr_output *wlr_output,
wlr_render_texture_with_matrix(renderer, texture, matrix, alpha); wlr_render_texture_with_matrix(renderer, texture, matrix, alpha);
} }
damage_finish: buffer_damage_finish:
pixman_region32_fini(&damage); pixman_region32_fini(&damage);
} }
@ -121,7 +121,7 @@ static void render_decorations(struct roots_output *output,
pixman_region32_intersect(&damage, &damage, data->damage); pixman_region32_intersect(&damage, &damage, data->damage);
bool damaged = pixman_region32_not_empty(&damage); bool damaged = pixman_region32_not_empty(&damage);
if (!damaged) { if (!damaged) {
goto damage_finish; goto buffer_damage_finish;
} }
float matrix[9]; float matrix[9];
@ -137,7 +137,7 @@ static void render_decorations(struct roots_output *output,
wlr_render_quad_with_matrix(renderer, color, matrix); wlr_render_quad_with_matrix(renderer, color, matrix);
} }
damage_finish: buffer_damage_finish:
pixman_region32_fini(&damage); pixman_region32_fini(&damage);
} }
@ -221,25 +221,26 @@ void output_render(struct roots_output *output) {
} }
bool needs_frame; bool needs_frame;
pixman_region32_t damage; pixman_region32_t buffer_damage;
pixman_region32_init(&damage); pixman_region32_init(&buffer_damage);
if (!wlr_output_damage_attach_render(output->damage, &needs_frame, &damage)) { if (!wlr_output_damage_attach_render(output->damage, &needs_frame,
&buffer_damage)) {
return; return;
} }
struct render_data data = { struct render_data data = {
.damage = &damage, .damage = &buffer_damage,
.alpha = 1.0, .alpha = 1.0,
}; };
if (!needs_frame) { if (!needs_frame) {
// Output doesn't need swap and isn't damaged, skip rendering completely // Output doesn't need swap and isn't damaged, skip rendering completely
goto damage_finish; goto buffer_damage_finish;
} }
wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height);
if (!pixman_region32_not_empty(&damage)) { if (!pixman_region32_not_empty(&buffer_damage)) {
// Output isn't damaged but needs buffer swap // Output isn't damaged but needs buffer swap
goto renderer_end; goto renderer_end;
} }
@ -249,15 +250,15 @@ void output_render(struct roots_output *output) {
} }
int nrects; int nrects;
pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); pixman_box32_t *rects = pixman_region32_rectangles(&buffer_damage, &nrects);
for (int i = 0; i < nrects; ++i) { for (int i = 0; i < nrects; ++i) {
scissor_output(output->wlr_output, &rects[i]); scissor_output(output->wlr_output, &rects[i]);
wlr_renderer_clear(renderer, clear_color); wlr_renderer_clear(renderer, clear_color);
} }
render_layer(output, &damage, render_layer(output, &buffer_damage,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]);
render_layer(output, &damage, render_layer(output, &buffer_damage,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);
// If a view is fullscreen on this output, render it // If a view is fullscreen on this output, render it
@ -285,39 +286,46 @@ void output_render(struct roots_output *output) {
render_view(output, view, &data); render_view(output, view, &data);
} }
// Render top layer above shell views // Render top layer above shell views
render_layer(output, &damage, render_layer(output, &buffer_damage,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]);
} }
render_drag_icons(output, &damage, server->input); render_drag_icons(output, &buffer_damage, server->input);
render_layer(output, &damage, render_layer(output, &buffer_damage,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]);
renderer_end: renderer_end:
wlr_output_render_software_cursors(wlr_output, &damage); wlr_output_render_software_cursors(wlr_output, &buffer_damage);
wlr_renderer_scissor(renderer, NULL); wlr_renderer_scissor(renderer, NULL);
wlr_renderer_end(renderer); wlr_renderer_end(renderer);
int width, height; int width, height;
wlr_output_transformed_resolution(wlr_output, &width, &height); wlr_output_transformed_resolution(wlr_output, &width, &height);
pixman_region32_t output_damage;
pixman_region32_init(&output_damage);
if (server->config->debug_damage_tracking) { if (server->config->debug_damage_tracking) {
pixman_region32_union_rect(&damage, &damage, 0, 0, width, height); pixman_region32_union_rect(&output_damage, &output_damage,
0, 0, width, height);
} }
enum wl_output_transform transform = enum wl_output_transform transform =
wlr_output_transform_invert(wlr_output->transform); wlr_output_transform_invert(wlr_output->transform);
wlr_region_transform(&damage, &damage, transform, width, height); wlr_region_transform(&output_damage, &output->damage->current,
transform, width, height);
wlr_output_set_damage(wlr_output, &output_damage);
pixman_region32_fini(&output_damage);
wlr_output_set_damage(wlr_output, &damage);
if (!wlr_output_commit(wlr_output)) { if (!wlr_output_commit(wlr_output)) {
goto damage_finish; goto buffer_damage_finish;
} }
output->last_frame = desktop->last_frame = now; output->last_frame = desktop->last_frame = now;
damage_finish: buffer_damage_finish:
pixman_region32_fini(&damage); pixman_region32_fini(&buffer_damage);
// Send frame done events to all surfaces // Send frame done events to all surfaces
output_for_each_surface(output, surface_send_frame_done_iterator, &now); output_for_each_surface(output, surface_send_frame_done_iterator, &now);