From a776ecbb860608e0f75430a53ea75a6ed19ac746 Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 30 Mar 2018 13:18:50 -0400 Subject: [PATCH] Add lite damage tracking This skips the renderer if nothing has changed, and renders everything otherwise. --- include/sway/output.h | 14 +++- include/sway/server.h | 1 - include/sway/tree/view.h | 4 + sway/desktop/layer_shell.c | 26 +++++-- sway/desktop/output.c | 148 +++++++++++++++++++++++++----------- sway/desktop/wl_shell.c | 1 + sway/desktop/xdg_shell_v6.c | 5 +- sway/desktop/xwayland.c | 13 ++-- sway/tree/container.c | 2 +- sway/tree/output.c | 5 +- sway/tree/view.c | 18 ++++- 11 files changed, 171 insertions(+), 66 deletions(-) diff --git a/include/sway/output.h b/include/sway/output.h index 6fb79987..b4980cd8 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -5,6 +5,7 @@ #include #include #include +#include "sway/tree/view.h" struct sway_server; struct sway_container; @@ -13,17 +14,26 @@ struct sway_output { struct wlr_output *wlr_output; struct sway_container *swayc; struct sway_server *server; - struct timespec last_frame; struct wl_list layers[4]; // sway_layer_surface::link struct wlr_box usable_area; - struct wl_listener frame; + struct timespec last_frame; + struct wlr_output_damage *damage; + struct wl_listener destroy; struct wl_listener mode; struct wl_listener transform; + struct wl_listener damage_destroy; + struct wl_listener damage_frame; + pid_t bg_pid; }; +void output_damage_whole(struct sway_output *output); + +void output_damage_whole_view(struct sway_output *output, + struct sway_view *view); + #endif diff --git a/include/sway/server.h b/include/sway/server.h index db81932f..61f21cdb 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -25,7 +25,6 @@ struct sway_server { struct sway_input_manager *input; struct wl_listener new_output; - struct wl_listener output_frame; struct wlr_layer_shell *layer_shell; struct wl_listener layer_shell_surface; diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 54f6d90e..526a8485 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -113,4 +113,8 @@ void view_close(struct sway_view *view); void view_update_outputs(struct sway_view *view, const struct wlr_box *before); +void view_damage_whole(struct sway_view *view); + +void view_damage_from(struct sway_view *view); + #endif diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index f7e5d19c..5c96659a 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -4,12 +4,13 @@ #include #include #include +#include #include #include #include "sway/layers.h" -#include "sway/tree/layout.h" #include "sway/output.h" #include "sway/server.h" +#include "sway/tree/layout.h" static void apply_exclusive(struct wlr_box *usable_area, uint32_t anchor, int32_t exclusive, @@ -210,20 +211,26 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) { } else { // TODO DAMAGE from surface damage } + wlr_output_damage_add_box(output->damage, &old_geo); + wlr_output_damage_add_box(output->damage, &layer->geo); } } -static void unmap(struct wlr_layer_surface *layer_surface) { - // TODO DAMAGE +static void unmap(struct sway_layer_surface *sway_layer) { + struct wlr_output *wlr_output = sway_layer->layer_surface->output; + if (wlr_output != NULL) { + struct sway_output *output = wlr_output->data; + wlr_output_damage_add_box(output->damage, &sway_layer->geo); + } } static void handle_destroy(struct wl_listener *listener, void *data) { - struct sway_layer_surface *sway_layer = wl_container_of( - listener, sway_layer, destroy); + struct sway_layer_surface *sway_layer = wl_container_of(listener, + sway_layer, destroy); wlr_log(L_DEBUG, "Layer surface destroyed (%s)", sway_layer->layer_surface->namespace); if (sway_layer->layer_surface->mapped) { - unmap(sway_layer->layer_surface); + unmap(sway_layer); } wl_list_remove(&sway_layer->link); wl_list_remove(&sway_layer->destroy.link); @@ -239,13 +246,16 @@ static void handle_destroy(struct wl_listener *listener, void *data) { } static void handle_map(struct wl_listener *listener, void *data) { - // TODO DAMAGE + struct sway_layer_surface *sway_layer = wl_container_of(listener, + sway_layer, map); + struct sway_output *output = sway_layer->layer_surface->output->data; + wlr_output_damage_add_box(output->damage, &sway_layer->geo); } static void handle_unmap(struct wl_listener *listener, void *data) { struct sway_layer_surface *sway_layer = wl_container_of( listener, sway_layer, unmap); - unmap(sway_layer->layer_surface); + unmap(sway_layer); } void handle_layer_shell_surface(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/output.c b/sway/desktop/output.c index f3416c03..ea457996 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -6,18 +6,19 @@ #include #include #include -#include +#include #include +#include #include #include #include "log.h" -#include "sway/tree/container.h" #include "sway/input/input-manager.h" #include "sway/input/seat.h" #include "sway/layers.h" -#include "sway/tree/layout.h" #include "sway/output.h" #include "sway/server.h" +#include "sway/tree/container.h" +#include "sway/tree/layout.h" #include "sway/tree/view.h" /** @@ -145,13 +146,13 @@ static void render_wl_shell_surface(struct wlr_wl_shell_surface *surface, struct render_data { struct sway_output *output; - struct timespec *now; + struct timespec *when; }; -static void output_frame_view(struct sway_container *view, void *data) { +static void render_view(struct sway_container *view, void *data) { struct render_data *rdata = data; struct sway_output *output = rdata->output; - struct timespec *now = rdata->now; + struct timespec *when = rdata->when; struct wlr_output *wlr_output = output->wlr_output; struct sway_view *sway_view = view->sway_view; struct wlr_surface *surface = sway_view->surface; @@ -164,18 +165,18 @@ static void output_frame_view(struct sway_container *view, void *data) { case SWAY_XDG_SHELL_V6_VIEW: { int window_offset_x = view->sway_view->wlr_xdg_surface_v6->geometry.x; int window_offset_y = view->sway_view->wlr_xdg_surface_v6->geometry.y; - render_surface(surface, wlr_output, now, + render_surface(surface, wlr_output, when, view->x - window_offset_x, view->y - window_offset_y, 0); render_xdg_v6_popups(sway_view->wlr_xdg_surface_v6, wlr_output, - now, view->x - window_offset_x, view->y - window_offset_y, 0); + when, view->x - window_offset_x, view->y - window_offset_y, 0); break; } case SWAY_WL_SHELL_VIEW: render_wl_shell_surface(sway_view->wlr_wl_shell_surface, wlr_output, - now, view->x, view->y, 0, false); + when, view->x, view->y, 0, false); break; case SWAY_XWAYLAND_VIEW: - render_surface(surface, wlr_output, now, view->x, view->y, 0); + render_surface(surface, wlr_output, when, view->x, view->y, 0); break; default: break; @@ -195,82 +196,134 @@ static void render_layer(struct sway_output *output, } } -static void handle_output_frame(struct wl_listener *listener, void *data) { - struct sway_output *soutput = wl_container_of(listener, soutput, frame); - struct wlr_output *wlr_output = data; +static void render_output(struct sway_output *output, struct timespec *when, + pixman_region32_t *damage) { + wlr_log(L_DEBUG, "render"); + struct wlr_output *wlr_output = output->wlr_output; struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); - wlr_output_make_current(wlr_output, NULL); wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); + if (!pixman_region32_not_empty(damage)) { + // Output isn't damaged but needs buffer swap + goto renderer_end; + } + + // TODO + int width, height; + wlr_output_transformed_resolution(wlr_output, &width, &height); + pixman_region32_union_rect(damage, damage, 0, 0, width, height); + float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; wlr_renderer_clear(renderer, clear_color); - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - struct wlr_output_layout *layout = root_container.sway_root->output_layout; - const struct wlr_box *output_box = wlr_output_layout_get_box( - layout, wlr_output); + const struct wlr_box *output_box = + wlr_output_layout_get_box(layout, wlr_output); - render_layer(soutput, output_box, &now, - &soutput->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); - render_layer(soutput, output_box, &now, - &soutput->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); + render_layer(output, output_box, when, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); + render_layer(output, output_box, when, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); struct sway_seat *seat = input_manager_current_seat(input_manager); struct sway_container *focus = - sway_seat_get_focus_inactive(seat, soutput->swayc); + sway_seat_get_focus_inactive(seat, output->swayc); struct sway_container *workspace = (focus->type == C_WORKSPACE ? focus : container_parent(focus, C_WORKSPACE)); struct render_data rdata = { - .output = soutput, - .now = &now, + .output = output, + .when = when, }; - container_descendants(workspace, C_VIEW, output_frame_view, &rdata); + container_descendants(workspace, C_VIEW, render_view, &rdata); // render unmanaged views on top struct sway_view *view; wl_list_for_each(view, &root_container.sway_root->unmanaged_views, unmanaged_view_link) { if (view->type == SWAY_XWAYLAND_VIEW) { - // the only kind of unamanged view right now is xwayland override redirect + // the only kind of unamanged view right now is xwayland override + // redirect int view_x = view->wlr_xwayland_surface->x; int view_y = view->wlr_xwayland_surface->y; - render_surface(view->surface, wlr_output, &soutput->last_frame, + render_surface(view->surface, wlr_output, &output->last_frame, view_x, view_y, 0); } } // TODO: Consider revising this when fullscreen windows are supported - render_layer(soutput, output_box, &now, - &soutput->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); - render_layer(soutput, output_box, &now, - &soutput->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); + render_layer(output, output_box, when, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); + render_layer(output, output_box, when, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); +renderer_end: wlr_renderer_end(renderer); - wlr_output_swap_buffers(wlr_output, &now, NULL); - soutput->last_frame = now; + if (!wlr_output_damage_swap_buffers(output->damage, when, damage)) { + return; + } + output->last_frame = *when; } -static void handle_output_destroy(struct wl_listener *listener, void *data) { - struct sway_output *output = wl_container_of(listener, output, destroy); +static void damage_handle_frame(struct wl_listener *listener, void *data) { + struct sway_output *output = + wl_container_of(listener, output, damage_frame); struct wlr_output *wlr_output = data; - wlr_log(L_DEBUG, "Output %p %s removed", wlr_output, wlr_output->name); + if (!wlr_output->enabled) { + return; + } + + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + + bool needs_swap; + pixman_region32_t damage; + pixman_region32_init(&damage); + if (!wlr_output_damage_make_current(output->damage, &needs_swap, &damage)) { + return; + } + + if (needs_swap) { + render_output(output, &now, &damage); + } + + pixman_region32_fini(&damage); + + // TODO: send frame done events here instead of inside render_surface +} + +void output_damage_whole(struct sway_output *output) { + wlr_output_damage_add_whole(output->damage); +} + +void output_damage_whole_view(struct sway_output *output, + struct sway_view *view) { + // TODO + output_damage_whole(output); +} + +static void damage_handle_destroy(struct wl_listener *listener, void *data) { + struct sway_output *output = + wl_container_of(listener, output, damage_destroy); container_output_destroy(output->swayc); } -static void handle_output_mode(struct wl_listener *listener, void *data) { +static void handle_destroy(struct wl_listener *listener, void *data) { + struct sway_output *output = wl_container_of(listener, output, destroy); + container_output_destroy(output->swayc); +} + +static void handle_mode(struct wl_listener *listener, void *data) { struct sway_output *output = wl_container_of(listener, output, mode); arrange_layers(output); arrange_windows(output->swayc, -1, -1); } -static void handle_output_transform(struct wl_listener *listener, void *data) { +static void handle_transform(struct wl_listener *listener, void *data) { struct sway_output *output = wl_container_of(listener, output, transform); arrange_layers(output); arrange_windows(output->swayc, -1, -1); @@ -295,6 +348,8 @@ void handle_new_output(struct wl_listener *listener, void *data) { wlr_output_set_mode(wlr_output, mode); } + output->damage = wlr_output_damage_create(wlr_output); + output->swayc = container_output_create(output); if (!output->swayc) { free(output); @@ -308,14 +363,17 @@ void handle_new_output(struct wl_listener *listener, void *data) { sway_input_manager_configure_xcursor(input_manager); - wl_signal_add(&wlr_output->events.frame, &output->frame); - output->frame.notify = handle_output_frame; wl_signal_add(&wlr_output->events.destroy, &output->destroy); - output->destroy.notify = handle_output_destroy; + output->destroy.notify = handle_destroy; wl_signal_add(&wlr_output->events.mode, &output->mode); - output->mode.notify = handle_output_mode; + output->mode.notify = handle_mode; wl_signal_add(&wlr_output->events.transform, &output->transform); - output->transform.notify = handle_output_transform; + output->transform.notify = handle_transform; + + 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; arrange_layers(output); arrange_windows(&root_container, -1, -1); diff --git a/sway/desktop/wl_shell.c b/sway/desktop/wl_shell.c index 4d4d1ed7..4fcc6317 100644 --- a/sway/desktop/wl_shell.c +++ b/sway/desktop/wl_shell.c @@ -67,6 +67,7 @@ static void handle_commit(struct wl_listener *listener, void *data) { // TODO: Let floating views do whatever view->width = sway_surface->pending_width; view->height = sway_surface->pending_height; + view_damage_from(view); } static void handle_destroy(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 01f38d16..68abc120 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -76,6 +76,7 @@ static void handle_commit(struct wl_listener *listener, void *data) { // TODO: Let floating views do whatever view->width = sway_surface->pending_width; view->height = sway_surface->pending_height; + view_damage_from(view); } static void handle_destroy(struct wl_listener *listener, void *data) { @@ -123,12 +124,12 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { sway_view->sway_xdg_surface_v6 = sway_surface; sway_view->surface = xdg_surface->surface; sway_surface->view = sway_view; - + // TODO: // - Look up pid and open on appropriate workspace // - Set new view to maximized so it behaves nicely // - Criteria - + sway_surface->commit.notify = handle_commit; wl_signal_add(&xdg_surface->surface->events.commit, &sway_surface->commit); diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index dfc54e86..79c675a0 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -14,10 +14,10 @@ #include "sway/input/input-manager.h" #include "log.h" - static bool assert_xwayland(struct sway_view *view) { - return sway_assert(view->type == SWAY_XWAYLAND_VIEW && view->wlr_xwayland_surface, - "Expected xwayland view!"); - } +static bool assert_xwayland(struct sway_view *view) { + return sway_assert(view->type == SWAY_XWAYLAND_VIEW, + "Expected xwayland view!"); +} static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) { if (!assert_xwayland(view)) { @@ -99,6 +99,7 @@ static void handle_commit(struct wl_listener *listener, void *data) { // TODO: Let floating views do whatever view->width = sway_surface->pending_width; view->height = sway_surface->pending_height; + view_damage_from(view); } static void handle_destroy(struct wl_listener *listener, void *data) { @@ -117,7 +118,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { static void handle_unmap(struct wl_listener *listener, void *data) { struct sway_xwayland_surface *sway_surface = wl_container_of(listener, sway_surface, unmap); - + view_damage_whole(sway_surface->view); wl_list_remove(&sway_surface->view->unmanaged_view_link); wl_list_init(&sway_surface->view->unmanaged_view_link); container_view_destroy(sway_surface->view->swayc); @@ -150,6 +151,8 @@ static void handle_map(struct wl_listener *listener, void *data) { arrange_windows(cont->parent, -1, -1); sway_input_manager_set_focus(input_manager, cont); } + + view_damage_whole(sway_surface->view); } static void handle_configure_request(struct wl_listener *listener, void *data) { diff --git a/sway/tree/container.c b/sway/tree/container.c index c3cf6c64..8705edc7 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -6,8 +6,8 @@ #include #include #include +#include "log.h" #include "sway/config.h" -#include "sway/tree/container.h" #include "sway/input/input-manager.h" #include "sway/input/seat.h" #include "sway/ipc-server.h" diff --git a/sway/tree/output.c b/sway/tree/output.c index 2246cb11..7248fd00 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -26,9 +26,12 @@ struct sway_container *container_output_destroy(struct sway_container *output) { } } - wl_list_remove(&output->sway_output->frame.link); wl_list_remove(&output->sway_output->destroy.link); wl_list_remove(&output->sway_output->mode.link); + wl_list_remove(&output->sway_output->transform.link); + + wl_list_remove(&output->sway_output->damage_destroy.link); + wl_list_remove(&output->sway_output->damage_frame.link); wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name); container_destroy(output); diff --git a/sway/tree/view.c b/sway/tree/view.c index 480ff693..b7d1a41b 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -1,9 +1,10 @@ #include #include +#include "log.h" +#include "sway/output.h" #include "sway/tree/container.h" #include "sway/tree/layout.h" #include "sway/tree/view.h" -#include "log.h" const char *view_get_title(struct sway_view *view) { if (view->iface.get_prop) { @@ -105,3 +106,18 @@ struct sway_container *container_view_destroy(struct sway_container *view) { arrange_windows(parent, -1, -1); return parent; } + +void view_damage_whole(struct sway_view *view) { + struct sway_container *cont = NULL; + for (int i = 0; i < root_container.children->length; ++i) { + cont = root_container.children->items[i]; + if (cont->type == C_OUTPUT) { + output_damage_whole_view(cont->sway_output, view); + } + } +} + +void view_damage_from(struct sway_view *view) { + // TODO + view_damage_whole(view); +}