diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h index 49804d83..74f55288 100644 --- a/include/wlr/types/wlr_scene.h +++ b/include/wlr/types/wlr_scene.h @@ -22,6 +22,7 @@ #include #include #include +#include struct wlr_output; struct wlr_output_layout; @@ -160,7 +161,7 @@ struct wlr_scene_output { struct wlr_scene *scene; struct wlr_addon addon; - struct wlr_output_damage *damage; + struct wlr_damage_ring damage_ring; int x, y; @@ -175,6 +176,7 @@ struct wlr_scene_output { struct wl_listener output_commit; struct wl_listener output_mode; + struct wl_listener output_needs_frame; }; /** A layer shell scene helper */ diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 4cdf4be8..0b127e60 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -5,8 +5,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -422,8 +422,11 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff wlr_region_scale_xy(&output_damage, &trans_damage, output_scale * scale_x, output_scale * scale_y); pixman_region32_translate(&output_damage, - (lx - scene_output->x) * output_scale, (ly - scene_output->y) * output_scale); - wlr_output_damage_add(scene_output->damage, &output_damage); + (lx - scene_output->x) * output_scale, + (ly - scene_output->y) * output_scale); + if (wlr_damage_ring_add(&scene_output->damage_ring, &output_damage)) { + wlr_output_schedule_frame(scene_output->output); + } pixman_region32_fini(&output_damage); } @@ -572,7 +575,9 @@ static void _scene_node_damage_whole(struct wlr_scene_node *node, scale_box(&box, scene_output->output->scale); - wlr_output_damage_add_box(scene_output->damage, &box); + if (wlr_damage_ring_add_box(&scene_output->damage_ring, &box)) { + wlr_output_schedule_frame(scene_output->output); + } } } @@ -969,6 +974,15 @@ static const struct wlr_addon_interface output_addon_impl = { .destroy = scene_output_handle_destroy, }; +static void scene_output_update_geometry(struct wlr_scene_output *scene_output) { + int width, height; + wlr_output_transformed_resolution(scene_output->output, &width, &height); + wlr_damage_ring_set_bounds(&scene_output->damage_ring, width, height); + wlr_output_schedule_frame(scene_output->output); + + scene_node_update_outputs(&scene_output->scene->tree.node, NULL); +} + static void scene_output_handle_commit(struct wl_listener *listener, void *data) { struct wlr_scene_output *scene_output = wl_container_of(listener, scene_output, output_commit); @@ -977,14 +991,20 @@ static void scene_output_handle_commit(struct wl_listener *listener, void *data) if (event->committed & (WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_TRANSFORM | WLR_OUTPUT_STATE_SCALE)) { - scene_node_update_outputs(&scene_output->scene->tree.node, NULL); + scene_output_update_geometry(scene_output); } } static void scene_output_handle_mode(struct wl_listener *listener, void *data) { struct wlr_scene_output *scene_output = wl_container_of(listener, scene_output, output_mode); - scene_node_update_outputs(&scene_output->scene->tree.node, NULL); + scene_output_update_geometry(scene_output); +} + +static void scene_output_handle_needs_frame(struct wl_listener *listener, void *data) { + struct wlr_scene_output *scene_output = wl_container_of(listener, + scene_output, output_needs_frame); + wlr_output_schedule_frame(scene_output->output); } struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, @@ -994,16 +1014,12 @@ struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, return NULL; } - scene_output->damage = wlr_output_damage_create(output); - if (scene_output->damage == NULL) { - free(scene_output); - return NULL; - } - scene_output->output = output; scene_output->scene = scene; wlr_addon_init(&scene_output->addon, &output->addons, scene, &output_addon_impl); + wlr_damage_ring_init(&scene_output->damage_ring); + int prev_output_index = -1; struct wl_list *prev_output_link = &scene->outputs; @@ -1029,8 +1045,10 @@ struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, scene_output->output_mode.notify = scene_output_handle_mode; wl_signal_add(&output->events.mode, &scene_output->output_mode); - wlr_output_damage_add_whole(scene_output->damage); - scene_node_update_outputs(&scene->tree.node, NULL); + scene_output->output_needs_frame.notify = scene_output_handle_needs_frame; + wl_signal_add(&output->events.needs_frame, &scene_output->output_needs_frame); + + scene_output_update_geometry(scene_output); return scene_output; } @@ -1045,9 +1063,11 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) { scene_node_update_outputs(&scene_output->scene->tree.node, scene_output); wlr_addon_finish(&scene_output->addon); + wlr_damage_ring_finish(&scene_output->damage_ring); wl_list_remove(&scene_output->link); wl_list_remove(&scene_output->output_commit.link); wl_list_remove(&scene_output->output_mode.link); + wl_list_remove(&scene_output->output_needs_frame.link); free(scene_output); } @@ -1072,9 +1092,8 @@ void wlr_scene_output_set_position(struct wlr_scene_output *scene_output, scene_output->x = lx; scene_output->y = ly; - wlr_output_damage_add_whole(scene_output->damage); - scene_node_update_outputs(&scene_output->scene->tree.node, NULL); + scene_output_update_geometry(scene_output); } struct check_scanout_data { @@ -1174,7 +1193,7 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { wlr_log(WLR_DEBUG, "Direct scan-out %s", scanout ? "enabled" : "disabled"); // When exiting direct scan-out, damage everything - wlr_output_damage_add_whole(scene_output->damage); + wlr_damage_ring_add_whole(&scene_output->damage_ring); } scene_output->prev_scanout = scanout; if (scanout) { @@ -1182,7 +1201,7 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { } if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_RERENDER) { - wlr_output_damage_add_whole(scene_output->damage); + wlr_damage_ring_add_whole(&scene_output->damage_ring); } struct timespec now; @@ -1191,13 +1210,13 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { clock_gettime(CLOCK_MONOTONIC, &now); // add the current frame's damage if there is damage - if (pixman_region32_not_empty(&scene_output->damage->current)) { + if (pixman_region32_not_empty(&scene_output->damage_ring.current)) { struct highlight_region *current_damage = calloc(1, sizeof(*current_damage)); if (current_damage) { pixman_region32_init(¤t_damage->region); pixman_region32_copy(¤t_damage->region, - &scene_output->damage->current); + &scene_output->damage_ring.current); memcpy(¤t_damage->when, &now, sizeof(now)); wl_list_insert(regions, ¤t_damage->link); } @@ -1220,20 +1239,21 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { } } - wlr_output_damage_add(scene_output->damage, &acc_damage); + wlr_damage_ring_add(&scene_output->damage_ring, &acc_damage); pixman_region32_fini(&acc_damage); } - bool needs_frame; - pixman_region32_t damage; - pixman_region32_init(&damage); - if (!wlr_output_damage_attach_render(scene_output->damage, - &needs_frame, &damage)) { - pixman_region32_fini(&damage); + int buffer_age; + if (!wlr_output_attach_render(output, &buffer_age)) { return false; } - if (!needs_frame) { + pixman_region32_t damage; + pixman_region32_init(&damage); + wlr_damage_ring_get_buffer_damage(&scene_output->damage_ring, + buffer_age, &damage); + if (!output->needs_frame && !pixman_region32_not_empty( + &scene_output->damage_ring.current)) { pixman_region32_fini(&damage); wlr_output_rollback(output); return true; @@ -1294,13 +1314,18 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { pixman_region32_t frame_damage; pixman_region32_init(&frame_damage); - wlr_region_transform(&frame_damage, &scene_output->damage->current, + wlr_region_transform(&frame_damage, + &scene_output->damage_ring.current, transform, tr_width, tr_height); wlr_output_set_damage(output, &frame_damage); pixman_region32_fini(&frame_damage); bool success = wlr_output_commit(output); + if (success) { + wlr_damage_ring_rotate(&scene_output->damage_ring); + } + if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT && !wl_list_empty(&scene_output->scene->damage_highlight_regions)) { wlr_output_schedule_frame(scene_output->output);