diff --git a/include/sway/output.h b/include/sway/output.h index d72bf1b21..7ccaa09c9 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "config.h" #include "sway/tree/node.h" @@ -26,7 +27,7 @@ struct sway_output { struct wlr_box usable_area; struct timespec last_frame; - struct wlr_output_damage *damage; + struct wlr_damage_ring damage_ring; int lx, ly; // layout coords int width, height; // transformed buffer size @@ -44,8 +45,9 @@ struct sway_output { struct wl_listener commit; struct wl_listener mode; struct wl_listener present; - struct wl_listener damage_destroy; - struct wl_listener damage_frame; + struct wl_listener damage; + struct wl_listener frame; + struct wl_listener needs_frame; struct { struct wl_signal disable; diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index d44d6338e..6e3cc0e2b 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include "log.h" diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 3f3f9494a..75651a7aa 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -553,31 +552,43 @@ static int output_repaint_timer_handler(void *data) { } } - bool needs_frame; - pixman_region32_t damage; - pixman_region32_init(&damage); - if (!wlr_output_damage_attach_render(output->damage, - &needs_frame, &damage)) { + int buffer_age; + if (!wlr_output_attach_render(output->wlr_output, &buffer_age)) { return 0; } - if (needs_frame) { - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - - output_render(output, &now, &damage); - } else { + pixman_region32_t damage; + pixman_region32_init(&damage); + wlr_damage_ring_get_buffer_damage(&output->damage_ring, buffer_age, &damage); + if (!output->wlr_output->needs_frame && + !pixman_region32_not_empty(&output->damage_ring.current)) { + pixman_region32_fini(&damage); wlr_output_rollback(output->wlr_output); + return 0; } + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + + output_render(output, &now, &damage); + pixman_region32_fini(&damage); return 0; } -static void damage_handle_frame(struct wl_listener *listener, void *user_data) { +static void handle_damage(struct wl_listener *listener, void *user_data) { struct sway_output *output = - wl_container_of(listener, output, damage_frame); + wl_container_of(listener, output, damage); + struct wlr_output_event_damage *event = user_data; + if (wlr_damage_ring_add(&output->damage_ring, event->damage)) { + wlr_output_schedule_frame(output->wlr_output); + } +} + +static void handle_frame(struct wl_listener *listener, void *user_data) { + struct sway_output *output = + wl_container_of(listener, output, frame); if (!output->enabled || !output->wlr_output->enabled) { return; } @@ -640,11 +651,18 @@ static void damage_handle_frame(struct wl_listener *listener, void *user_data) { send_frame_done(output, &data); } +static void handle_needs_frame(struct wl_listener *listener, void *user_data) { + struct sway_output *output = + wl_container_of(listener, output, needs_frame); + wlr_output_schedule_frame(output->wlr_output); +} + void output_damage_whole(struct sway_output *output) { // The output can exist with no wlr_output if it's just been disconnected // and the transaction to evacuate it has't completed yet. - if (output && output->wlr_output && output->damage) { - wlr_output_damage_add_whole(output->damage); + if (output != NULL && output->wlr_output != NULL) { + wlr_damage_ring_add_whole(&output->damage_ring); + wlr_output_schedule_frame(output->wlr_output); } } @@ -668,11 +686,15 @@ static void damage_surface_iterator(struct sway_output *output, ceil(output->wlr_output->scale) - surface->current.scale); } pixman_region32_translate(&damage, box.x, box.y); - wlr_output_damage_add(output->damage, &damage); + if (wlr_damage_ring_add(&output->damage_ring, &damage)) { + wlr_output_schedule_frame(output->wlr_output); + } pixman_region32_fini(&damage); if (whole) { - wlr_output_damage_add_box(output->damage, &box); + if (wlr_damage_ring_add_box(&output->damage_ring, &box)) { + wlr_output_schedule_frame(output->wlr_output); + } } if (!wl_list_empty(&surface->current.frame_callback_list)) { @@ -702,7 +724,9 @@ void output_damage_box(struct sway_output *output, struct wlr_box *_box) { box.x -= output->lx; box.y -= output->ly; scale_box(&box, output->wlr_output->scale); - wlr_output_damage_add_box(output->damage, &box); + if (wlr_damage_ring_add_box(&output->damage_ring, &box)) { + wlr_output_schedule_frame(output->wlr_output); + } } static void damage_child_views_iterator(struct sway_container *con, @@ -726,7 +750,9 @@ void output_damage_whole_container(struct sway_output *output, .height = con->current.height + 2, }; scale_box(&box, output->wlr_output->scale); - wlr_output_damage_add_box(output->damage, &box); + if (wlr_damage_ring_add_box(&output->damage_ring, &box)) { + wlr_output_schedule_frame(output->wlr_output); + } // Damage subsurfaces as well, which may extend outside the box if (con->view) { damage_child_views_iterator(con, output); @@ -735,20 +761,6 @@ void output_damage_whole_container(struct sway_output *output, } } -static void damage_handle_destroy(struct wl_listener *listener, void *data) { - struct sway_output *output = - wl_container_of(listener, output, damage_destroy); - if (!output->enabled) { - return; - } - output_disable(output); - - wl_list_remove(&output->damage_destroy.link); - wl_list_remove(&output->damage_frame.link); - - transaction_commit_dirty(); -} - static void update_output_manager_config(struct sway_server *server) { struct wlr_output_configuration_v1 *config = wlr_output_configuration_v1_create(); @@ -778,18 +790,24 @@ static void update_output_manager_config(struct sway_server *server) { static void handle_destroy(struct wl_listener *listener, void *data) { struct sway_output *output = wl_container_of(listener, output, destroy); struct sway_server *server = output->server; - output_begin_destroy(output); if (output->enabled) { output_disable(output); } + output_begin_destroy(output); + wl_list_remove(&output->link); wl_list_remove(&output->destroy.link); wl_list_remove(&output->commit.link); wl_list_remove(&output->mode.link); wl_list_remove(&output->present.link); + wl_list_remove(&output->damage.link); + wl_list_remove(&output->frame.link); + wl_list_remove(&output->needs_frame.link); + + wlr_damage_ring_finish(&output->damage_ring); output->wlr_output->data = NULL; output->wlr_output = NULL; @@ -817,10 +835,15 @@ static void handle_mode(struct wl_listener *listener, void *data) { if (!output->enabled) { return; } + arrange_layers(output); arrange_output(output); transaction_commit_dirty(); + wlr_damage_ring_set_bounds(&output->damage_ring, + output->width, output->height); + wlr_output_schedule_frame(output->wlr_output); + update_output_manager_config(output->server); } @@ -848,6 +871,14 @@ static void handle_commit(struct wl_listener *listener, void *data) { update_output_manager_config(output->server); } + + if (event->committed & (WLR_OUTPUT_STATE_MODE | + WLR_OUTPUT_STATE_TRANSFORM | + WLR_OUTPUT_STATE_SCALE)) { + wlr_damage_ring_set_bounds(&output->damage_ring, + output->width, output->height); + wlr_output_schedule_frame(output->wlr_output); + } } static void handle_present(struct wl_listener *listener, void *data) { @@ -903,7 +934,7 @@ void handle_new_output(struct wl_listener *listener, void *data) { return; } output->server = server; - output->damage = wlr_output_damage_create(wlr_output); + wlr_damage_ring_init(&output->damage_ring); wl_signal_add(&wlr_output->events.destroy, &output->destroy); output->destroy.notify = handle_destroy; @@ -913,10 +944,12 @@ void handle_new_output(struct wl_listener *listener, void *data) { output->mode.notify = handle_mode; wl_signal_add(&wlr_output->events.present, &output->present); output->present.notify = handle_present; - wl_signal_add(&output->damage->events.frame, &output->damage_frame); - output->damage_frame.notify = damage_handle_frame; - wl_signal_add(&output->damage->events.destroy, &output->damage_destroy); - output->damage_destroy.notify = damage_handle_destroy; + wl_signal_add(&wlr_output->events.damage, &output->damage); + output->damage.notify = handle_damage; + wl_signal_add(&wlr_output->events.frame, &output->frame); + output->frame.notify = handle_frame; + wl_signal_add(&wlr_output->events.needs_frame, &output->needs_frame); + output->needs_frame.notify = handle_needs_frame; output->repaint_timer = wl_event_loop_add_timer(server->wl_event_loop, output_repaint_timer_handler, output); diff --git a/sway/desktop/render.c b/sway/desktop/render.c index ed9ad4906..efa3a0d9e 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -8,8 +8,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -1186,7 +1186,7 @@ renderer_end: enum wl_output_transform transform = wlr_output_transform_invert(wlr_output->transform); - wlr_region_transform(&frame_damage, &output->damage->current, + wlr_region_transform(&frame_damage, &output->damage_ring.current, transform, width, height); if (debug.damage != DAMAGE_DEFAULT) { @@ -1200,5 +1200,7 @@ renderer_end: if (!wlr_output_commit(wlr_output)) { return; } + + wlr_damage_ring_rotate(&output->damage_ring); output->last_frame = *when; } diff --git a/sway/tree/output.c b/sway/tree/output.c index 368f0541c..eccab2f72 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -3,7 +3,6 @@ #include #include #include -#include #include "sway/ipc-server.h" #include "sway/layers.h" #include "sway/output.h"