From 1a084807ce6ce1d8e4b8c35e3195240507ebffe8 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 18 Jan 2018 03:31:46 +0100 Subject: [PATCH 01/75] rootston: do not redraw if output has no damage --- include/rootston/desktop.h | 17 ++------ include/rootston/output.h | 26 +++++++++++ rootston/desktop.c | 18 +++++--- rootston/meson.build | 2 +- rootston/output.c | 88 +++++++++++++++++++++++++++----------- rootston/xdg_shell_v6.c | 2 + 6 files changed, 108 insertions(+), 45 deletions(-) create mode 100644 include/rootston/output.h diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h index 9dfd7b10..3d0e2a2b 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -16,15 +16,7 @@ #include #include "rootston/view.h" #include "rootston/config.h" - -struct roots_output { - struct roots_desktop *desktop; - struct wlr_output *wlr_output; - struct wl_listener frame; - struct timespec last_frame; - struct wl_list link; // roots_desktop:outputs - struct roots_view *fullscreen_view; -}; +#include "rootston/output.h" struct roots_desktop { struct wl_list views; // roots_view::link @@ -64,20 +56,19 @@ struct roots_desktop { struct roots_server; struct roots_desktop *desktop_create(struct roots_server *server, - struct roots_config *config); + struct roots_config *config); void desktop_destroy(struct roots_desktop *desktop); struct roots_output *desktop_output_from_wlr_output( struct roots_desktop *desktop, struct wlr_output *output); struct roots_view *desktop_view_at(struct roots_desktop *desktop, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy); +void desktop_damage_surface(struct roots_desktop *desktop, + struct wlr_surface *surface, double lx, double ly); void view_init(struct roots_view *view, struct roots_desktop *desktop); void view_destroy(struct roots_view *view); void view_activate(struct roots_view *view, bool activate); -void output_add_notify(struct wl_listener *listener, void *data); -void output_remove_notify(struct wl_listener *listener, void *data); - void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data); void handle_wl_shell_surface(struct wl_listener *listener, void *data); void handle_xwayland_surface(struct wl_listener *listener, void *data); diff --git a/include/rootston/output.h b/include/rootston/output.h new file mode 100644 index 00000000..e7f49227 --- /dev/null +++ b/include/rootston/output.h @@ -0,0 +1,26 @@ +#ifndef _ROOTSTON_OUTPUT_H +#define _ROOTSTON_OUTPUT_H + +#include +#include +#include + +struct roots_desktop; + +struct roots_output { + struct roots_desktop *desktop; + struct wlr_output *wlr_output; + struct wl_listener frame; + struct timespec last_frame; + struct wl_list link; // roots_desktop:outputs + struct roots_view *fullscreen_view; + pixman_region32_t damage; +}; + +void output_add_notify(struct wl_listener *listener, void *data); +void output_remove_notify(struct wl_listener *listener, void *data); + +void output_damage_surface(struct roots_output *output, + struct wlr_surface *surface, double lx, double ly); + +#endif diff --git a/rootston/desktop.c b/rootston/desktop.c index d7da1600..3b8e6602 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -513,12 +513,20 @@ void desktop_destroy(struct roots_desktop *desktop) { } struct roots_output *desktop_output_from_wlr_output( - struct roots_desktop *desktop, struct wlr_output *output) { - struct roots_output *roots_output; - wl_list_for_each(roots_output, &desktop->outputs, link) { - if (roots_output->wlr_output == output) { - return roots_output; + struct roots_desktop *desktop, struct wlr_output *wlr_output) { + struct roots_output *output; + wl_list_for_each(output, &desktop->outputs, link) { + if (output->wlr_output == wlr_output) { + return output; } } return NULL; } + +void desktop_damage_surface(struct roots_desktop *desktop, + struct wlr_surface *surface, double lx, double ly) { + struct roots_output *output; + wl_list_for_each(output, &desktop->outputs, link) { + output_damage_surface(output, surface, lx, ly); + } +} diff --git a/rootston/meson.build b/rootston/meson.build index 36b6241a..973f93a4 100644 --- a/rootston/meson.build +++ b/rootston/meson.build @@ -15,5 +15,5 @@ if get_option('enable_xwayland') sources += ['xwayland.c'] endif executable( - 'rootston', sources, dependencies: [wlroots, wlr_protos] + 'rootston', sources, dependencies: [wlroots, wlr_protos, pixman] ) diff --git a/rootston/output.c b/rootston/output.c index c26ea36e..22b8615a 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -10,7 +10,7 @@ #include #include #include "rootston/server.h" -#include "rootston/desktop.h" +#include "rootston/output.h" #include "rootston/config.h" /** @@ -31,6 +31,23 @@ static void rotate_child_position(double *sx, double *sy, double sw, double sh, } } +static bool surface_intersect_output(struct wlr_surface *surface, + struct wlr_output_layout *output_layout, struct wlr_output *wlr_output, + double lx, double ly, struct wlr_box *box) { + double ox = lx, oy = ly; + wlr_output_layout_output_coords(output_layout, wlr_output, &ox, &oy); + box->x = ox * wlr_output->scale; + box->y = oy * wlr_output->scale; + box->width = surface->current->width * wlr_output->scale; + box->height = surface->current->height * wlr_output->scale; + + struct wlr_box render_box = { + .x = lx, .y = ly, + .width = box->width, .height = box->height, + }; + return wlr_output_layout_intersects(output_layout, wlr_output, &render_box); +} + static void render_surface(struct wlr_surface *surface, struct roots_desktop *desktop, struct wlr_output *wlr_output, struct timespec *when, double lx, double ly, float rotation) { @@ -38,35 +55,25 @@ static void render_surface(struct wlr_surface *surface, return; } - int width = surface->current->width; - int height = surface->current->height; - int render_width = width * wlr_output->scale; - int render_height = height * wlr_output->scale; - double ox = lx, oy = ly; - wlr_output_layout_output_coords(desktop->layout, wlr_output, &ox, &oy); - ox *= wlr_output->scale; - oy *= wlr_output->scale; - - struct wlr_box render_box = { - .x = lx, .y = ly, - .width = render_width, .height = render_height, - }; - if (wlr_output_layout_intersects(desktop->layout, wlr_output, &render_box)) { + struct wlr_box box; + bool intersects = surface_intersect_output(surface, desktop->layout, + wlr_output, lx, ly, &box); + if (intersects) { float matrix[16]; float translate_center[16]; wlr_matrix_translate(&translate_center, - (int)ox + render_width / 2, (int)oy + render_height / 2, 0); + box.x + box.width / 2, box.y + box.height / 2, 0); float rotate[16]; wlr_matrix_rotate(&rotate, rotation); float translate_origin[16]; - wlr_matrix_translate(&translate_origin, -render_width / 2, - -render_height / 2, 0); + wlr_matrix_translate(&translate_origin, -box.width / 2, + -box.height / 2, 0); float scale[16]; - wlr_matrix_scale(&scale, render_width, render_height, 1); + wlr_matrix_scale(&scale, box.width, box.height, 1); float transform[16]; wlr_matrix_mul(&translate_center, &rotate, &transform); @@ -106,7 +113,8 @@ static void render_surface(struct wlr_surface *surface, double sy = state->subsurface_position.y; double sw = state->buffer_width / state->scale; double sh = state->buffer_height / state->scale; - rotate_child_position(&sx, &sy, sw, sh, width, height, rotation); + rotate_child_position(&sx, &sy, sw, sh, surface->current->width, + surface->current->height, rotation); render_surface(subsurface->surface, desktop, wlr_output, when, lx + sx, @@ -219,8 +227,8 @@ static bool has_standalone_surface(struct roots_view *view) { } static void output_frame_notify(struct wl_listener *listener, void *data) { - struct wlr_output *wlr_output = data; struct roots_output *output = wl_container_of(listener, output, frame); + struct wlr_output *wlr_output = output->wlr_output; struct roots_desktop *desktop = output->desktop; struct roots_server *server = desktop->server; @@ -231,6 +239,12 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); + // TODO: fullscreen + if (!pixman_region32_not_empty(&output->damage) && + !wlr_output->needs_swap) { + goto swap_buffers; + } + wlr_output_make_current(wlr_output); wlr_renderer_begin(server->renderer, wlr_output); @@ -266,10 +280,8 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { wlr_output, &now); } } - wlr_renderer_end(server->renderer); - wlr_output_swap_buffers(wlr_output); - output->last_frame = desktop->last_frame = now; - return; + + goto renderer_end; } else { wlr_output_set_fullscreen_surface(wlr_output, NULL); } @@ -305,12 +317,33 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { } } +renderer_end: wlr_renderer_end(server->renderer); +swap_buffers: wlr_output_swap_buffers(wlr_output); + pixman_region32_clear(&output->damage); output->last_frame = desktop->last_frame = now; } +void output_damage_surface(struct roots_output *output, + struct wlr_surface *surface, double lx, double ly) { + if (!wlr_surface_has_buffer(surface)) { + return; + } + + struct wlr_box box; + bool intersects = surface_intersect_output(surface, + output->desktop->layout, output->wlr_output, lx, ly, &box); + if (!intersects) { + return; + } + + // TODO: use surface damage + pixman_region32_union_rect(&output->damage, &output->damage, box.x, box.y, + box.width, box.height); +} + static void set_mode(struct wlr_output *output, struct roots_output_config *oc) { int mhz = (int)(oc->mode.refresh_rate * 1000); @@ -361,9 +394,11 @@ void output_add_notify(struct wl_listener *listener, void *data) { clock_gettime(CLOCK_MONOTONIC, &output->last_frame); output->desktop = desktop; output->wlr_output = wlr_output; + wl_list_insert(&desktop->outputs, &output->link); + pixman_region32_init(&output->damage); + output->frame.notify = output_frame_notify; wl_signal_add(&wlr_output->events.frame, &output->frame); - wl_list_insert(&desktop->outputs, &output->link); struct roots_output_config *output_config = roots_config_get_output(config, wlr_output); @@ -412,6 +447,7 @@ void output_remove_notify(struct wl_listener *listener, void *data) { //example_config_configure_cursor(sample->config, sample->cursor, // sample->compositor); + pixman_region32_fini(&output->damage); wl_list_remove(&output->link); wl_list_remove(&output->frame.link); free(output); diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c index 0515263b..e915d1a6 100644 --- a/rootston/xdg_shell_v6.c +++ b/rootston/xdg_shell_v6.c @@ -217,6 +217,8 @@ static void handle_commit(struct wl_listener *listener, void *data) { roots_surface->pending_move_resize_configure_serial = 0; } } + + desktop_damage_surface(view->desktop, view->wlr_surface, view->x, view->y); } static void handle_destroy(struct wl_listener *listener, void *data) { From 5089f2d9fbcbc76c985e3a93b6fb694b57f116aa Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 18 Jan 2018 11:42:54 +0100 Subject: [PATCH 02/75] rootston: do not swap buffers when output isn't damaged --- include/rootston/output.h | 7 +++++-- rootston/output.c | 23 +++++++++++++++++++---- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/include/rootston/output.h b/include/rootston/output.h index e7f49227..d44479ed 100644 --- a/include/rootston/output.h +++ b/include/rootston/output.h @@ -10,11 +10,14 @@ struct roots_desktop; struct roots_output { struct roots_desktop *desktop; struct wlr_output *wlr_output; + struct wl_list link; // roots_desktop:outputs + + struct roots_view *fullscreen_view; + struct wl_listener frame; struct timespec last_frame; - struct wl_list link; // roots_desktop:outputs - struct roots_view *fullscreen_view; pixman_region32_t damage; + struct wl_event_source *repaint_timer; }; void output_add_notify(struct wl_listener *listener, void *data); diff --git a/rootston/output.c b/rootston/output.c index 22b8615a..a700ea07 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -226,7 +226,7 @@ static bool has_standalone_surface(struct roots_view *view) { return true; } -static void output_frame_notify(struct wl_listener *listener, void *data) { +static void output_handle_frame(struct wl_listener *listener, void *data) { struct roots_output *output = wl_container_of(listener, output, frame); struct wlr_output *wlr_output = output->wlr_output; struct roots_desktop *desktop = output->desktop; @@ -242,7 +242,12 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { // TODO: fullscreen if (!pixman_region32_not_empty(&output->damage) && !wlr_output->needs_swap) { - goto swap_buffers; + int refresh = wlr_output->refresh; + if (refresh <= 0) { + refresh = 60; + } + wl_event_source_timer_update(output->repaint_timer, 1000.0f / refresh); + goto clear_damage; } wlr_output_make_current(wlr_output); @@ -319,13 +324,19 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { renderer_end: wlr_renderer_end(server->renderer); -swap_buffers: wlr_output_swap_buffers(wlr_output); +clear_damage: pixman_region32_clear(&output->damage); output->last_frame = desktop->last_frame = now; } +static int handle_repaint(void *data) { + struct roots_output *output = data; + output_handle_frame(&output->frame, output->wlr_output); + return 0; +} + void output_damage_surface(struct roots_output *output, struct wlr_surface *surface, double lx, double ly) { if (!wlr_surface_has_buffer(surface)) { @@ -396,8 +407,11 @@ void output_add_notify(struct wl_listener *listener, void *data) { output->wlr_output = wlr_output; wl_list_insert(&desktop->outputs, &output->link); pixman_region32_init(&output->damage); + struct wl_event_loop *ev = + wl_display_get_event_loop(desktop->server->wl_display); + output->repaint_timer = wl_event_loop_add_timer(ev, handle_repaint, output); - output->frame.notify = output_frame_notify; + output->frame.notify = output_handle_frame; wl_signal_add(&wlr_output->events.frame, &output->frame); struct roots_output_config *output_config = @@ -447,6 +461,7 @@ void output_remove_notify(struct wl_listener *listener, void *data) { //example_config_configure_cursor(sample->config, sample->cursor, // sample->compositor); + wl_event_source_remove(output->repaint_timer); pixman_region32_fini(&output->damage); wl_list_remove(&output->link); wl_list_remove(&output->frame.link); From 01bcc2ab01715df1f105ab972041134c878612e0 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 18 Jan 2018 12:25:39 +0100 Subject: [PATCH 03/75] rootston: damage views when moved --- include/rootston/desktop.h | 4 ++-- include/rootston/output.h | 3 +-- rootston/desktop.c | 26 ++++++++++++++++---------- rootston/output.c | 8 +++++++- rootston/wl_shell.c | 9 ++++++--- rootston/xdg_shell_v6.c | 11 ++++++----- rootston/xwayland.c | 24 ++++++++++++++---------- 7 files changed, 52 insertions(+), 33 deletions(-) diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h index 3d0e2a2b..c0790917 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -62,12 +62,12 @@ struct roots_output *desktop_output_from_wlr_output( struct roots_desktop *desktop, struct wlr_output *output); struct roots_view *desktop_view_at(struct roots_desktop *desktop, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy); -void desktop_damage_surface(struct roots_desktop *desktop, - struct wlr_surface *surface, double lx, double ly); void view_init(struct roots_view *view, struct roots_desktop *desktop); void view_destroy(struct roots_view *view); void view_activate(struct roots_view *view, bool activate); +void view_damage(struct roots_view *view); +void view_update_position(struct roots_view *view, double x, double y); void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data); void handle_wl_shell_surface(struct wl_listener *listener, void *data); diff --git a/include/rootston/output.h b/include/rootston/output.h index d44479ed..e8c64c3e 100644 --- a/include/rootston/output.h +++ b/include/rootston/output.h @@ -23,7 +23,6 @@ struct roots_output { void output_add_notify(struct wl_listener *listener, void *data); void output_remove_notify(struct wl_listener *listener, void *data); -void output_damage_surface(struct roots_output *output, - struct wlr_surface *surface, double lx, double ly); +void output_damage_view(struct roots_output *output, struct roots_view *view); #endif diff --git a/rootston/desktop.c b/rootston/desktop.c index 3b8e6602..94350359 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -61,8 +61,7 @@ void view_move(struct roots_view *view, double x, double y) { if (view->move) { view->move(view, x, y); } else { - view->x = x; - view->y = y; + view_update_position(view, x, y); } view_update_output(view, &before); } @@ -268,6 +267,7 @@ void view_destroy(struct roots_view *view) { void view_init(struct roots_view *view, struct roots_desktop *desktop) { view->desktop = desktop; wl_signal_init(&view->events.destroy); + view_damage(view); } void view_setup(struct roots_view *view) { @@ -282,6 +282,20 @@ void view_setup(struct roots_view *view) { view_update_output(view, NULL); } +void view_damage(struct roots_view *view) { + struct roots_output *output; + wl_list_for_each(output, &view->desktop->outputs, link) { + output_damage_view(output, view); + } +} + +void view_update_position(struct roots_view *view, double x, double y) { + view_damage(view); + view->x = x; + view->y = y; + view_damage(view); +} + static bool view_at(struct roots_view *view, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { if (view->type == ROOTS_WL_SHELL_VIEW && @@ -522,11 +536,3 @@ struct roots_output *desktop_output_from_wlr_output( } return NULL; } - -void desktop_damage_surface(struct roots_desktop *desktop, - struct wlr_surface *surface, double lx, double ly) { - struct roots_output *output; - wl_list_for_each(output, &desktop->outputs, link) { - output_damage_surface(output, surface, lx, ly); - } -} diff --git a/rootston/output.c b/rootston/output.c index a700ea07..5ccd9eb7 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -337,7 +337,7 @@ static int handle_repaint(void *data) { return 0; } -void output_damage_surface(struct roots_output *output, +static void output_damage_surface(struct roots_output *output, struct wlr_surface *surface, double lx, double ly) { if (!wlr_surface_has_buffer(surface)) { return; @@ -355,6 +355,12 @@ void output_damage_surface(struct roots_output *output, box.width, box.height); } +void output_damage_view(struct roots_output *output, struct roots_view *view) { + output_damage_surface(output, view->wlr_surface, view->x, view->y); + + // TODO: subsurfaces, popups, etc +} + static void set_mode(struct wlr_output *output, struct roots_output_config *oc) { int mhz = (int)(oc->mode.refresh_rate * 1000); diff --git a/rootston/wl_shell.c b/rootston/wl_shell.c index 65067920..e1dea82b 100644 --- a/rootston/wl_shell.c +++ b/rootston/wl_shell.c @@ -90,17 +90,20 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) { int width = wlr_surface->current->width; int height = wlr_surface->current->height; - if (view->pending_move_resize.update_x) { - view->x = view->pending_move_resize.x + + double x = view->pending_move_resize.x + view->pending_move_resize.width - width; + view_update_position(view, x, view->y); view->pending_move_resize.update_x = false; } if (view->pending_move_resize.update_y) { - view->y = view->pending_move_resize.y + + double y = view->pending_move_resize.y + view->pending_move_resize.height - height; + view_update_position(view, view->x, y); view->pending_move_resize.update_y = false; } + + view_damage(view); } static void handle_destroy(struct wl_listener *listener, void *data) { diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c index e915d1a6..259b62a5 100644 --- a/rootston/xdg_shell_v6.c +++ b/rootston/xdg_shell_v6.c @@ -102,8 +102,7 @@ static void move_resize(struct roots_view *view, double x, double y, if (serial > 0) { roots_surface->pending_move_resize_configure_serial = serial; } else { - view->x = x; - view->y = y; + view_update_position(view, x, y); } } @@ -205,12 +204,14 @@ static void handle_commit(struct wl_listener *listener, void *data) { get_size(view, &size); if (view->pending_move_resize.update_x) { - view->x = view->pending_move_resize.x + + double x = view->pending_move_resize.x + view->pending_move_resize.width - size.width; + view_update_position(view, x, view->y); } if (view->pending_move_resize.update_y) { - view->y = view->pending_move_resize.y + + double y = view->pending_move_resize.y + view->pending_move_resize.height - size.height; + view_update_position(view, view->x, y); } if (pending_serial == surface->configure_serial) { @@ -218,7 +219,7 @@ static void handle_commit(struct wl_listener *listener, void *data) { } } - desktop_damage_surface(view->desktop, view->wlr_surface, view->x, view->y); + view_damage(view); } static void handle_destroy(struct wl_listener *listener, void *data) { diff --git a/rootston/xwayland.c b/rootston/xwayland.c index 3d84dc19..b3cf409c 100644 --- a/rootston/xwayland.c +++ b/rootston/xwayland.c @@ -18,8 +18,7 @@ static void activate(struct roots_view *view, bool active) { static void move(struct roots_view *view, double x, double y) { assert(view->type == ROOTS_XWAYLAND_VIEW); struct wlr_xwayland_surface *xwayland_surface = view->xwayland_surface; - view->x = x; - view->y = y; + view_update_position(view, x, y); wlr_xwayland_surface_configure(xwayland_surface, x, y, xwayland_surface->width, xwayland_surface->height); } @@ -133,8 +132,7 @@ static void handle_request_configure(struct wl_listener *listener, void *data) { roots_surface->view->xwayland_surface; struct wlr_xwayland_surface_configure_event *event = data; - roots_surface->view->x = (double)event->x; - roots_surface->view->y = (double)event->y; + view_update_position(roots_surface->view, event->x, event->y); wlr_xwayland_surface_configure(xwayland_surface, event->x, event->y, event->width, event->height); @@ -210,15 +208,19 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) { int height = wlr_surface->current->height; if (view->pending_move_resize.update_x) { - view->x = view->pending_move_resize.x + + double x = view->pending_move_resize.x + view->pending_move_resize.width - width; + view_update_position(view, x, view->y); view->pending_move_resize.update_x = false; } if (view->pending_move_resize.update_y) { - view->y = view->pending_move_resize.y + + double y = view->pending_move_resize.y + view->pending_move_resize.height - height; + view_update_position(view, view->x, y); view->pending_move_resize.update_y = false; } + + view_damage(view); } static void handle_map_notify(struct wl_listener *listener, void *data) { @@ -229,8 +231,9 @@ static void handle_map_notify(struct wl_listener *listener, void *data) { struct roots_desktop *desktop = view->desktop; view->wlr_surface = xsurface->surface; - view->x = (double)xsurface->x; - view->y = (double)xsurface->y; + view->x = xsurface->x; + view->y = xsurface->y; + view_damage(view); roots_surface->surface_commit.notify = handle_surface_commit; wl_signal_add(&xsurface->surface->events.commit, @@ -242,10 +245,11 @@ static void handle_map_notify(struct wl_listener *listener, void *data) { static void handle_unmap_notify(struct wl_listener *listener, void *data) { struct roots_xwayland_surface *roots_surface = wl_container_of(listener, roots_surface, unmap_notify); + + view_damage(roots_surface->view); + roots_surface->view->wlr_surface = NULL; - wl_list_remove(&roots_surface->surface_commit.link); - wl_list_remove(&roots_surface->view->link); } From 6fa0a91ee2325f4259021f529297920603343d69 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 18 Jan 2018 13:06:57 +0100 Subject: [PATCH 04/75] backend/wayland: fix segfault in wlr_wl_output_destroy --- backend/wayland/output.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/wayland/output.c b/backend/wayland/output.c index 52791679..7e299ecc 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -18,10 +18,12 @@ int os_create_anonymous_file(off_t size); static struct wl_callback_listener frame_listener; static void surface_frame_callback(void *data, struct wl_callback *cb, uint32_t time) { - struct wlr_output *wlr_output = data; + struct wlr_wl_backend_output *output = data; + struct wlr_output *wlr_output = (struct wlr_output *)output; assert(wlr_output); wl_signal_emit(&wlr_output->events.frame, wlr_output); wl_callback_destroy(cb); + output->frame_callback = NULL; } static struct wl_callback_listener frame_listener = { From 5017d7f7625e4ca3369feb241a81ad8a570d0fd1 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 18 Jan 2018 14:36:42 +0100 Subject: [PATCH 05/75] rootston: only draw damaged regions --- render/gles2/renderer.c | 8 +- rootston/desktop.c | 1 + rootston/output.c | 193 ++++++++++++++++++++++++---------------- 3 files changed, 121 insertions(+), 81 deletions(-) diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 89cc4ffb..2dd64176 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -108,11 +108,9 @@ static void init_globals() { static void wlr_gles2_begin(struct wlr_renderer *_renderer, struct wlr_output *output) { // TODO: let users customize the clear color? - GL_CALL(glClearColor(0.25f, 0.25f, 0.25f, 1)); - GL_CALL(glClear(GL_COLOR_BUFFER_BIT)); - int32_t width = output->width; - int32_t height = output->height; - GL_CALL(glViewport(0, 0, width, height)); + //GL_CALL(glClearColor(0.25f, 0.25f, 0.25f, 1)); + //GL_CALL(glClear(GL_COLOR_BUFFER_BIT)); + GL_CALL(glViewport(0, 0, output->width, output->height)); // enable transparency GL_CALL(glEnable(GL_BLEND)); diff --git a/rootston/desktop.c b/rootston/desktop.c index 94350359..b8c876cb 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -255,6 +255,7 @@ bool view_center(struct roots_view *view) { } void view_destroy(struct roots_view *view) { + view_damage(view); wl_signal_emit(&view->events.destroy, view); if (view->fullscreen_output) { diff --git a/rootston/output.c b/rootston/output.c index 5ccd9eb7..027d8275 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -41,71 +41,99 @@ static bool surface_intersect_output(struct wlr_surface *surface, box->width = surface->current->width * wlr_output->scale; box->height = surface->current->height * wlr_output->scale; - struct wlr_box render_box = { + struct wlr_box layout_box = { .x = lx, .y = ly, - .width = box->width, .height = box->height, + .width = surface->current->width, .height = surface->current->height, }; - return wlr_output_layout_intersects(output_layout, wlr_output, &render_box); + return wlr_output_layout_intersects(output_layout, wlr_output, &layout_box); } static void render_surface(struct wlr_surface *surface, - struct roots_desktop *desktop, struct wlr_output *wlr_output, - struct timespec *when, double lx, double ly, float rotation) { + struct roots_output *output, struct timespec *when, + double lx, double ly, float rotation) { if (!wlr_surface_has_buffer(surface)) { return; } struct wlr_box box; - bool intersects = surface_intersect_output(surface, desktop->layout, - wlr_output, lx, ly, &box); - if (intersects) { - float matrix[16]; + bool intersects = surface_intersect_output(surface, output->desktop->layout, + output->wlr_output, lx, ly, &box); + if (!intersects) { + goto render_subsurfaces; + } + // TODO: do not render regions of the surface that aren't damaged + // TODO: output scale, output transform support + pixman_region32_t surface_damage; + pixman_region32_init(&surface_damage); + pixman_region32_union_rect(&surface_damage, &surface_damage, box.x, box.y, + box.width, box.height); + pixman_region32_intersect(&surface_damage, &surface_damage, + &output->damage); + bool damaged = pixman_region32_not_empty(&surface_damage); + if (!damaged) { + goto render_subsurfaces; + } + + float transform[16]; + wlr_matrix_translate(&transform, box.x, box.y, 0); + + if (rotation != 0) { float translate_center[16]; - wlr_matrix_translate(&translate_center, - box.x + box.width / 2, box.y + box.height / 2, 0); + wlr_matrix_translate(&translate_center, box.width/2, box.height/2, 0); float rotate[16]; wlr_matrix_rotate(&rotate, rotation); float translate_origin[16]; - wlr_matrix_translate(&translate_origin, -box.width / 2, - -box.height / 2, 0); + wlr_matrix_translate(&translate_origin, -box.width/2, -box.height/2, 0); - float scale[16]; - wlr_matrix_scale(&scale, box.width, box.height, 1); - - float transform[16]; - wlr_matrix_mul(&translate_center, &rotate, &transform); + wlr_matrix_mul(&transform, &translate_center, &transform); + wlr_matrix_mul(&transform, &rotate, &transform); wlr_matrix_mul(&transform, &translate_origin, &transform); - wlr_matrix_mul(&transform, &scale, &transform); - - if (surface->current->transform != WL_OUTPUT_TRANSFORM_NORMAL) { - float surface_translate_center[16]; - wlr_matrix_translate(&surface_translate_center, 0.5, 0.5, 0); - - float surface_transform[16]; - wlr_matrix_transform(surface_transform, - wlr_output_transform_invert(surface->current->transform)); - - float surface_translate_origin[16]; - wlr_matrix_translate(&surface_translate_origin, -0.5, -0.5, 0); - - wlr_matrix_mul(&transform, &surface_translate_center, - &transform); - wlr_matrix_mul(&transform, &surface_transform, &transform); - wlr_matrix_mul(&transform, &surface_translate_origin, - &transform); - } - - wlr_matrix_mul(&wlr_output->transform_matrix, &transform, &matrix); - - wlr_render_with_matrix(desktop->server->renderer, surface->texture, - &matrix); - - wlr_surface_send_frame_done(surface, when); } + float scale[16]; + wlr_matrix_scale(&scale, box.width, box.height, 1); + + wlr_matrix_mul(&transform, &scale, &transform); + + if (surface->current->transform != WL_OUTPUT_TRANSFORM_NORMAL) { + float surface_translate_center[16]; + wlr_matrix_translate(&surface_translate_center, 0.5, 0.5, 0); + + float surface_transform[16]; + wlr_matrix_transform(surface_transform, + wlr_output_transform_invert(surface->current->transform)); + + float surface_translate_origin[16]; + wlr_matrix_translate(&surface_translate_origin, -0.5, -0.5, 0); + + wlr_matrix_mul(&transform, &surface_translate_center, + &transform); + wlr_matrix_mul(&transform, &surface_transform, &transform); + wlr_matrix_mul(&transform, &surface_translate_origin, + &transform); + } + + float matrix[16]; + wlr_matrix_mul(&output->wlr_output->transform_matrix, &transform, &matrix); + + int nrects; + pixman_box32_t *rects = + pixman_region32_rectangles(&surface_damage, &nrects); + for (int i = 0; i < nrects; ++i) { + glScissor(rects[i].x1, output->wlr_output->height - rects[i].y2, + rects[i].x2 - rects[i].x1, rects[i].y2 - rects[i].y1); + wlr_render_with_matrix(output->desktop->server->renderer, + surface->texture, &matrix); + } + + wlr_surface_send_frame_done(surface, when); + +render_subsurfaces: + pixman_region32_fini(&surface_damage); + struct wlr_subsurface *subsurface; wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) { struct wlr_surface_state *state = subsurface->surface->current; @@ -116,16 +144,14 @@ static void render_surface(struct wlr_surface *surface, rotate_child_position(&sx, &sy, sw, sh, surface->current->width, surface->current->height, rotation); - render_surface(subsurface->surface, desktop, wlr_output, when, - lx + sx, - ly + sy, + render_surface(subsurface->surface, output, when, lx + sx, ly + sy, rotation); } } static void render_xdg_v6_popups(struct wlr_xdg_surface_v6 *surface, - struct roots_desktop *desktop, struct wlr_output *wlr_output, - struct timespec *when, double base_x, double base_y, float rotation) { + struct roots_output *output, struct timespec *when, + double base_x, double base_y, float rotation) { double width = surface->surface->current->width; double height = surface->surface->current->height; @@ -143,20 +169,18 @@ static void render_xdg_v6_popups(struct wlr_xdg_surface_v6 *surface, rotate_child_position(&popup_sx, &popup_sy, popup_width, popup_height, width, height, rotation); - render_surface(popup->surface, desktop, wlr_output, when, + render_surface(popup->surface, output, when, base_x + popup_sx, base_y + popup_sy, rotation); - render_xdg_v6_popups(popup, desktop, wlr_output, when, + render_xdg_v6_popups(popup, output, when, base_x + popup_sx, base_y + popup_sy, rotation); } } static void render_wl_shell_surface(struct wlr_wl_shell_surface *surface, - struct roots_desktop *desktop, struct wlr_output *wlr_output, - struct timespec *when, double lx, double ly, float rotation, - bool is_child) { + struct roots_output *output, struct timespec *when, + double lx, double ly, float rotation, bool is_child) { if (is_child || surface->state != WLR_WL_SHELL_SURFACE_STATE_POPUP) { - render_surface(surface->surface, desktop, wlr_output, when, - lx, ly, rotation); + render_surface(surface->surface, output, when, lx, ly, rotation); double width = surface->surface->current->width; double height = surface->surface->current->height; @@ -171,41 +195,40 @@ static void render_wl_shell_surface(struct wlr_wl_shell_surface *surface, rotate_child_position(&popup_x, &popup_y, popup_width, popup_height, width, height, rotation); - render_wl_shell_surface(popup, desktop, wlr_output, when, + render_wl_shell_surface(popup, output, when, lx + popup_x, ly + popup_y, rotation, true); } } } static void render_xwayland_children(struct wlr_xwayland_surface *surface, - struct roots_desktop *desktop, struct wlr_output *wlr_output, - struct timespec *when) { + struct roots_output *output, struct timespec *when) { struct wlr_xwayland_surface *child; wl_list_for_each(child, &surface->children, parent_link) { if (child->surface != NULL && child->added) { - render_surface(child->surface, desktop, wlr_output, when, + render_surface(child->surface, output, when, child->x, child->y, 0); } - render_xwayland_children(child, desktop, wlr_output, when); + render_xwayland_children(child, output, when); } } -static void render_view(struct roots_view *view, struct roots_desktop *desktop, - struct wlr_output *wlr_output, struct timespec *when) { +static void render_view(struct roots_view *view, struct roots_output *output, + struct timespec *when) { switch (view->type) { case ROOTS_XDG_SHELL_V6_VIEW: - render_surface(view->wlr_surface, desktop, wlr_output, when, + render_surface(view->wlr_surface, output, when, view->x, view->y, + view->rotation); + render_xdg_v6_popups(view->xdg_surface_v6, output, when, view->x, view->y, view->rotation); - render_xdg_v6_popups(view->xdg_surface_v6, desktop, wlr_output, - when, view->x, view->y, view->rotation); break; case ROOTS_WL_SHELL_VIEW: - render_wl_shell_surface(view->wl_shell_surface, desktop, wlr_output, - when, view->x, view->y, view->rotation, false); + render_wl_shell_surface(view->wl_shell_surface, output, when, + view->x, view->y, view->rotation, false); break; case ROOTS_XWAYLAND_VIEW: - render_surface(view->wlr_surface, desktop, wlr_output, when, - view->x, view->y, view->rotation); + render_surface(view->wlr_surface, output, when, view->x, view->y, + view->rotation); break; } } @@ -239,6 +262,13 @@ static void output_handle_frame(struct wl_listener *listener, void *data) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); + // TODO: use real wlr_output damage + if (wlr_output->needs_swap) { + int width, height; + wlr_output_effective_resolution(wlr_output, &width, &height); + pixman_region32_union_rect(&output->damage, &output->damage, 0, 0, + width, height); + } // TODO: fullscreen if (!pixman_region32_not_empty(&output->damage) && !wlr_output->needs_swap) { @@ -252,6 +282,17 @@ static void output_handle_frame(struct wl_listener *listener, void *data) { wlr_output_make_current(wlr_output); wlr_renderer_begin(server->renderer, wlr_output); + glEnable(GL_SCISSOR_TEST); + + int nrects; + pixman_box32_t *rects = + pixman_region32_rectangles(&output->damage, &nrects); + for (int i = 0; i < nrects; ++i) { + glScissor(rects[i].x1, wlr_output->height - rects[i].y2, + rects[i].x2 - rects[i].x1, rects[i].y2 - rects[i].y1); + glClearColor(0.25f, 0.25f, 0.25f, 1); + glClear(GL_COLOR_BUFFER_BIT); + } if (output->fullscreen_view != NULL) { struct roots_view *view = output->fullscreen_view; @@ -275,14 +316,13 @@ static void output_handle_frame(struct wl_listener *listener, void *data) { glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); - render_view(view, desktop, wlr_output, &now); + render_view(view, output, &now); // During normal rendering the xwayland window tree isn't traversed // because all windows are rendered. Here we only want to render // the fullscreen window's children so we have to traverse the tree. if (view->type == ROOTS_XWAYLAND_VIEW) { - render_xwayland_children(view->xwayland_surface, desktop, - wlr_output, &now); + render_xwayland_children(view->xwayland_surface, output, &now); } } @@ -293,7 +333,7 @@ static void output_handle_frame(struct wl_listener *listener, void *data) { struct roots_view *view; wl_list_for_each_reverse(view, &desktop->views, link) { - render_view(view, desktop, wlr_output, &now); + render_view(view, output, &now); } struct wlr_drag_icon *drag_icon = NULL; @@ -309,20 +349,21 @@ static void output_handle_frame(struct wl_listener *listener, void *data) { if (drag_icon->is_pointer) { icon_x = cursor->x + drag_icon->sx; icon_y = cursor->y + drag_icon->sy; - render_surface(icon, desktop, wlr_output, &now, icon_x, icon_y, 0); + render_surface(icon, output, &now, icon_x, icon_y, 0); } else { struct wlr_touch_point *point = wlr_seat_touch_get_point(seat->seat, drag_icon->touch_id); if (point) { icon_x = seat->touch_x + drag_icon->sx; icon_y = seat->touch_y + drag_icon->sy; - render_surface(icon, desktop, wlr_output, &now, icon_x, icon_y, 0); + render_surface(icon, output, &now, icon_x, icon_y, 0); } } } } renderer_end: + glDisable(GL_SCISSOR_TEST); wlr_renderer_end(server->renderer); wlr_output_swap_buffers(wlr_output); From 7f5a538cb73eb20fa37ff98161d45a3a383622aa Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 18 Jan 2018 14:50:30 +0100 Subject: [PATCH 06/75] rootston: fix segfault when rendering surface outside output --- rootston/output.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/rootston/output.c b/rootston/output.c index 027d8275..16a185af 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -72,7 +72,7 @@ static void render_surface(struct wlr_surface *surface, &output->damage); bool damaged = pixman_region32_not_empty(&surface_damage); if (!damaged) { - goto render_subsurfaces; + goto finish_surface_damage; } float transform[16]; @@ -131,9 +131,10 @@ static void render_surface(struct wlr_surface *surface, wlr_surface_send_frame_done(surface, when); -render_subsurfaces: +finish_surface_damage: pixman_region32_fini(&surface_damage); +render_subsurfaces:; struct wlr_subsurface *subsurface; wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) { struct wlr_surface_state *state = subsurface->surface->current; From 96d6f34eddbd0159e347d41e5c20c74a0600e878 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 18 Jan 2018 16:30:56 +0100 Subject: [PATCH 07/75] rootston: replace view_damage with view_apply_damage and view_damage_whole --- include/rootston/desktop.h | 3 ++- include/rootston/output.h | 5 ++++- rootston/desktop.c | 19 +++++++++++++------ rootston/output.c | 15 +++++++++++---- rootston/wl_shell.c | 2 +- rootston/xdg_shell_v6.c | 2 +- rootston/xwayland.c | 6 +++--- 7 files changed, 35 insertions(+), 17 deletions(-) diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h index c0790917..812bb42a 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -66,7 +66,8 @@ struct roots_view *desktop_view_at(struct roots_desktop *desktop, double lx, void view_init(struct roots_view *view, struct roots_desktop *desktop); void view_destroy(struct roots_view *view); void view_activate(struct roots_view *view, bool activate); -void view_damage(struct roots_view *view); +void view_apply_damage(struct roots_view *view); +void view_damage_whole(struct roots_view *view); void view_update_position(struct roots_view *view, double x, double y); void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data); diff --git a/include/rootston/output.h b/include/rootston/output.h index e8c64c3e..cf34496b 100644 --- a/include/rootston/output.h +++ b/include/rootston/output.h @@ -23,6 +23,9 @@ struct roots_output { void output_add_notify(struct wl_listener *listener, void *data); void output_remove_notify(struct wl_listener *listener, void *data); -void output_damage_view(struct roots_output *output, struct roots_view *view); +void output_damage_whole_view(struct roots_output *output, + struct roots_view *view); +void output_damage_from_view(struct roots_output *output, + struct roots_view *view); #endif diff --git a/rootston/desktop.c b/rootston/desktop.c index b8c876cb..faaefd05 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -255,7 +255,7 @@ bool view_center(struct roots_view *view) { } void view_destroy(struct roots_view *view) { - view_damage(view); + view_damage_whole(view); wl_signal_emit(&view->events.destroy, view); if (view->fullscreen_output) { @@ -268,7 +268,7 @@ void view_destroy(struct roots_view *view) { void view_init(struct roots_view *view, struct roots_desktop *desktop) { view->desktop = desktop; wl_signal_init(&view->events.destroy); - view_damage(view); + view_damage_whole(view); } void view_setup(struct roots_view *view) { @@ -283,18 +283,25 @@ void view_setup(struct roots_view *view) { view_update_output(view, NULL); } -void view_damage(struct roots_view *view) { +void view_apply_damage(struct roots_view *view) { struct roots_output *output; wl_list_for_each(output, &view->desktop->outputs, link) { - output_damage_view(output, view); + output_damage_from_view(output, view); + } +} + +void view_damage_whole(struct roots_view *view) { + struct roots_output *output; + wl_list_for_each(output, &view->desktop->outputs, link) { + output_damage_whole_view(output, view); } } void view_update_position(struct roots_view *view, double x, double y) { - view_damage(view); + view_damage_whole(view); view->x = x; view->y = y; - view_damage(view); + view_damage_whole(view); } static bool view_at(struct roots_view *view, double lx, double ly, diff --git a/rootston/output.c b/rootston/output.c index 16a185af..846bb4e6 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -379,7 +379,7 @@ static int handle_repaint(void *data) { return 0; } -static void output_damage_surface(struct roots_output *output, +static void output_damage_whole_surface(struct roots_output *output, struct wlr_surface *surface, double lx, double ly) { if (!wlr_surface_has_buffer(surface)) { return; @@ -392,17 +392,24 @@ static void output_damage_surface(struct roots_output *output, return; } - // TODO: use surface damage + pixman_region32_union_rect(&output->damage, &output->damage, box.x, box.y, box.width, box.height); } -void output_damage_view(struct roots_output *output, struct roots_view *view) { - output_damage_surface(output, view->wlr_surface, view->x, view->y); +void output_damage_whole_view(struct roots_output *output, + struct roots_view *view) { + output_damage_whole_surface(output, view->wlr_surface, view->x, view->y); // TODO: subsurfaces, popups, etc } +void output_damage_from_view(struct roots_output *output, + struct roots_view *view) { + // TODO: use surface damage + output_damage_whole_view(output, view); +} + static void set_mode(struct wlr_output *output, struct roots_output_config *oc) { int mhz = (int)(oc->mode.refresh_rate * 1000); diff --git a/rootston/wl_shell.c b/rootston/wl_shell.c index e1dea82b..25ef9a3c 100644 --- a/rootston/wl_shell.c +++ b/rootston/wl_shell.c @@ -103,7 +103,7 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) { view->pending_move_resize.update_y = false; } - view_damage(view); + view_apply_damage(view); } static void handle_destroy(struct wl_listener *listener, void *data) { diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c index 259b62a5..225886ad 100644 --- a/rootston/xdg_shell_v6.c +++ b/rootston/xdg_shell_v6.c @@ -219,7 +219,7 @@ static void handle_commit(struct wl_listener *listener, void *data) { } } - view_damage(view); + view_apply_damage(view); } static void handle_destroy(struct wl_listener *listener, void *data) { diff --git a/rootston/xwayland.c b/rootston/xwayland.c index b3cf409c..856c3d70 100644 --- a/rootston/xwayland.c +++ b/rootston/xwayland.c @@ -220,7 +220,7 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) { view->pending_move_resize.update_y = false; } - view_damage(view); + view_apply_damage(view); } static void handle_map_notify(struct wl_listener *listener, void *data) { @@ -233,7 +233,7 @@ static void handle_map_notify(struct wl_listener *listener, void *data) { view->wlr_surface = xsurface->surface; view->x = xsurface->x; view->y = xsurface->y; - view_damage(view); + view_damage_whole(view); roots_surface->surface_commit.notify = handle_surface_commit; wl_signal_add(&xsurface->surface->events.commit, @@ -246,7 +246,7 @@ static void handle_unmap_notify(struct wl_listener *listener, void *data) { struct roots_xwayland_surface *roots_surface = wl_container_of(listener, roots_surface, unmap_notify); - view_damage(roots_surface->view); + view_damage_whole(roots_surface->view); roots_surface->view->wlr_surface = NULL; wl_list_remove(&roots_surface->surface_commit.link); From 7c11d3e372769c4ec596d7c82a3207e65454dffe Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 18 Jan 2018 16:36:49 +0100 Subject: [PATCH 08/75] rootston: fix repaint timer for outputs with refresh rate --- rootston/output.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rootston/output.c b/rootston/output.c index 846bb4e6..086e120d 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -273,11 +273,11 @@ static void output_handle_frame(struct wl_listener *listener, void *data) { // TODO: fullscreen if (!pixman_region32_not_empty(&output->damage) && !wlr_output->needs_swap) { - int refresh = wlr_output->refresh; - if (refresh <= 0) { - refresh = 60; + float hz = wlr_output->refresh / 1000.0f; + if (hz <= 0) { + hz = 60; } - wl_event_source_timer_update(output->repaint_timer, 1000.0f / refresh); + wl_event_source_timer_update(output->repaint_timer, 1000.0f / hz); goto clear_damage; } From 8b3f3ddb7f806d64a47e60c8161d9546f6aeaccf Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 18 Jan 2018 17:18:21 +0100 Subject: [PATCH 09/75] rootston: fix double-buffering artifacts --- include/rootston/output.h | 2 +- rootston/output.c | 88 ++++++++++++++++++++++----------------- 2 files changed, 51 insertions(+), 39 deletions(-) diff --git a/include/rootston/output.h b/include/rootston/output.h index cf34496b..a0b2b1b4 100644 --- a/include/rootston/output.h +++ b/include/rootston/output.h @@ -16,7 +16,7 @@ struct roots_output { struct wl_listener frame; struct timespec last_frame; - pixman_region32_t damage; + pixman_region32_t damage, previous_damage; struct wl_event_source *repaint_timer; }; diff --git a/rootston/output.c b/rootston/output.c index 086e120d..c63e0e4b 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -50,7 +50,7 @@ static bool surface_intersect_output(struct wlr_surface *surface, static void render_surface(struct wlr_surface *surface, struct roots_output *output, struct timespec *when, - double lx, double ly, float rotation) { + pixman_region32_t *damage, double lx, double ly, float rotation) { if (!wlr_surface_has_buffer(surface)) { return; } @@ -68,8 +68,7 @@ static void render_surface(struct wlr_surface *surface, pixman_region32_init(&surface_damage); pixman_region32_union_rect(&surface_damage, &surface_damage, box.x, box.y, box.width, box.height); - pixman_region32_intersect(&surface_damage, &surface_damage, - &output->damage); + pixman_region32_intersect(&surface_damage, &surface_damage, damage); bool damaged = pixman_region32_not_empty(&surface_damage); if (!damaged) { goto finish_surface_damage; @@ -145,14 +144,15 @@ render_subsurfaces:; rotate_child_position(&sx, &sy, sw, sh, surface->current->width, surface->current->height, rotation); - render_surface(subsurface->surface, output, when, lx + sx, ly + sy, - rotation); + render_surface(subsurface->surface, output, when, damage, + lx + sx, ly + sy, rotation); } } static void render_xdg_v6_popups(struct wlr_xdg_surface_v6 *surface, struct roots_output *output, struct timespec *when, - double base_x, double base_y, float rotation) { + pixman_region32_t *damage, double base_x, double base_y, + float rotation) { double width = surface->surface->current->width; double height = surface->surface->current->height; @@ -170,18 +170,20 @@ static void render_xdg_v6_popups(struct wlr_xdg_surface_v6 *surface, rotate_child_position(&popup_sx, &popup_sy, popup_width, popup_height, width, height, rotation); - render_surface(popup->surface, output, when, + render_surface(popup->surface, output, when, damage, base_x + popup_sx, base_y + popup_sy, rotation); - render_xdg_v6_popups(popup, output, when, + render_xdg_v6_popups(popup, output, when, damage, base_x + popup_sx, base_y + popup_sy, rotation); } } static void render_wl_shell_surface(struct wlr_wl_shell_surface *surface, struct roots_output *output, struct timespec *when, - double lx, double ly, float rotation, bool is_child) { + pixman_region32_t *damage, double lx, double ly, float rotation, + bool is_child) { if (is_child || surface->state != WLR_WL_SHELL_SURFACE_STATE_POPUP) { - render_surface(surface->surface, output, when, lx, ly, rotation); + render_surface(surface->surface, output, when, damage, lx, ly, + rotation); double width = surface->surface->current->width; double height = surface->surface->current->height; @@ -196,40 +198,41 @@ static void render_wl_shell_surface(struct wlr_wl_shell_surface *surface, rotate_child_position(&popup_x, &popup_y, popup_width, popup_height, width, height, rotation); - render_wl_shell_surface(popup, output, when, + render_wl_shell_surface(popup, output, when, damage, lx + popup_x, ly + popup_y, rotation, true); } } } static void render_xwayland_children(struct wlr_xwayland_surface *surface, - struct roots_output *output, struct timespec *when) { + struct roots_output *output, struct timespec *when, + pixman_region32_t *damage) { struct wlr_xwayland_surface *child; wl_list_for_each(child, &surface->children, parent_link) { if (child->surface != NULL && child->added) { - render_surface(child->surface, output, when, + render_surface(child->surface, output, when, damage, child->x, child->y, 0); } - render_xwayland_children(child, output, when); + render_xwayland_children(child, output, when, damage); } } static void render_view(struct roots_view *view, struct roots_output *output, - struct timespec *when) { + struct timespec *when, pixman_region32_t *damage) { switch (view->type) { case ROOTS_XDG_SHELL_V6_VIEW: - render_surface(view->wlr_surface, output, when, view->x, view->y, - view->rotation); - render_xdg_v6_popups(view->xdg_surface_v6, output, when, + render_surface(view->wlr_surface, output, when, damage, + view->x, view->y, view->rotation); + render_xdg_v6_popups(view->xdg_surface_v6, output, when, damage, view->x, view->y, view->rotation); break; case ROOTS_WL_SHELL_VIEW: - render_wl_shell_surface(view->wl_shell_surface, output, when, + render_wl_shell_surface(view->wl_shell_surface, output, when, damage, view->x, view->y, view->rotation, false); break; case ROOTS_XWAYLAND_VIEW: - render_surface(view->wlr_surface, output, when, view->x, view->y, - view->rotation); + render_surface(view->wlr_surface, output, when, damage, + view->x, view->y, view->rotation); break; } } @@ -263,31 +266,36 @@ static void output_handle_frame(struct wl_listener *listener, void *data) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); + pixman_region32_t damage; + pixman_region32_init(&damage); + pixman_region32_union(&damage, &output->damage, &output->previous_damage); + // TODO: use real wlr_output damage if (wlr_output->needs_swap) { int width, height; wlr_output_effective_resolution(wlr_output, &width, &height); - pixman_region32_union_rect(&output->damage, &output->damage, 0, 0, - width, height); + pixman_region32_union_rect(&output->damage, &output->damage, + 0, 0, width, height); } // TODO: fullscreen - if (!pixman_region32_not_empty(&output->damage) && - !wlr_output->needs_swap) { + if (!pixman_region32_not_empty(&output->damage)) { float hz = wlr_output->refresh / 1000.0f; if (hz <= 0) { hz = 60; } wl_event_source_timer_update(output->repaint_timer, 1000.0f / hz); - goto clear_damage; + pixman_region32_clear(&output->damage); + goto damage_finish; } + wlr_log(L_DEBUG, "render"); + wlr_output_make_current(wlr_output); wlr_renderer_begin(server->renderer, wlr_output); glEnable(GL_SCISSOR_TEST); int nrects; - pixman_box32_t *rects = - pixman_region32_rectangles(&output->damage, &nrects); + pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); for (int i = 0; i < nrects; ++i) { glScissor(rects[i].x1, wlr_output->height - rects[i].y2, rects[i].x2 - rects[i].x1, rects[i].y2 - rects[i].y1); @@ -317,13 +325,14 @@ static void output_handle_frame(struct wl_listener *listener, void *data) { glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); - render_view(view, output, &now); + render_view(view, output, &now, &damage); // During normal rendering the xwayland window tree isn't traversed // because all windows are rendered. Here we only want to render // the fullscreen window's children so we have to traverse the tree. if (view->type == ROOTS_XWAYLAND_VIEW) { - render_xwayland_children(view->xwayland_surface, output, &now); + render_xwayland_children(view->xwayland_surface, output, &now, + &damage); } } @@ -334,7 +343,7 @@ static void output_handle_frame(struct wl_listener *listener, void *data) { struct roots_view *view; wl_list_for_each_reverse(view, &desktop->views, link) { - render_view(view, output, &now); + render_view(view, output, &now, &damage); } struct wlr_drag_icon *drag_icon = NULL; @@ -350,14 +359,14 @@ static void output_handle_frame(struct wl_listener *listener, void *data) { if (drag_icon->is_pointer) { icon_x = cursor->x + drag_icon->sx; icon_y = cursor->y + drag_icon->sy; - render_surface(icon, output, &now, icon_x, icon_y, 0); + render_surface(icon, output, &now, &damage, icon_x, icon_y, 0); } else { struct wlr_touch_point *point = wlr_seat_touch_get_point(seat->seat, drag_icon->touch_id); if (point) { icon_x = seat->touch_x + drag_icon->sx; icon_y = seat->touch_y + drag_icon->sy; - render_surface(icon, output, &now, icon_x, icon_y, 0); + render_surface(icon, output, &now, &damage, icon_x, icon_y, 0); } } } @@ -367,10 +376,12 @@ renderer_end: glDisable(GL_SCISSOR_TEST); wlr_renderer_end(server->renderer); wlr_output_swap_buffers(wlr_output); - -clear_damage: + pixman_region32_copy(&output->previous_damage, &output->damage); pixman_region32_clear(&output->damage); output->last_frame = desktop->last_frame = now; + +damage_finish: + pixman_region32_fini(&damage); } static int handle_repaint(void *data) { @@ -392,9 +403,8 @@ static void output_damage_whole_surface(struct roots_output *output, return; } - - pixman_region32_union_rect(&output->damage, &output->damage, box.x, box.y, - box.width, box.height); + pixman_region32_union_rect(&output->damage, &output->damage, + box.x, box.y, box.width, box.height); } void output_damage_whole_view(struct roots_output *output, @@ -462,6 +472,7 @@ void output_add_notify(struct wl_listener *listener, void *data) { output->wlr_output = wlr_output; wl_list_insert(&desktop->outputs, &output->link); pixman_region32_init(&output->damage); + pixman_region32_init(&output->previous_damage); struct wl_event_loop *ev = wl_display_get_event_loop(desktop->server->wl_display); output->repaint_timer = wl_event_loop_add_timer(ev, handle_repaint, output); @@ -518,6 +529,7 @@ void output_remove_notify(struct wl_listener *listener, void *data) { wl_event_source_remove(output->repaint_timer); pixman_region32_fini(&output->damage); + pixman_region32_fini(&output->previous_damage); wl_list_remove(&output->link); wl_list_remove(&output->frame.link); free(output); From baa17ec7553311af9dbeafec91ad47e62738acde Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 18 Jan 2018 18:57:11 +0100 Subject: [PATCH 10/75] rootston: damage whole output when created --- rootston/output.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/rootston/output.c b/rootston/output.c index c63e0e4b..6e3403fc 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -237,6 +237,13 @@ static void render_view(struct roots_view *view, struct roots_output *output, } } +static void output_damage_whole(struct roots_output *output) { + int width, height; + wlr_output_effective_resolution(output->wlr_output, &width, &height); + pixman_region32_union_rect(&output->damage, &output->damage, + 0, 0, width, height); +} + static bool has_standalone_surface(struct roots_view *view) { if (!wl_list_empty(&view->wlr_surface->subsurface_list)) { return false; @@ -253,8 +260,7 @@ static bool has_standalone_surface(struct roots_view *view) { return true; } -static void output_handle_frame(struct wl_listener *listener, void *data) { - struct roots_output *output = wl_container_of(listener, output, frame); +static void render_output(struct roots_output *output) { struct wlr_output *wlr_output = output->wlr_output; struct roots_desktop *desktop = output->desktop; struct roots_server *server = desktop->server; @@ -272,10 +278,7 @@ static void output_handle_frame(struct wl_listener *listener, void *data) { // TODO: use real wlr_output damage if (wlr_output->needs_swap) { - int width, height; - wlr_output_effective_resolution(wlr_output, &width, &height); - pixman_region32_union_rect(&output->damage, &output->damage, - 0, 0, width, height); + output_damage_whole(output); } // TODO: fullscreen if (!pixman_region32_not_empty(&output->damage)) { @@ -384,9 +387,14 @@ damage_finish: pixman_region32_fini(&damage); } +static void output_handle_frame(struct wl_listener *listener, void *data) { + struct roots_output *output = wl_container_of(listener, output, frame); + render_output(output); +} + static int handle_repaint(void *data) { struct roots_output *output = data; - output_handle_frame(&output->frame, output->wlr_output); + render_output(output); return 0; } @@ -503,6 +511,8 @@ void output_add_notify(struct wl_listener *listener, void *data) { roots_seat_configure_cursor(seat); roots_seat_configure_xcursor(seat); } + + output_damage_whole(output); } void output_remove_notify(struct wl_listener *listener, void *data) { From bde255933eb4cd2bab2d310725ab5de39467b900 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 18 Jan 2018 19:47:21 +0100 Subject: [PATCH 11/75] output: add wlr_output::damage, fixes #572 --- backend/meson.build | 13 +++++++++++- include/wlr/types/wlr_output.h | 3 ++- render/meson.build | 2 +- rootston/output.c | 11 ++++------ types/wlr_output.c | 39 +++++++++++++++++++++++++++------- xcursor/wlr_xcursor.c | 1 - 6 files changed, 50 insertions(+), 19 deletions(-) diff --git a/backend/meson.build b/backend/meson.build index b8084448..9931f546 100644 --- a/backend/meson.build +++ b/backend/meson.build @@ -45,5 +45,16 @@ lib_wlr_backend = static_library( 'wlr_backend', backend_files, include_directories: wlr_inc, - dependencies: [wayland_server, egl, gbm, libinput, systemd, elogind, wlr_render, wlr_protos, drm], + dependencies: [ + wayland_server, + egl, + gbm, + libinput, + systemd, + elogind, + wlr_render, + wlr_protos, + drm, + pixman, + ], ) diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 71463cb5..f6a5ac84 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -2,6 +2,7 @@ #define WLR_TYPES_WLR_OUTPUT_H #include +#include #include #include @@ -51,8 +52,8 @@ struct wlr_output { float scale; enum wl_output_subpixel subpixel; enum wl_output_transform transform; - bool needs_swap; + pixman_region32_t damage; float transform_matrix[16]; // Note: some backends may have zero modes diff --git a/render/meson.build b/render/meson.build index 1eea9a83..309e83cd 100644 --- a/render/meson.build +++ b/render/meson.build @@ -22,7 +22,7 @@ lib_wlr_render = static_library( glapi[0], glapi[1], include_directories: wlr_inc, - dependencies: [glesv2, egl], + dependencies: [glesv2, egl, pixman], ) wlr_render = declare_dependency( diff --git a/rootston/output.c b/rootston/output.c index 6e3403fc..38ca7241 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -62,7 +62,6 @@ static void render_surface(struct wlr_surface *surface, goto render_subsurfaces; } - // TODO: do not render regions of the surface that aren't damaged // TODO: output scale, output transform support pixman_region32_t surface_damage; pixman_region32_init(&surface_damage); @@ -71,7 +70,7 @@ static void render_surface(struct wlr_surface *surface, pixman_region32_intersect(&surface_damage, &surface_damage, damage); bool damaged = pixman_region32_not_empty(&surface_damage); if (!damaged) { - goto finish_surface_damage; + goto surface_damage_finish; } float transform[16]; @@ -130,7 +129,7 @@ static void render_surface(struct wlr_surface *surface, wlr_surface_send_frame_done(surface, when); -finish_surface_damage: +surface_damage_finish: pixman_region32_fini(&surface_damage); render_subsurfaces:; @@ -272,14 +271,12 @@ static void render_output(struct roots_output *output) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); + pixman_region32_union(&output->damage, &output->damage, &wlr_output->damage); + pixman_region32_t damage; pixman_region32_init(&damage); pixman_region32_union(&damage, &output->damage, &output->previous_damage); - // TODO: use real wlr_output damage - if (wlr_output->needs_swap) { - output_damage_whole(output); - } // TODO: fullscreen if (!pixman_region32_not_empty(&output->damage)) { float hz = wlr_output->refresh / 1000.0f; diff --git a/types/wlr_output.c b/types/wlr_output.c index b47fb3a0..e55243ef 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -279,6 +279,7 @@ void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, wl_signal_init(&output->events.scale); wl_signal_init(&output->events.transform); wl_signal_init(&output->events.destroy); + pixman_region32_init(&output->damage); output->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &output->display_destroy); @@ -292,6 +293,7 @@ void wlr_output_destroy(struct wlr_output *output) { wl_list_remove(&output->display_destroy.link); wlr_output_destroy_global(output); wlr_output_set_fullscreen_surface(output, NULL); + pixman_region32_fini(&output->damage); wl_signal_emit(&output->events.destroy, output); @@ -440,7 +442,7 @@ void wlr_output_swap_buffers(struct wlr_output *output) { } output->impl->swap_buffers(output); - output->needs_swap = false; + pixman_region32_clear(&output->damage); } void wlr_output_set_gamma(struct wlr_output *output, @@ -457,12 +459,17 @@ uint32_t wlr_output_get_gamma_size(struct wlr_output *output) { return output->impl->get_gamma_size(output); } +static void output_damage_whole(struct wlr_output *output) { + pixman_region32_union_rect(&output->damage, &output->damage, 0, 0, + output->width, output->height); +} + static void output_fullscreen_surface_reset(struct wlr_output *output) { if (output->fullscreen_surface != NULL) { wl_list_remove(&output->fullscreen_surface_commit.link); wl_list_remove(&output->fullscreen_surface_destroy.link); output->fullscreen_surface = NULL; - output->needs_swap = true; + output_damage_whole(output); } } @@ -470,7 +477,8 @@ static void output_fullscreen_surface_handle_commit( struct wl_listener *listener, void *data) { struct wlr_output *output = wl_container_of(listener, output, fullscreen_surface_commit); - output->needs_swap = true; + // TODO: use surface damage + output_damage_whole(output); } static void output_fullscreen_surface_handle_destroy( @@ -491,7 +499,7 @@ void wlr_output_set_fullscreen_surface(struct wlr_output *output, output_fullscreen_surface_reset(output); output->fullscreen_surface = surface; - output->needs_swap = true; + output_damage_whole(output); if (surface == NULL) { return; @@ -507,9 +515,16 @@ void wlr_output_set_fullscreen_surface(struct wlr_output *output, } +static void output_cursor_damage_whole(struct wlr_output_cursor *cursor) { + struct wlr_box box; + output_cursor_get_box(cursor, &box); + pixman_region32_union_rect(&cursor->output->damage, &cursor->output->damage, + box.x, box.y, box.width, box.height); +} + static void output_cursor_reset(struct wlr_output_cursor *cursor) { if (cursor->output->hardware_cursor != cursor) { - cursor->output->needs_swap = true; + output_cursor_damage_whole(cursor); } if (cursor->surface != NULL) { wl_list_remove(&cursor->surface_commit.link); @@ -543,7 +558,7 @@ bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor, } wlr_log(L_DEBUG, "Falling back to software cursor"); - cursor->output->needs_swap = true; + output_cursor_damage_whole(cursor); cursor->enabled = pixels != NULL; if (!cursor->enabled) { @@ -602,7 +617,7 @@ static void output_cursor_commit(struct wlr_output_cursor *cursor) { cursor->height = cursor->surface->current->height * cursor->output->scale; if (cursor->output->hardware_cursor != cursor) { - cursor->output->needs_swap = true; + output_cursor_damage_whole(cursor); } else { // TODO: upload pixels @@ -677,6 +692,14 @@ void wlr_output_cursor_set_surface(struct wlr_output_cursor *cursor, bool wlr_output_cursor_move(struct wlr_output_cursor *cursor, double x, double y) { + if (cursor->x == x && cursor->y == y) { + return true; + } + + if (cursor->output->hardware_cursor != cursor) { + output_cursor_damage_whole(cursor); + } + x *= cursor->output->scale; y *= cursor->output->scale; cursor->x = x; @@ -684,7 +707,7 @@ bool wlr_output_cursor_move(struct wlr_output_cursor *cursor, output_cursor_update_visible(cursor); if (cursor->output->hardware_cursor != cursor) { - cursor->output->needs_swap = true; + output_cursor_damage_whole(cursor); return true; } diff --git a/xcursor/wlr_xcursor.c b/xcursor/wlr_xcursor.c index b1678223..2d1a38b5 100644 --- a/xcursor/wlr_xcursor.c +++ b/xcursor/wlr_xcursor.c @@ -24,7 +24,6 @@ */ #define _XOPEN_SOURCE 500 -#include #include #include #include From bed752210803fa8ed915b6fc86037f4b94d3f6f8 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 18 Jan 2018 19:50:34 +0100 Subject: [PATCH 12/75] rootston: fix segfault when destroying unmapped xwayland view This happens when closing chromium for instance. --- rootston/output.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rootston/output.c b/rootston/output.c index 38ca7241..8d90ebb7 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -414,7 +414,9 @@ static void output_damage_whole_surface(struct roots_output *output, void output_damage_whole_view(struct roots_output *output, struct roots_view *view) { - output_damage_whole_surface(output, view->wlr_surface, view->x, view->y); + if (view->wlr_surface != NULL) { + output_damage_whole_surface(output, view->wlr_surface, view->x, view->y); + } // TODO: subsurfaces, popups, etc } From 3ba447a8f98ba804e51d9a2caabc5566e386595a Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 18 Jan 2018 20:08:26 +0100 Subject: [PATCH 13/75] rootston: fix damage test --- rootston/output.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rootston/output.c b/rootston/output.c index 8d90ebb7..62327b0c 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -278,13 +278,12 @@ static void render_output(struct roots_output *output) { pixman_region32_union(&damage, &output->damage, &output->previous_damage); // TODO: fullscreen - if (!pixman_region32_not_empty(&output->damage)) { + if (!pixman_region32_not_empty(&damage)) { float hz = wlr_output->refresh / 1000.0f; if (hz <= 0) { hz = 60; } wl_event_source_timer_update(output->repaint_timer, 1000.0f / hz); - pixman_region32_clear(&output->damage); goto damage_finish; } From 59ba8f35edba01a9a778a7255c65f37592025ccf Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 18 Jan 2018 21:34:10 +0100 Subject: [PATCH 14/75] rootston: use surface damage --- rootston/output.c | 28 ++++++++++++++++++++++++++-- types/wlr_output.c | 43 +++++++++++++++++++++++++++++-------------- types/wlr_surface.c | 10 +++++----- 3 files changed, 60 insertions(+), 21 deletions(-) diff --git a/rootston/output.c b/rootston/output.c index 62327b0c..6187217e 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -420,10 +420,34 @@ void output_damage_whole_view(struct roots_output *output, // TODO: subsurfaces, popups, etc } +static void output_damage_from_surface(struct roots_output *output, + struct wlr_surface *surface, double lx, double ly) { + if (!wlr_surface_has_buffer(surface)) { + return; + } + + struct wlr_box box; + bool intersects = surface_intersect_output(surface, + output->desktop->layout, output->wlr_output, lx, ly, &box); + if (!intersects) { + return; + } + + pixman_region32_t damage; + pixman_region32_init(&damage); + pixman_region32_copy(&damage, &surface->current->surface_damage); + pixman_region32_translate(&damage, box.x, box.y); + pixman_region32_union(&output->damage, &output->damage, &damage); + pixman_region32_fini(&damage); +} + void output_damage_from_view(struct roots_output *output, struct roots_view *view) { - // TODO: use surface damage - output_damage_whole_view(output, view); + if (view->wlr_surface != NULL) { + output_damage_from_surface(output, view->wlr_surface, view->x, view->y); + } + + // TODO: subsurfaces, popups, etc } static void set_mode(struct wlr_output *output, diff --git a/types/wlr_output.c b/types/wlr_output.c index e55243ef..c5f2ce87 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -332,19 +332,22 @@ void wlr_output_make_current(struct wlr_output *output) { output->impl->make_current(output); } -static void output_fullscreen_surface_render(struct wlr_output *output, - struct wlr_surface *surface, const struct timespec *when) { +static void output_fullscreen_surface_get_box(struct wlr_output *output, + struct wlr_surface *surface, struct wlr_box *box) { int width, height; wlr_output_effective_resolution(output, &width, &height); int x = (width - surface->current->width) / 2; int y = (height - surface->current->height) / 2; - int render_x = x * output->scale; - int render_y = y * output->scale; - int render_width = surface->current->width * output->scale; - int render_height = surface->current->height * output->scale; + box->x = x * output->scale; + box->y = y * output->scale; + box->width = surface->current->width * output->scale; + box->height = surface->current->height * output->scale; +} +static void output_fullscreen_surface_render(struct wlr_output *output, + struct wlr_surface *surface, const struct timespec *when) { glViewport(0, 0, output->width, output->height); glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); @@ -353,11 +356,14 @@ static void output_fullscreen_surface_render(struct wlr_output *output, return; } + struct wlr_box box; + output_fullscreen_surface_get_box(output, surface, &box); + float translate[16]; - wlr_matrix_translate(&translate, render_x, render_y, 0); + wlr_matrix_translate(&translate, box.x, box.y, 0); float scale[16]; - wlr_matrix_scale(&scale, render_width, render_height, 1); + wlr_matrix_scale(&scale, box.width, box.height, 1); float matrix[16]; wlr_matrix_mul(&translate, &scale, &matrix); @@ -401,14 +407,14 @@ static void output_cursor_render(struct wlr_output_cursor *cursor, glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - struct wlr_box cursor_box; - output_cursor_get_box(cursor, &cursor_box); + struct wlr_box box; + output_cursor_get_box(cursor, &box); float translate[16]; - wlr_matrix_translate(&translate, cursor_box.x, cursor_box.y, 0); + wlr_matrix_translate(&translate, box.x, box.y, 0); float scale[16]; - wlr_matrix_scale(&scale, cursor_box.width, cursor_box.height, 1); + wlr_matrix_scale(&scale, box.width, box.height, 1); float matrix[16]; wlr_matrix_mul(&translate, &scale, &matrix); @@ -477,8 +483,17 @@ static void output_fullscreen_surface_handle_commit( struct wl_listener *listener, void *data) { struct wlr_output *output = wl_container_of(listener, output, fullscreen_surface_commit); - // TODO: use surface damage - output_damage_whole(output); + struct wlr_surface *surface = output->fullscreen_surface; + + struct wlr_box box; + output_fullscreen_surface_get_box(output, surface, &box); + + pixman_region32_t damage; + pixman_region32_init(&damage); + pixman_region32_copy(&damage, &surface->current->surface_damage); + pixman_region32_translate(&damage, box.x, box.y); + pixman_region32_union(&output->damage, &output->damage, &damage); + pixman_region32_fini(&damage); } static void output_fullscreen_surface_handle_destroy( diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 8e024177..29cc7cad 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -351,7 +351,7 @@ static void wlr_surface_damage_subsurfaces(struct wlr_subsurface *subsurface) { } } -static void wlr_surface_flush_damage(struct wlr_surface *surface, +static void wlr_surface_apply_damage(struct wlr_surface *surface, bool reupload_buffer) { if (!surface->current->buffer) { return; @@ -391,9 +391,6 @@ static void wlr_surface_flush_damage(struct wlr_surface *surface, } release: - pixman_region32_clear(&surface->current->surface_damage); - pixman_region32_clear(&surface->current->buffer_damage); - wlr_surface_state_release_buffer(surface->current); } @@ -413,7 +410,7 @@ static void wlr_surface_commit_pending(struct wlr_surface *surface) { bool reupload_buffer = oldw != surface->current->buffer_width || oldh != surface->current->buffer_height; - wlr_surface_flush_damage(surface, reupload_buffer); + wlr_surface_apply_damage(surface, reupload_buffer); // commit subsurface order struct wlr_subsurface *subsurface; @@ -434,6 +431,9 @@ static void wlr_surface_commit_pending(struct wlr_surface *surface) { // TODO: add the invalid bitfield to this callback wl_signal_emit(&surface->events.commit, surface); + + pixman_region32_clear(&surface->current->surface_damage); + pixman_region32_clear(&surface->current->buffer_damage); } static bool wlr_subsurface_is_synchronized(struct wlr_subsurface *subsurface) { From f061a1da6313e08d57b9f54662a5703c9c43c6d8 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 18 Jan 2018 22:18:53 +0100 Subject: [PATCH 15/75] output: fix software cursor artifacts --- types/wlr_output.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/types/wlr_output.c b/types/wlr_output.c index c5f2ce87..af35f2b5 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -626,6 +626,10 @@ static void output_cursor_update_visible(struct wlr_output_cursor *cursor) { } static void output_cursor_commit(struct wlr_output_cursor *cursor) { + if (cursor->output->hardware_cursor != cursor) { + output_cursor_damage_whole(cursor); + } + // Some clients commit a cursor surface with a NULL buffer to hide it. cursor->enabled = wlr_surface_has_buffer(cursor->surface); cursor->width = cursor->surface->current->width * cursor->output->scale; @@ -662,14 +666,23 @@ void wlr_output_cursor_set_surface(struct wlr_output_cursor *cursor, return; } - cursor->hotspot_x = hotspot_x * cursor->output->scale; - cursor->hotspot_y = hotspot_y * cursor->output->scale; + hotspot_x *= cursor->output->scale; + hotspot_y *= cursor->output->scale; if (surface && surface == cursor->surface) { + // Only update the hotspot: surface hasn't changed + + if (cursor->output->hardware_cursor != cursor) { + output_cursor_damage_whole(cursor); + } + cursor->hotspot_x = hotspot_x; + cursor->hotspot_y = hotspot_y; + if (cursor->output->hardware_cursor != cursor) { + output_cursor_damage_whole(cursor); + } + if (cursor->output->hardware_cursor == cursor && cursor->output->impl->set_cursor) { - // If the surface hasn't changed and it's an hardware cursor, only - // update the hotspot cursor->output->impl->set_cursor(cursor->output, NULL, 0, 0, 0, hotspot_x, hotspot_y, false); } @@ -688,6 +701,8 @@ void wlr_output_cursor_set_surface(struct wlr_output_cursor *cursor, } cursor->surface = surface; + cursor->hotspot_x = hotspot_x; + cursor->hotspot_y = hotspot_y; if (surface != NULL) { wl_signal_add(&surface->events.commit, &cursor->surface_commit); From 977a401fa112ad198d7920e5aa1b0e94eb6f05b2 Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 19 Jan 2018 11:04:12 +0100 Subject: [PATCH 16/75] rootston: damage tracking for fullscreen views --- rootston/output.c | 79 ++++++++++++++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 29 deletions(-) diff --git a/rootston/output.c b/rootston/output.c index 6187217e..6b12898b 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -271,6 +271,35 @@ static void render_output(struct roots_output *output) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); + float clear_color[] = {0.25f, 0.25f, 0.25f}; + + // Check if we can delegate the fullscreen surface to the output + if (output->fullscreen_view != NULL) { + struct roots_view *view = output->fullscreen_view; + + // Make sure the view is centered on screen + const struct wlr_box *output_box = + wlr_output_layout_get_box(desktop->layout, wlr_output); + struct wlr_box view_box; + view_get_box(view, &view_box); + double view_x = (double)(output_box->width - view_box.width) / 2 + + output_box->x; + double view_y = (double)(output_box->height - view_box.height) / 2 + + output_box->y; + view_move(view, view_x, view_y); + + if (has_standalone_surface(view)) { + wlr_output_set_fullscreen_surface(wlr_output, view->wlr_surface); + } else { + wlr_output_set_fullscreen_surface(wlr_output, NULL); + } + + // Fullscreen views are rendered on a black background + clear_color[0] = clear_color[1] = clear_color[2] = 0; + } else { + wlr_output_set_fullscreen_surface(wlr_output, NULL); + } + pixman_region32_union(&output->damage, &output->damage, &wlr_output->damage); pixman_region32_t damage; @@ -298,46 +327,30 @@ static void render_output(struct roots_output *output) { for (int i = 0; i < nrects; ++i) { glScissor(rects[i].x1, wlr_output->height - rects[i].y2, rects[i].x2 - rects[i].x1, rects[i].y2 - rects[i].y1); - glClearColor(0.25f, 0.25f, 0.25f, 1); + glClearColor(clear_color[0], clear_color[1], clear_color[2], 1); glClear(GL_COLOR_BUFFER_BIT); } + // If a view is fullscreen on this output, render it if (output->fullscreen_view != NULL) { struct roots_view *view = output->fullscreen_view; - // Make sure the view is centered on screen - const struct wlr_box *output_box = - wlr_output_layout_get_box(desktop->layout, wlr_output); - struct wlr_box view_box; - view_get_box(view, &view_box); - double view_x = (double)(output_box->width - view_box.width) / 2 + - output_box->x; - double view_y = (double)(output_box->height - view_box.height) / 2 + - output_box->y; - view_move(view, view_x, view_y); + if (wlr_output->fullscreen_surface == view->wlr_surface) { + // The output will render the fullscreen view + goto renderer_end; + } - if (has_standalone_surface(view)) { - wlr_output_set_fullscreen_surface(wlr_output, view->wlr_surface); - } else { - wlr_output_set_fullscreen_surface(wlr_output, NULL); + render_view(view, output, &now, &damage); - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); - - render_view(view, output, &now, &damage); - - // During normal rendering the xwayland window tree isn't traversed - // because all windows are rendered. Here we only want to render - // the fullscreen window's children so we have to traverse the tree. - if (view->type == ROOTS_XWAYLAND_VIEW) { - render_xwayland_children(view->xwayland_surface, output, &now, - &damage); - } + // During normal rendering the xwayland window tree isn't traversed + // because all windows are rendered. Here we only want to render + // the fullscreen window's children so we have to traverse the tree. + if (view->type == ROOTS_XWAYLAND_VIEW) { + render_xwayland_children(view->xwayland_surface, output, &now, + &damage); } goto renderer_end; - } else { - wlr_output_set_fullscreen_surface(wlr_output, NULL); } struct roots_view *view; @@ -413,6 +426,10 @@ static void output_damage_whole_surface(struct roots_output *output, void output_damage_whole_view(struct roots_output *output, struct roots_view *view) { + if (output->fullscreen_view != NULL && output->fullscreen_view != view) { + return; + } + if (view->wlr_surface != NULL) { output_damage_whole_surface(output, view->wlr_surface, view->x, view->y); } @@ -443,6 +460,10 @@ static void output_damage_from_surface(struct roots_output *output, void output_damage_from_view(struct roots_output *output, struct roots_view *view) { + if (output->fullscreen_view != NULL && output->fullscreen_view != view) { + return; + } + if (view->wlr_surface != NULL) { output_damage_from_surface(output, view->wlr_surface, view->x, view->y); } From 443bd4cd898b86cf1056416f58e30cb451d1fcd4 Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 19 Jan 2018 11:20:27 +0100 Subject: [PATCH 17/75] output: fullscreen surface damage tracking --- include/wlr/types/wlr_output.h | 2 +- types/wlr_output.c | 40 ++++++++++++++++++++++++++++------ 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index f6a5ac84..bc05dfbf 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -53,7 +53,7 @@ struct wlr_output { enum wl_output_subpixel subpixel; enum wl_output_transform transform; - pixman_region32_t damage; + pixman_region32_t damage, previous_damage; float transform_matrix[16]; // Note: some backends may have zero modes diff --git a/types/wlr_output.c b/types/wlr_output.c index af35f2b5..dfcba906 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -280,6 +280,7 @@ void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, wl_signal_init(&output->events.transform); wl_signal_init(&output->events.destroy); pixman_region32_init(&output->damage); + pixman_region32_init(&output->previous_damage); output->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &output->display_destroy); @@ -293,7 +294,6 @@ void wlr_output_destroy(struct wlr_output *output) { wl_list_remove(&output->display_destroy.link); wlr_output_destroy_global(output); wlr_output_set_fullscreen_surface(output, NULL); - pixman_region32_fini(&output->damage); wl_signal_emit(&output->events.destroy, output); @@ -308,6 +308,9 @@ void wlr_output_destroy(struct wlr_output *output) { wlr_output_cursor_destroy(cursor); } + pixman_region32_fini(&output->damage); + pixman_region32_fini(&output->previous_damage); + if (output->impl && output->impl->destroy) { output->impl->destroy(output); } else { @@ -347,12 +350,15 @@ static void output_fullscreen_surface_get_box(struct wlr_output *output, } static void output_fullscreen_surface_render(struct wlr_output *output, - struct wlr_surface *surface, const struct timespec *when) { + struct wlr_surface *surface, const struct timespec *when, + pixman_region32_t *damage) { glViewport(0, 0, output->width, output->height); - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); if (!wlr_surface_has_buffer(surface)) { + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); return; } @@ -369,7 +375,17 @@ static void output_fullscreen_surface_render(struct wlr_output *output, wlr_matrix_mul(&translate, &scale, &matrix); wlr_matrix_mul(&output->transform_matrix, &matrix, &matrix); - wlr_render_with_matrix(surface->renderer, surface->texture, &matrix); + int nrects; + pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); + glEnable(GL_SCISSOR_TEST); + for (int i = 0; i < nrects; ++i) { + glScissor(rects[i].x1, output->height - rects[i].y2, + rects[i].x2 - rects[i].x1, rects[i].y2 - rects[i].y1); + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); + wlr_render_with_matrix(surface->renderer, surface->texture, &matrix); + } + glDisable(GL_SCISSOR_TEST); wlr_surface_send_frame_done(surface, when); } @@ -434,8 +450,17 @@ void wlr_output_swap_buffers(struct wlr_output *output) { clock_gettime(CLOCK_MONOTONIC, &now); if (output->fullscreen_surface != NULL) { - output_fullscreen_surface_render(output, output->fullscreen_surface, - &now); + pixman_region32_t damage; + pixman_region32_init(&damage); + pixman_region32_copy(&damage, &output->damage); + pixman_region32_union(&damage, &damage, &output->previous_damage); + + if (pixman_region32_not_empty(&damage)) { + output_fullscreen_surface_render(output, output->fullscreen_surface, + &now, &damage); + } + + pixman_region32_fini(&damage); } struct wlr_output_cursor *cursor; @@ -448,6 +473,7 @@ void wlr_output_swap_buffers(struct wlr_output *output) { } output->impl->swap_buffers(output); + pixman_region32_copy(&output->previous_damage, &output->damage); pixman_region32_clear(&output->damage); } From 7f9f918b78f438c60f959b30d6111acdfa4dfc27 Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 19 Jan 2018 11:31:04 +0100 Subject: [PATCH 18/75] rootston: damage output on mode change --- include/rootston/output.h | 4 +++- rootston/output.c | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/rootston/output.h b/include/rootston/output.h index a0b2b1b4..8d5550af 100644 --- a/include/rootston/output.h +++ b/include/rootston/output.h @@ -14,10 +14,12 @@ struct roots_output { struct roots_view *fullscreen_view; - struct wl_listener frame; struct timespec last_frame; pixman_region32_t damage, previous_damage; struct wl_event_source *repaint_timer; + + struct wl_listener frame; + struct wl_listener mode; }; void output_add_notify(struct wl_listener *listener, void *data); diff --git a/rootston/output.c b/rootston/output.c index 6b12898b..f7c113ca 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -471,6 +471,11 @@ void output_damage_from_view(struct roots_output *output, // TODO: subsurfaces, popups, etc } +static void output_handle_mode(struct wl_listener *listener, void *data) { + struct roots_output *output = wl_container_of(listener, output, mode); + output_damage_whole(output); +} + static void set_mode(struct wlr_output *output, struct roots_output_config *oc) { int mhz = (int)(oc->mode.refresh_rate * 1000); @@ -530,6 +535,8 @@ void output_add_notify(struct wl_listener *listener, void *data) { output->frame.notify = output_handle_frame; wl_signal_add(&wlr_output->events.frame, &output->frame); + output->mode.notify = output_handle_mode; + wl_signal_add(&wlr_output->events.mode, &output->mode); struct roots_output_config *output_config = roots_config_get_output(config, wlr_output); From a0f24b809e3b5f25885d44f8d2cfd9271ec1c506 Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 19 Jan 2018 13:13:46 +0100 Subject: [PATCH 19/75] output: add damage event --- include/wlr/types/wlr_output.h | 1 + render/gles2/renderer.c | 3 --- types/wlr_output.c | 5 +++++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index bc05dfbf..2c28e82f 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -63,6 +63,7 @@ struct wlr_output { int32_t refresh; // mHz struct { + struct wl_signal damage; struct wl_signal frame; struct wl_signal swap_buffers; struct wl_signal enable; diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 2dd64176..32f2eb02 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -107,9 +107,6 @@ static void init_globals() { static void wlr_gles2_begin(struct wlr_renderer *_renderer, struct wlr_output *output) { - // TODO: let users customize the clear color? - //GL_CALL(glClearColor(0.25f, 0.25f, 0.25f, 1)); - //GL_CALL(glClear(GL_COLOR_BUFFER_BIT)); GL_CALL(glViewport(0, 0, output->width, output->height)); // enable transparency diff --git a/types/wlr_output.c b/types/wlr_output.c index dfcba906..bf02967c 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -272,6 +272,7 @@ void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, output->scale = 1; wl_list_init(&output->cursors); wl_list_init(&output->wl_resources); + wl_signal_init(&output->events.damage); wl_signal_init(&output->events.frame); wl_signal_init(&output->events.swap_buffers); wl_signal_init(&output->events.enable); @@ -494,6 +495,7 @@ uint32_t wlr_output_get_gamma_size(struct wlr_output *output) { static void output_damage_whole(struct wlr_output *output) { pixman_region32_union_rect(&output->damage, &output->damage, 0, 0, output->width, output->height); + wl_signal_emit(&output->events.damage, output); } static void output_fullscreen_surface_reset(struct wlr_output *output) { @@ -520,6 +522,8 @@ static void output_fullscreen_surface_handle_commit( pixman_region32_translate(&damage, box.x, box.y); pixman_region32_union(&output->damage, &output->damage, &damage); pixman_region32_fini(&damage); + + wl_signal_emit(&output->events.damage, output); } static void output_fullscreen_surface_handle_destroy( @@ -561,6 +565,7 @@ static void output_cursor_damage_whole(struct wlr_output_cursor *cursor) { output_cursor_get_box(cursor, &box); pixman_region32_union_rect(&cursor->output->damage, &cursor->output->damage, box.x, box.y, box.width, box.height); + wl_signal_emit(&cursor->output->events.damage, cursor->output); } static void output_cursor_reset(struct wlr_output_cursor *cursor) { From b296481007f79481a90a82f3dee3aead2883d00c Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 19 Jan 2018 13:14:16 +0100 Subject: [PATCH 20/75] rootston: remove repaint timer, listen for damage instead --- include/rootston/output.h | 3 ++- rootston/output.c | 55 +++++++++++++++++++++++++-------------- 2 files changed, 37 insertions(+), 21 deletions(-) diff --git a/include/rootston/output.h b/include/rootston/output.h index 8d5550af..a80e1f49 100644 --- a/include/rootston/output.h +++ b/include/rootston/output.h @@ -16,10 +16,11 @@ struct roots_output { struct timespec last_frame; pixman_region32_t damage, previous_damage; - struct wl_event_source *repaint_timer; + bool frame_scheduled; struct wl_listener frame; struct wl_listener mode; + struct wl_listener damage_listener; }; void output_add_notify(struct wl_listener *listener, void *data); diff --git a/rootston/output.c b/rootston/output.c index f7c113ca..a1448917 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -236,13 +236,6 @@ static void render_view(struct roots_view *view, struct roots_output *output, } } -static void output_damage_whole(struct roots_output *output) { - int width, height; - wlr_output_effective_resolution(output->wlr_output, &width, &height); - pixman_region32_union_rect(&output->damage, &output->damage, - 0, 0, width, height); -} - static bool has_standalone_surface(struct roots_view *view) { if (!wl_list_empty(&view->wlr_surface->subsurface_list)) { return false; @@ -300,19 +293,13 @@ static void render_output(struct roots_output *output) { wlr_output_set_fullscreen_surface(wlr_output, NULL); } - pixman_region32_union(&output->damage, &output->damage, &wlr_output->damage); - pixman_region32_t damage; pixman_region32_init(&damage); pixman_region32_union(&damage, &output->damage, &output->previous_damage); // TODO: fullscreen if (!pixman_region32_not_empty(&damage)) { - float hz = wlr_output->refresh / 1000.0f; - if (hz <= 0) { - hz = 60; - } - wl_event_source_timer_update(output->repaint_timer, 1000.0f / hz); + output->frame_scheduled = false; goto damage_finish; } @@ -388,6 +375,7 @@ renderer_end: glDisable(GL_SCISSOR_TEST); wlr_renderer_end(server->renderer); wlr_output_swap_buffers(wlr_output); + output->frame_scheduled = true; pixman_region32_copy(&output->previous_damage, &output->damage); pixman_region32_clear(&output->damage); output->last_frame = desktop->last_frame = now; @@ -401,10 +389,27 @@ static void output_handle_frame(struct wl_listener *listener, void *data) { render_output(output); } -static int handle_repaint(void *data) { +static void handle_idle_render(void *data) { struct roots_output *output = data; render_output(output); - return 0; +} + +static void schedule_render(struct roots_output *output) { + if (!output->frame_scheduled) { + struct wl_event_loop *ev = + wl_display_get_event_loop(output->desktop->server->wl_display); + wl_event_loop_add_idle(ev, handle_idle_render, output); + output->frame_scheduled = true; + } +} + +static void output_damage_whole(struct roots_output *output) { + int width, height; + wlr_output_effective_resolution(output->wlr_output, &width, &height); + pixman_region32_union_rect(&output->damage, &output->damage, + 0, 0, width, height); + + schedule_render(output); } static void output_damage_whole_surface(struct roots_output *output, @@ -422,6 +427,8 @@ static void output_damage_whole_surface(struct roots_output *output, pixman_region32_union_rect(&output->damage, &output->damage, box.x, box.y, box.width, box.height); + + schedule_render(output); } void output_damage_whole_view(struct roots_output *output, @@ -456,6 +463,8 @@ static void output_damage_from_surface(struct roots_output *output, pixman_region32_translate(&damage, box.x, box.y); pixman_region32_union(&output->damage, &output->damage, &damage); pixman_region32_fini(&damage); + + schedule_render(output); } void output_damage_from_view(struct roots_output *output, @@ -476,6 +485,14 @@ static void output_handle_mode(struct wl_listener *listener, void *data) { output_damage_whole(output); } +static void output_handle_damage(struct wl_listener *listener, void *data) { + struct roots_output *output = + wl_container_of(listener, output, damage_listener); + pixman_region32_union(&output->damage, &output->damage, + &output->wlr_output->damage); + schedule_render(output); +} + static void set_mode(struct wlr_output *output, struct roots_output_config *oc) { int mhz = (int)(oc->mode.refresh_rate * 1000); @@ -529,14 +546,13 @@ void output_add_notify(struct wl_listener *listener, void *data) { wl_list_insert(&desktop->outputs, &output->link); pixman_region32_init(&output->damage); pixman_region32_init(&output->previous_damage); - struct wl_event_loop *ev = - wl_display_get_event_loop(desktop->server->wl_display); - output->repaint_timer = wl_event_loop_add_timer(ev, handle_repaint, output); output->frame.notify = output_handle_frame; wl_signal_add(&wlr_output->events.frame, &output->frame); output->mode.notify = output_handle_mode; wl_signal_add(&wlr_output->events.mode, &output->mode); + output->damage_listener.notify = output_handle_damage; + wl_signal_add(&wlr_output->events.damage, &output->damage_listener); struct roots_output_config *output_config = roots_config_get_output(config, wlr_output); @@ -587,7 +603,6 @@ void output_remove_notify(struct wl_listener *listener, void *data) { //example_config_configure_cursor(sample->config, sample->cursor, // sample->compositor); - wl_event_source_remove(output->repaint_timer); pixman_region32_fini(&output->damage); pixman_region32_fini(&output->previous_damage); wl_list_remove(&output->link); From e29a0df8c14fdc5038e64de4a1ad08a7de8fd7fc Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 19 Jan 2018 14:08:47 +0100 Subject: [PATCH 21/75] output: fix software cursors damage tracking --- examples/multi-pointer.c | 2 +- examples/output-layout.c | 2 +- examples/pointer.c | 2 +- examples/rotation.c | 2 +- examples/simple.c | 2 +- examples/tablet.c | 2 +- examples/touch.c | 2 +- include/wlr/types/wlr_output.h | 9 +++- rootston/output.c | 2 +- types/wlr_output.c | 82 ++++++++++++++++++++++++---------- 10 files changed, 74 insertions(+), 33 deletions(-) diff --git a/examples/multi-pointer.c b/examples/multi-pointer.c index 62aa1bac..d5297aef 100644 --- a/examples/multi-pointer.c +++ b/examples/multi-pointer.c @@ -62,7 +62,7 @@ static void handle_output_frame(struct output_state *output, sample->clear_color[2], sample->clear_color[3]); glClear(GL_COLOR_BUFFER_BIT); - wlr_output_swap_buffers(wlr_output); + wlr_output_swap_buffers(wlr_output, NULL, NULL); } static void handle_output_add(struct output_state *ostate) { diff --git a/examples/output-layout.c b/examples/output-layout.c index 35ed22a8..825e97d1 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -125,7 +125,7 @@ static void handle_output_frame(struct output_state *output, } wlr_renderer_end(sample->renderer); - wlr_output_swap_buffers(wlr_output); + wlr_output_swap_buffers(wlr_output, NULL, NULL); } static void handle_output_add(struct output_state *ostate) { diff --git a/examples/pointer.c b/examples/pointer.c index 9894e311..8b0993e5 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -91,7 +91,7 @@ static void handle_output_frame(struct output_state *output, sample->clear_color[2], sample->clear_color[3]); glClear(GL_COLOR_BUFFER_BIT); - wlr_output_swap_buffers(wlr_output); + wlr_output_swap_buffers(wlr_output, NULL, NULL); } static void handle_output_add(struct output_state *ostate) { diff --git a/examples/rotation.c b/examples/rotation.c index 1d974025..6fa06dcc 100644 --- a/examples/rotation.c +++ b/examples/rotation.c @@ -56,7 +56,7 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts } wlr_renderer_end(sample->renderer); - wlr_output_swap_buffers(wlr_output); + wlr_output_swap_buffers(wlr_output, NULL, NULL); long ms = (ts->tv_sec - output->last_frame.tv_sec) * 1000 + (ts->tv_nsec - output->last_frame.tv_nsec) / 1000000; diff --git a/examples/simple.c b/examples/simple.c index 95c056c8..f788618d 100644 --- a/examples/simple.c +++ b/examples/simple.c @@ -40,7 +40,7 @@ void handle_output_frame(struct output_state *output, struct timespec *ts) { glClearColor(sample->color[0], sample->color[1], sample->color[2], 1.0); glClear(GL_COLOR_BUFFER_BIT); - wlr_output_swap_buffers(output->output); + wlr_output_swap_buffers(output->output, NULL, NULL); } int main() { diff --git a/examples/tablet.c b/examples/tablet.c index f3cd5339..5498c9ff 100644 --- a/examples/tablet.c +++ b/examples/tablet.c @@ -76,7 +76,7 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts } wlr_renderer_end(sample->renderer); - wlr_output_swap_buffers(wlr_output); + wlr_output_swap_buffers(wlr_output, NULL, NULL); } static void handle_tool_axis(struct tablet_tool_state *tstate, diff --git a/examples/touch.c b/examples/touch.c index 4c1f97b6..5c778743 100644 --- a/examples/touch.c +++ b/examples/touch.c @@ -56,7 +56,7 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts } wlr_renderer_end(sample->renderer); - wlr_output_swap_buffers(wlr_output); + wlr_output_swap_buffers(wlr_output, NULL, NULL); } static void handle_touch_down(struct touch_state *tstate, int32_t touch_id, diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 2c28e82f..1091ee62 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -2,6 +2,7 @@ #define WLR_TYPES_WLR_OUTPUT_H #include +#include #include #include #include @@ -103,7 +104,13 @@ void wlr_output_destroy(struct wlr_output *output); void wlr_output_effective_resolution(struct wlr_output *output, int *width, int *height); void wlr_output_make_current(struct wlr_output *output); -void wlr_output_swap_buffers(struct wlr_output *output); +/** + * Swaps the output buffers. If the time of the frame isn't known, set `when` to + * NULL. If the compositor doesn't support damage tracking, set `damage` to + * NULL. + */ +void wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when, + pixman_region32_t *damage); void wlr_output_set_gamma(struct wlr_output *output, uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b); uint32_t wlr_output_get_gamma_size(struct wlr_output *output); diff --git a/rootston/output.c b/rootston/output.c index a1448917..93d74703 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -374,7 +374,7 @@ static void render_output(struct roots_output *output) { renderer_end: glDisable(GL_SCISSOR_TEST); wlr_renderer_end(server->renderer); - wlr_output_swap_buffers(wlr_output); + wlr_output_swap_buffers(wlr_output, &now, &damage); output->frame_scheduled = true; pixman_region32_copy(&output->previous_damage, &output->damage); pixman_region32_clear(&output->damage); diff --git a/types/wlr_output.c b/types/wlr_output.c index bf02967c..55ee1cb3 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -408,7 +408,7 @@ static void output_cursor_get_box(struct wlr_output_cursor *cursor, } static void output_cursor_render(struct wlr_output_cursor *cursor, - const struct timespec *when) { + const struct timespec *when, pixman_region32_t *damage) { struct wlr_texture *texture = cursor->texture; struct wlr_renderer *renderer = cursor->renderer; if (cursor->surface != NULL) { @@ -420,13 +420,22 @@ static void output_cursor_render(struct wlr_output_cursor *cursor, return; } + struct wlr_box box; + output_cursor_get_box(cursor, &box); + + pixman_region32_t surface_damage; + pixman_region32_init(&surface_damage); + pixman_region32_union_rect(&surface_damage, &surface_damage, box.x, box.y, + box.width, box.height); + pixman_region32_intersect(&surface_damage, &surface_damage, damage); + if (!pixman_region32_not_empty(&surface_damage)) { + goto surface_damage_finish; + } + glViewport(0, 0, cursor->output->width, cursor->output->height); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - struct wlr_box box; - output_cursor_get_box(cursor, &box); - float translate[16]; wlr_matrix_translate(&translate, box.x, box.y, 0); @@ -439,43 +448,68 @@ static void output_cursor_render(struct wlr_output_cursor *cursor, wlr_render_with_matrix(renderer, texture, &matrix); + int nrects; + pixman_box32_t *rects = pixman_region32_rectangles(&surface_damage, &nrects); + glEnable(GL_SCISSOR_TEST); + for (int i = 0; i < nrects; ++i) { + glScissor(rects[i].x1, cursor->output->height - rects[i].y2, + rects[i].x2 - rects[i].x1, rects[i].y2 - rects[i].y1); + wlr_render_with_matrix(renderer, texture, &matrix); + } + glDisable(GL_SCISSOR_TEST); + if (cursor->surface != NULL) { wlr_surface_send_frame_done(cursor->surface, when); } + +surface_damage_finish: + pixman_region32_fini(&surface_damage); } -void wlr_output_swap_buffers(struct wlr_output *output) { - wl_signal_emit(&output->events.swap_buffers, &output); +void wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when, + pixman_region32_t *damage) { + wl_signal_emit(&output->events.swap_buffers, damage); - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); + pixman_region32_t *render_damage = damage; + if (damage == NULL) { + pixman_region32_t output_damage; + pixman_region32_init(&output_damage); + pixman_region32_copy(&output_damage, &output->damage); + pixman_region32_union(&output_damage, &output_damage, + &output->previous_damage); + render_damage = &output_damage; + } - if (output->fullscreen_surface != NULL) { - pixman_region32_t damage; - pixman_region32_init(&damage); - pixman_region32_copy(&damage, &output->damage); - pixman_region32_union(&damage, &damage, &output->previous_damage); + if (when == NULL) { + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + when = &now; + } - if (pixman_region32_not_empty(&damage)) { + if (pixman_region32_not_empty(render_damage)) { + if (output->fullscreen_surface != NULL) { output_fullscreen_surface_render(output, output->fullscreen_surface, - &now, &damage); + when, render_damage); } - pixman_region32_fini(&damage); - } - - struct wlr_output_cursor *cursor; - wl_list_for_each(cursor, &output->cursors, link) { - if (!cursor->enabled || !cursor->visible || - output->hardware_cursor == cursor) { - continue; + struct wlr_output_cursor *cursor; + wl_list_for_each(cursor, &output->cursors, link) { + if (!cursor->enabled || !cursor->visible || + output->hardware_cursor == cursor) { + continue; + } + output_cursor_render(cursor, when, render_damage); } - output_cursor_render(cursor, &now); } + // TODO: provide `damage` (not `render_damage`) to backend output->impl->swap_buffers(output); pixman_region32_copy(&output->previous_damage, &output->damage); pixman_region32_clear(&output->damage); + + if (damage == NULL) { + pixman_region32_fini(render_damage); + } } void wlr_output_set_gamma(struct wlr_output *output, From d6c74d8a16ea38fccfd47dcd068a3c4f2423bfe4 Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 19 Jan 2018 14:32:42 +0100 Subject: [PATCH 22/75] rooston: restrict damage to output extents --- rootston/output.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rootston/output.c b/rootston/output.c index 93d74703..407ba144 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -296,6 +296,8 @@ static void render_output(struct roots_output *output) { pixman_region32_t damage; pixman_region32_init(&damage); pixman_region32_union(&damage, &output->damage, &output->previous_damage); + pixman_region32_intersect_rect(&damage, &damage, 0, 0, wlr_output->width, + wlr_output->height); // TODO: fullscreen if (!pixman_region32_not_empty(&damage)) { @@ -404,10 +406,8 @@ static void schedule_render(struct roots_output *output) { } static void output_damage_whole(struct roots_output *output) { - int width, height; - wlr_output_effective_resolution(output->wlr_output, &width, &height); pixman_region32_union_rect(&output->damage, &output->damage, - 0, 0, width, height); + 0, 0, output->wlr_output->width, output->wlr_output->height); schedule_render(output); } From f0f97280a0364f58c1b5fc3f95818c6969058010 Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 19 Jan 2018 23:35:23 +0100 Subject: [PATCH 23/75] backend/drm: fix retry pageflip --- backend/drm/drm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 0d32605a..267cafc3 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -199,14 +199,13 @@ static void wlr_drm_connector_swap_buffers(struct wlr_output *output) { if (drm->parent) { bo = wlr_drm_surface_mgpu_copy(&plane->mgpu_surf, bo); } - uint32_t fb_id = get_fb_for_bo(bo); if (drm->iface->crtc_pageflip(drm, conn, crtc, fb_id, NULL)) { conn->pageflip_pending = true; } else { wl_event_source_timer_update(conn->retry_pageflip, - 1000.0f / conn->output.current_mode->refresh); + 1000000.0f / conn->output.current_mode->refresh); } } @@ -241,7 +240,7 @@ void wlr_drm_connector_start_renderer(struct wlr_drm_connector *conn) { conn->pageflip_pending = true; } else { wl_event_source_timer_update(conn->retry_pageflip, - 1000.0f / conn->output.current_mode->refresh); + 1000000.0f / conn->output.current_mode->refresh); } } From 584f06ad2fb45cfc57fc1a0cdd59deec0c2d18c1 Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 19 Jan 2018 23:46:40 +0100 Subject: [PATCH 24/75] backend/drm: do not try a pageflip is another one is in pending --- backend/drm/drm.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 267cafc3..e6bfee8c 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -201,6 +201,11 @@ static void wlr_drm_connector_swap_buffers(struct wlr_output *output) { } uint32_t fb_id = get_fb_for_bo(bo); + if (conn->pageflip_pending) { + wlr_log(L_ERROR, "Skipping pageflip"); + return; + } + if (drm->iface->crtc_pageflip(drm, conn, crtc, fb_id, NULL)) { conn->pageflip_pending = true; } else { From ddafcb86a2e4116183b59947afe046596c3301ea Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 20 Jan 2018 00:52:43 +0100 Subject: [PATCH 25/75] surface: add resize damage --- types/wlr_surface.c | 79 +++++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 35 deletions(-) diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 29cc7cad..58413818 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -133,11 +133,14 @@ static void surface_set_input_region(struct wl_client *client, } } -static void wlr_surface_update_size(struct wlr_surface *surface, struct wlr_surface_state *state) { +static bool wlr_surface_update_size(struct wlr_surface *surface, + struct wlr_surface_state *state) { if (!state->buffer) { + pixman_region32_union_rect(&state->surface_damage, + &state->surface_damage, 0, 0, state->width, state->height); state->height = 0; state->width = 0; - return; + return true; } int scale = state->scale; @@ -146,16 +149,16 @@ static void wlr_surface_update_size(struct wlr_surface *surface, struct wlr_surf wlr_texture_get_buffer_size(surface->texture, state->buffer, &state->buffer_width, &state->buffer_height); - int _width = state->buffer_width / scale; - int _height = state->buffer_height / scale; + int width = state->buffer_width / scale; + int height = state->buffer_height / scale; if (transform == WL_OUTPUT_TRANSFORM_90 || transform == WL_OUTPUT_TRANSFORM_270 || transform == WL_OUTPUT_TRANSFORM_FLIPPED_90 || transform == WL_OUTPUT_TRANSFORM_FLIPPED_270) { - int tmp = _width; - _width = _height; - _height = tmp; + int tmp = width; + width = height; + height = tmp; } struct wlr_frame_callback *cb, *tmp; @@ -164,24 +167,36 @@ static void wlr_surface_update_size(struct wlr_surface *surface, struct wlr_surf } wl_list_init(&state->frame_callback_list); - state->width = _width; - state->height = _height; + bool update_damage = false; + if (width < state->width) { + pixman_region32_union_rect(&state->surface_damage, &state->surface_damage, + width, 0, state->width - width, state->height); + update_damage = true; + } + if (height < state->height) { + pixman_region32_union_rect(&state->surface_damage, &state->surface_damage, + 0, height, state->width, state->height - height); + update_damage = true; + } + + state->width = width; + state->height = height; + + return update_damage; } static void wlr_surface_to_buffer_region(int scale, enum wl_output_transform transform, pixman_region32_t *surface_region, - pixman_region32_t *buffer_region, - int width, int height) { - pixman_box32_t *src_rects, *dest_rects; - int nrects, i; - - src_rects = pixman_region32_rectangles(surface_region, &nrects); - dest_rects = malloc(nrects * sizeof(*dest_rects)); - if (!dest_rects) { + pixman_region32_t *buffer_region, int width, int height) { + int nrects; + pixman_box32_t *src_rects = + pixman_region32_rectangles(surface_region, &nrects); + pixman_box32_t *dest_rects = malloc(nrects * sizeof(*dest_rects)); + if (dest_rects == NULL) { return; } - for (i = 0; i < nrects; i++) { + for (int i = 0; i < nrects; i++) { switch (transform) { default: case WL_OUTPUT_TRANSFORM_NORMAL: @@ -236,7 +251,7 @@ static void wlr_surface_to_buffer_region(int scale, } if (scale != 1) { - for (i = 0; i < nrects; i++) { + for (int i = 0; i < nrects; i++) { dest_rects[i].x1 *= scale; dest_rects[i].x2 *= scale; dest_rects[i].y1 *= scale; @@ -252,8 +267,8 @@ static void wlr_surface_to_buffer_region(int scale, /** * Append pending state to current state and clear pending state. */ -static void wlr_surface_move_state(struct wlr_surface *surface, struct wlr_surface_state *next, - struct wlr_surface_state *state) { +static void wlr_surface_move_state(struct wlr_surface *surface, + struct wlr_surface_state *next, struct wlr_surface_state *state) { bool update_damage = false; bool update_size = false; @@ -274,24 +289,22 @@ static void wlr_surface_move_state(struct wlr_surface *surface, struct wlr_surfa update_size = true; } if (update_size) { - wlr_surface_update_size(surface, state); + update_damage = wlr_surface_update_size(surface, state); } if ((next->invalid & WLR_SURFACE_INVALID_SURFACE_DAMAGE)) { - pixman_region32_union(&state->surface_damage, - &state->surface_damage, + pixman_region32_intersect_rect(&next->surface_damage, + &next->surface_damage, 0, 0, state->width, state->height); + pixman_region32_union(&state->surface_damage, &state->surface_damage, &next->surface_damage); - pixman_region32_intersect_rect(&state->surface_damage, - &state->surface_damage, 0, 0, state->width, - state->height); - pixman_region32_clear(&next->surface_damage); update_damage = true; } if ((next->invalid & WLR_SURFACE_INVALID_BUFFER_DAMAGE)) { - pixman_region32_union(&state->buffer_damage, - &state->buffer_damage, + pixman_region32_intersect_rect(&next->buffer_damage, + &next->buffer_damage, 0, 0, state->buffer_width, + state->buffer_height); + pixman_region32_union(&state->buffer_damage, &state->buffer_damage, &next->buffer_damage); - pixman_region32_clear(&next->buffer_damage); update_damage = true; } @@ -304,10 +317,6 @@ static void wlr_surface_move_state(struct wlr_surface *surface, struct wlr_surfa pixman_region32_union(&state->buffer_damage, &state->buffer_damage, &buffer_damage); pixman_region32_fini(&buffer_damage); - - pixman_region32_intersect_rect(&state->buffer_damage, - &state->buffer_damage, 0, 0, - state->buffer_width, state->buffer_height); } if ((next->invalid & WLR_SURFACE_INVALID_OPAQUE_REGION)) { // TODO: process buffer From bc001e90e988c965776abbd078224c14ac296047 Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 20 Jan 2018 01:04:35 +0100 Subject: [PATCH 26/75] rootston: fix artifacts when un-maximizing a view --- rootston/desktop.c | 4 ++++ rootston/wl_shell.c | 17 +++++++++-------- rootston/xdg_shell_v6.c | 17 +++++++++-------- rootston/xwayland.c | 18 +++++++++--------- 4 files changed, 31 insertions(+), 25 deletions(-) diff --git a/rootston/desktop.c b/rootston/desktop.c index faaefd05..e36ae6a4 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -298,6 +298,10 @@ void view_damage_whole(struct roots_view *view) { } void view_update_position(struct roots_view *view, double x, double y) { + if (view->x == x && view->y == y) { + return; + } + view_damage_whole(view); view->x = x; view->y = y; diff --git a/rootston/wl_shell.c b/rootston/wl_shell.c index 25ef9a3c..f7b09db0 100644 --- a/rootston/wl_shell.c +++ b/rootston/wl_shell.c @@ -88,22 +88,23 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) { struct roots_view *view = roots_surface->view; struct wlr_surface *wlr_surface = view->wlr_surface; + view_apply_damage(view); + int width = wlr_surface->current->width; int height = wlr_surface->current->height; + double x = view->x; + double y = view->y; if (view->pending_move_resize.update_x) { - double x = view->pending_move_resize.x + - view->pending_move_resize.width - width; - view_update_position(view, x, view->y); + x = view->pending_move_resize.x + view->pending_move_resize.width - + width; view->pending_move_resize.update_x = false; } if (view->pending_move_resize.update_y) { - double y = view->pending_move_resize.y + - view->pending_move_resize.height - height; - view_update_position(view, view->x, y); + y = view->pending_move_resize.y + view->pending_move_resize.height - + height; view->pending_move_resize.update_y = false; } - - view_apply_damage(view); + view_update_position(view, x, y); } static void handle_destroy(struct wl_listener *listener, void *data) { diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c index 225886ad..295be6a2 100644 --- a/rootston/xdg_shell_v6.c +++ b/rootston/xdg_shell_v6.c @@ -197,29 +197,30 @@ static void handle_commit(struct wl_listener *listener, void *data) { struct roots_view *view = roots_surface->view; struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6; + view_apply_damage(view); + uint32_t pending_serial = roots_surface->pending_move_resize_configure_serial; if (pending_serial > 0 && pending_serial >= surface->configure_serial) { struct wlr_box size; get_size(view, &size); + double x = view->x; + double y = view->y; if (view->pending_move_resize.update_x) { - double x = view->pending_move_resize.x + - view->pending_move_resize.width - size.width; - view_update_position(view, x, view->y); + x = view->pending_move_resize.x + view->pending_move_resize.width - + size.width; } if (view->pending_move_resize.update_y) { - double y = view->pending_move_resize.y + - view->pending_move_resize.height - size.height; - view_update_position(view, view->x, y); + y = view->pending_move_resize.y + view->pending_move_resize.height - + size.height; } + view_update_position(view, x, y); if (pending_serial == surface->configure_serial) { roots_surface->pending_move_resize_configure_serial = 0; } } - - view_apply_damage(view); } static void handle_destroy(struct wl_listener *listener, void *data) { diff --git a/rootston/xwayland.c b/rootston/xwayland.c index 856c3d70..81f91b4f 100644 --- a/rootston/xwayland.c +++ b/rootston/xwayland.c @@ -204,23 +204,23 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) { struct roots_view *view = roots_surface->view; struct wlr_surface *wlr_surface = view->wlr_surface; + view_apply_damage(view); + int width = wlr_surface->current->width; int height = wlr_surface->current->height; - + double x = view->x; + double y = view->y; if (view->pending_move_resize.update_x) { - double x = view->pending_move_resize.x + - view->pending_move_resize.width - width; - view_update_position(view, x, view->y); + x = view->pending_move_resize.x + view->pending_move_resize.width - + width; view->pending_move_resize.update_x = false; } if (view->pending_move_resize.update_y) { - double y = view->pending_move_resize.y + - view->pending_move_resize.height - height; - view_update_position(view, view->x, y); + y = view->pending_move_resize.y + view->pending_move_resize.height - + height; view->pending_move_resize.update_y = false; } - - view_apply_damage(view); + view_update_position(view, x, y); } static void handle_map_notify(struct wl_listener *listener, void *data) { From 4ca38b84ede12aed3c3b807521992b3580384f76 Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 20 Jan 2018 16:43:14 +0100 Subject: [PATCH 27/75] backend/drm: fix hardware cursors not moving This adds back `wlr_output::needs_swap`. This allows a backend to request buffer swaps even if the output isn't damaged. This is needed by the DRM backend to trigger pageflips when the cursor moves. --- backend/drm/drm.c | 12 ++++++++++-- include/rootston/output.h | 4 ++-- include/wlr/interfaces/wlr_output.h | 1 + include/wlr/types/wlr_output.h | 3 ++- rootston/output.c | 28 ++++++++++++++++++---------- types/wlr_output.c | 14 ++++++++++---- 6 files changed, 43 insertions(+), 19 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index e6bfee8c..72acbeab 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -619,7 +619,11 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, gbm_bo_unmap(bo, bo_data); - return drm->iface->crtc_set_cursor(drm, crtc, bo); + bool ok = drm->iface->crtc_set_cursor(drm, crtc, bo); + if (ok) { + wlr_output_update_needs_swap(output); + } + return ok; } static bool wlr_drm_connector_move_cursor(struct wlr_output *output, @@ -643,8 +647,12 @@ static bool wlr_drm_connector_move_cursor(struct wlr_output *output, transformed_box.y -= plane->cursor_hotspot_y; } - return drm->iface->crtc_move_cursor(drm, conn->crtc, transformed_box.x, + bool ok = drm->iface->crtc_move_cursor(drm, conn->crtc, transformed_box.x, transformed_box.y); + if (ok) { + wlr_output_update_needs_swap(output); + } + return ok; } static void wlr_drm_connector_destroy(struct wlr_output *output) { diff --git a/include/rootston/output.h b/include/rootston/output.h index a80e1f49..e8241de7 100644 --- a/include/rootston/output.h +++ b/include/rootston/output.h @@ -16,11 +16,11 @@ struct roots_output { struct timespec last_frame; pixman_region32_t damage, previous_damage; - bool frame_scheduled; + bool frame_pending; struct wl_listener frame; struct wl_listener mode; - struct wl_listener damage_listener; + struct wl_listener needs_swap; }; void output_add_notify(struct wl_listener *listener, void *data); diff --git a/include/wlr/interfaces/wlr_output.h b/include/wlr/interfaces/wlr_output.h index d5837def..56404ec7 100644 --- a/include/wlr/interfaces/wlr_output.h +++ b/include/wlr/interfaces/wlr_output.h @@ -32,5 +32,6 @@ void wlr_output_update_mode(struct wlr_output *output, void wlr_output_update_custom_mode(struct wlr_output *output, int32_t width, int32_t height, int32_t refresh); void wlr_output_update_enabled(struct wlr_output *output, bool enabled); +void wlr_output_update_needs_swap(struct wlr_output *output); #endif diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 1091ee62..33d27501 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -54,6 +54,7 @@ struct wlr_output { enum wl_output_subpixel subpixel; enum wl_output_transform transform; + bool needs_swap; pixman_region32_t damage, previous_damage; float transform_matrix[16]; @@ -64,8 +65,8 @@ struct wlr_output { int32_t refresh; // mHz struct { - struct wl_signal damage; struct wl_signal frame; + struct wl_signal needs_swap; struct wl_signal swap_buffers; struct wl_signal enable; struct wl_signal mode; diff --git a/rootston/output.c b/rootston/output.c index 407ba144..7f539347 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -258,6 +258,7 @@ static void render_output(struct roots_output *output) { struct roots_server *server = desktop->server; if (!wlr_output->enabled) { + output->frame_pending = false; return; } @@ -299,9 +300,9 @@ static void render_output(struct roots_output *output) { pixman_region32_intersect_rect(&damage, &damage, 0, 0, wlr_output->width, wlr_output->height); - // TODO: fullscreen - if (!pixman_region32_not_empty(&damage)) { - output->frame_scheduled = false; + if (!pixman_region32_not_empty(&damage) && !wlr_output->needs_swap) { + // Output doesn't need swap and isn't damaged, skip rendering completely + output->frame_pending = false; goto damage_finish; } @@ -311,6 +312,11 @@ static void render_output(struct roots_output *output) { wlr_renderer_begin(server->renderer, wlr_output); glEnable(GL_SCISSOR_TEST); + if (!pixman_region32_not_empty(&damage)) { + // Output isn't damaged but needs buffer swap + goto renderer_end; + } + int nrects; pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); for (int i = 0; i < nrects; ++i) { @@ -377,7 +383,7 @@ renderer_end: glDisable(GL_SCISSOR_TEST); wlr_renderer_end(server->renderer); wlr_output_swap_buffers(wlr_output, &now, &damage); - output->frame_scheduled = true; + output->frame_pending = true; pixman_region32_copy(&output->previous_damage, &output->damage); pixman_region32_clear(&output->damage); output->last_frame = desktop->last_frame = now; @@ -397,11 +403,11 @@ static void handle_idle_render(void *data) { } static void schedule_render(struct roots_output *output) { - if (!output->frame_scheduled) { + if (!output->frame_pending) { struct wl_event_loop *ev = wl_display_get_event_loop(output->desktop->server->wl_display); wl_event_loop_add_idle(ev, handle_idle_render, output); - output->frame_scheduled = true; + output->frame_pending = true; } } @@ -485,9 +491,9 @@ static void output_handle_mode(struct wl_listener *listener, void *data) { output_damage_whole(output); } -static void output_handle_damage(struct wl_listener *listener, void *data) { +static void output_handle_needs_swap(struct wl_listener *listener, void *data) { struct roots_output *output = - wl_container_of(listener, output, damage_listener); + wl_container_of(listener, output, needs_swap); pixman_region32_union(&output->damage, &output->damage, &output->wlr_output->damage); schedule_render(output); @@ -551,8 +557,8 @@ void output_add_notify(struct wl_listener *listener, void *data) { wl_signal_add(&wlr_output->events.frame, &output->frame); output->mode.notify = output_handle_mode; wl_signal_add(&wlr_output->events.mode, &output->mode); - output->damage_listener.notify = output_handle_damage; - wl_signal_add(&wlr_output->events.damage, &output->damage_listener); + output->needs_swap.notify = output_handle_needs_swap; + wl_signal_add(&wlr_output->events.needs_swap, &output->needs_swap); struct roots_output_config *output_config = roots_config_get_output(config, wlr_output); @@ -607,5 +613,7 @@ void output_remove_notify(struct wl_listener *listener, void *data) { pixman_region32_fini(&output->previous_damage); wl_list_remove(&output->link); wl_list_remove(&output->frame.link); + wl_list_remove(&output->mode.link); + wl_list_remove(&output->needs_swap.link); free(output); } diff --git a/types/wlr_output.c b/types/wlr_output.c index 55ee1cb3..4dd2ecc7 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -272,8 +272,8 @@ void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, output->scale = 1; wl_list_init(&output->cursors); wl_list_init(&output->wl_resources); - wl_signal_init(&output->events.damage); wl_signal_init(&output->events.frame); + wl_signal_init(&output->events.needs_swap); wl_signal_init(&output->events.swap_buffers); wl_signal_init(&output->events.enable); wl_signal_init(&output->events.mode); @@ -504,6 +504,7 @@ void wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when, // TODO: provide `damage` (not `render_damage`) to backend output->impl->swap_buffers(output); + output->needs_swap = false; pixman_region32_copy(&output->previous_damage, &output->damage); pixman_region32_clear(&output->damage); @@ -526,10 +527,15 @@ uint32_t wlr_output_get_gamma_size(struct wlr_output *output) { return output->impl->get_gamma_size(output); } +void wlr_output_update_needs_swap(struct wlr_output *output) { + output->needs_swap = true; + wl_signal_emit(&output->events.needs_swap, output); +} + static void output_damage_whole(struct wlr_output *output) { pixman_region32_union_rect(&output->damage, &output->damage, 0, 0, output->width, output->height); - wl_signal_emit(&output->events.damage, output); + wlr_output_update_needs_swap(output); } static void output_fullscreen_surface_reset(struct wlr_output *output) { @@ -557,7 +563,7 @@ static void output_fullscreen_surface_handle_commit( pixman_region32_union(&output->damage, &output->damage, &damage); pixman_region32_fini(&damage); - wl_signal_emit(&output->events.damage, output); + wlr_output_update_needs_swap(output); } static void output_fullscreen_surface_handle_destroy( @@ -599,7 +605,7 @@ static void output_cursor_damage_whole(struct wlr_output_cursor *cursor) { output_cursor_get_box(cursor, &box); pixman_region32_union_rect(&cursor->output->damage, &cursor->output->damage, box.x, box.y, box.width, box.height); - wl_signal_emit(&cursor->output->events.damage, cursor->output); + wlr_output_update_needs_swap(cursor->output); } static void output_cursor_reset(struct wlr_output_cursor *cursor) { From 78c13ead163e76b1c0ff344eefeadcaeffb3890e Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 20 Jan 2018 18:10:11 +0100 Subject: [PATCH 28/75] backend/x11: force rendering the whole output --- backend/x11/backend.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/backend/x11/backend.c b/backend/x11/backend.c index e1622d06..a2547f8d 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -395,6 +395,12 @@ static void output_swap_buffers(struct wlr_output *wlr_output) { if (!eglSwapBuffers(x11->egl.display, output->surf)) { wlr_log(L_ERROR, "eglSwapBuffers failed: %s", egl_error()); } + + // Damage the whole output + // TODO: use the buffer age extension + pixman_region32_union_rect(&wlr_output->damage, &wlr_output->damage, + 0, 0, wlr_output->width, wlr_output->height); + wlr_output_update_needs_swap(wlr_output); } static struct wlr_output_impl output_impl = { From 0365b587f03411d6a55017e111a991d466decc35 Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 21 Jan 2018 00:06:35 +0100 Subject: [PATCH 29/75] output: add damage tracking via buffer age --- backend/drm/drm.c | 13 +++++--- backend/drm/renderer.c | 17 ++++++---- backend/headless/output.c | 13 +++----- backend/wayland/output.c | 23 +++++++------ backend/x11/backend.c | 15 +++------ examples/multi-pointer.c | 2 +- examples/output-layout.c | 2 +- examples/pointer.c | 2 +- examples/rotation.c | 2 +- examples/simple.c | 2 +- examples/tablet.c | 2 +- examples/touch.c | 2 +- include/backend/drm/renderer.h | 2 +- include/rootston/output.h | 7 +++- include/wlr/interfaces/wlr_output.h | 4 +-- include/wlr/render/egl.h | 14 ++++++-- include/wlr/types/wlr_output.h | 14 ++++++-- render/egl.c | 50 ++++++++++++++++++++++++----- rootston/output.c | 35 ++++++++++++++++---- types/wlr_output.c | 22 +++++++------ types/wlr_screenshooter.c | 1 - 21 files changed, 163 insertions(+), 81 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 72acbeab..72fc1441 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -183,12 +183,13 @@ void wlr_drm_resources_free(struct wlr_drm_backend *drm) { free(drm->planes); } -static void wlr_drm_connector_make_current(struct wlr_output *output) { +static bool wlr_drm_connector_make_current(struct wlr_output *output, + int *buffer_age) { struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; - wlr_drm_surface_make_current(&conn->crtc->primary->surf); + return wlr_drm_surface_make_current(&conn->crtc->primary->surf, buffer_age); } -static void wlr_drm_connector_swap_buffers(struct wlr_output *output) { +static bool wlr_drm_connector_swap_buffers(struct wlr_output *output) { struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; struct wlr_drm_backend *drm = (struct wlr_drm_backend *)output->backend; @@ -203,7 +204,7 @@ static void wlr_drm_connector_swap_buffers(struct wlr_output *output) { if (conn->pageflip_pending) { wlr_log(L_ERROR, "Skipping pageflip"); - return; + return true; } if (drm->iface->crtc_pageflip(drm, conn, crtc, fb_id, NULL)) { @@ -212,6 +213,8 @@ static void wlr_drm_connector_swap_buffers(struct wlr_output *output) { wl_event_source_timer_update(conn->retry_pageflip, 1000000.0f / conn->output.current_mode->refresh); } + + return true; } static void wlr_drm_connector_set_gamma(struct wlr_output *output, @@ -595,7 +598,7 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, return false; } - wlr_drm_surface_make_current(&plane->surf); + wlr_drm_surface_make_current(&plane->surf, NULL); wlr_texture_upload_pixels(plane->wlr_tex, WL_SHM_FORMAT_ARGB8888, stride, width, height, buf); diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 00182c59..e2891057 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -113,9 +113,9 @@ void wlr_drm_surface_finish(struct wlr_drm_surface *surf) { memset(surf, 0, sizeof(*surf)); } -void wlr_drm_surface_make_current(struct wlr_drm_surface *surf) { - eglMakeCurrent(surf->renderer->egl.display, surf->egl, surf->egl, - surf->renderer->egl.context); +bool wlr_drm_surface_make_current(struct wlr_drm_surface *surf, + int *buffer_damage) { + return wlr_egl_make_current(&surf->renderer->egl, surf->egl, buffer_damage); } struct gbm_bo *wlr_drm_surface_swap_buffers(struct wlr_drm_surface *surf) { @@ -123,7 +123,9 @@ struct gbm_bo *wlr_drm_surface_swap_buffers(struct wlr_drm_surface *surf) { gbm_surface_release_buffer(surf->gbm, surf->front); } - eglSwapBuffers(surf->renderer->egl.display, surf->egl); + if (!eglSwapBuffers(surf->renderer->egl.display, surf->egl)) { + wlr_log(L_ERROR, "eglSwapBuffers failed"); + } surf->front = surf->back; surf->back = gbm_surface_lock_front_buffer(surf->gbm); @@ -135,7 +137,7 @@ struct gbm_bo *wlr_drm_surface_get_front(struct wlr_drm_surface *surf) { return surf->front; } - wlr_drm_surface_make_current(surf); + wlr_drm_surface_make_current(surf, NULL); glViewport(0, 0, surf->width, surf->height); glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); @@ -207,8 +209,9 @@ static struct wlr_texture *get_tex_for_bo(struct wlr_drm_renderer *renderer, str return tex->tex; } -struct gbm_bo *wlr_drm_surface_mgpu_copy(struct wlr_drm_surface *dest, struct gbm_bo *src) { - wlr_drm_surface_make_current(dest); +struct gbm_bo *wlr_drm_surface_mgpu_copy(struct wlr_drm_surface *dest, + struct gbm_bo *src) { + wlr_drm_surface_make_current(dest, NULL); struct wlr_texture *tex = get_tex_for_bo(dest->renderer, src); diff --git a/backend/headless/output.c b/backend/headless/output.c index 9fc92e88..a9a538ed 100644 --- a/backend/headless/output.c +++ b/backend/headless/output.c @@ -48,18 +48,15 @@ static void output_transform(struct wlr_output *wlr_output, output->wlr_output.transform = transform; } -static void output_make_current(struct wlr_output *wlr_output) { +static bool output_make_current(struct wlr_output *wlr_output, int *buffer_age) { struct wlr_headless_output *output = (struct wlr_headless_output *)wlr_output; - if (!eglMakeCurrent(output->backend->egl.display, - output->egl_surface, output->egl_surface, - output->backend->egl.context)) { - wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error()); - } + return wlr_egl_make_current(&output->backend->egl, output->egl_surface, + buffer_age); } -static void output_swap_buffers(struct wlr_output *wlr_output) { - // No-op +static bool output_swap_buffers(struct wlr_output *wlr_output) { + return true; // No-op } static void output_destroy(struct wlr_output *wlr_output) { diff --git a/backend/wayland/output.c b/backend/wayland/output.c index 7e299ecc..5de18d41 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -38,22 +38,27 @@ static bool wlr_wl_output_set_custom_mode(struct wlr_output *_output, return true; } -static void wlr_wl_output_make_current(struct wlr_output *_output) { - struct wlr_wl_backend_output *output = (struct wlr_wl_backend_output *)_output; - if (!eglMakeCurrent(output->backend->egl.display, - output->egl_surface, output->egl_surface, - output->backend->egl.context)) { - wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error()); - } +static bool wlr_wl_output_make_current(struct wlr_output *wlr_output, + int *buffer_age) { + struct wlr_wl_backend_output *output = + (struct wlr_wl_backend_output *)wlr_output; + return wlr_egl_make_current(&output->backend->egl, output->egl_surface, + buffer_age); } -static void wlr_wl_output_swap_buffers(struct wlr_output *_output) { - struct wlr_wl_backend_output *output = (struct wlr_wl_backend_output *)_output; +static bool wlr_wl_output_swap_buffers(struct wlr_output *wlr_output) { + struct wlr_wl_backend_output *output = + (struct wlr_wl_backend_output *)wlr_output; + output->frame_callback = wl_surface_frame(output->surface); wl_callback_add_listener(output->frame_callback, &frame_listener, output); + if (!eglSwapBuffers(output->backend->egl.display, output->egl_surface)) { wlr_log(L_ERROR, "eglSwapBuffers failed: %s", egl_error()); + return false; } + + return true; } static void wlr_wl_output_transform(struct wlr_output *_output, diff --git a/backend/x11/backend.c b/backend/x11/backend.c index a2547f8d..b9ea7d0f 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -379,28 +379,23 @@ static void output_destroy(struct wlr_output *wlr_output) { // output has been allocated on the stack, do not free it } -static void output_make_current(struct wlr_output *wlr_output) { +static bool output_make_current(struct wlr_output *wlr_output, int *buffer_age) { struct wlr_x11_output *output = (struct wlr_x11_output *)wlr_output; struct wlr_x11_backend *x11 = output->x11; - if (!eglMakeCurrent(x11->egl.display, output->surf, output->surf, x11->egl.context)) { - wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error()); - } + return wlr_egl_make_current(&x11->egl, output->surf, buffer_age); } -static void output_swap_buffers(struct wlr_output *wlr_output) { +static bool output_swap_buffers(struct wlr_output *wlr_output) { struct wlr_x11_output *output = (struct wlr_x11_output *)wlr_output; struct wlr_x11_backend *x11 = output->x11; if (!eglSwapBuffers(x11->egl.display, output->surf)) { wlr_log(L_ERROR, "eglSwapBuffers failed: %s", egl_error()); + return false; } - // Damage the whole output - // TODO: use the buffer age extension - pixman_region32_union_rect(&wlr_output->damage, &wlr_output->damage, - 0, 0, wlr_output->width, wlr_output->height); - wlr_output_update_needs_swap(wlr_output); + return true; } static struct wlr_output_impl output_impl = { diff --git a/examples/multi-pointer.c b/examples/multi-pointer.c index d5297aef..d3d425f2 100644 --- a/examples/multi-pointer.c +++ b/examples/multi-pointer.c @@ -56,7 +56,7 @@ static void handle_output_frame(struct output_state *output, struct sample_state *sample = state->data; struct wlr_output *wlr_output = output->output; - wlr_output_make_current(wlr_output); + wlr_output_make_current(wlr_output, NULL); glClearColor(sample->clear_color[0], sample->clear_color[1], sample->clear_color[2], sample->clear_color[3]); diff --git a/examples/output-layout.c b/examples/output-layout.c index 825e97d1..b97d3723 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -100,7 +100,7 @@ static void handle_output_frame(struct output_state *output, struct sample_state *sample = state->data; struct wlr_output *wlr_output = output->output; - wlr_output_make_current(wlr_output); + wlr_output_make_current(wlr_output, NULL); wlr_renderer_begin(sample->renderer, wlr_output); animate_cat(sample, output->output); diff --git a/examples/pointer.c b/examples/pointer.c index 8b0993e5..0dbd02d2 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -85,7 +85,7 @@ static void handle_output_frame(struct output_state *output, struct sample_state *sample = state->data; struct wlr_output *wlr_output = output->output; - wlr_output_make_current(wlr_output); + wlr_output_make_current(wlr_output, NULL); glClearColor(sample->clear_color[0], sample->clear_color[1], sample->clear_color[2], sample->clear_color[3]); diff --git a/examples/rotation.c b/examples/rotation.c index 6fa06dcc..65e436f6 100644 --- a/examples/rotation.c +++ b/examples/rotation.c @@ -42,7 +42,7 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts int32_t width, height; wlr_output_effective_resolution(wlr_output, &width, &height); - wlr_output_make_current(wlr_output); + wlr_output_make_current(wlr_output, NULL); wlr_renderer_begin(sample->renderer, wlr_output); float matrix[16]; diff --git a/examples/simple.c b/examples/simple.c index f788618d..90808b0f 100644 --- a/examples/simple.c +++ b/examples/simple.c @@ -35,7 +35,7 @@ void handle_output_frame(struct output_state *output, struct timespec *ts) { sample->dec = inc; } - wlr_output_make_current(output->output); + wlr_output_make_current(output->output, NULL); glClearColor(sample->color[0], sample->color[1], sample->color[2], 1.0); glClear(GL_COLOR_BUFFER_BIT); diff --git a/examples/tablet.c b/examples/tablet.c index 5498c9ff..35326664 100644 --- a/examples/tablet.c +++ b/examples/tablet.c @@ -42,7 +42,7 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts int32_t width, height; wlr_output_effective_resolution(wlr_output, &width, &height); - wlr_output_make_current(wlr_output); + wlr_output_make_current(wlr_output, NULL); wlr_renderer_begin(sample->renderer, wlr_output); float matrix[16], view[16]; diff --git a/examples/touch.c b/examples/touch.c index 5c778743..74642b96 100644 --- a/examples/touch.c +++ b/examples/touch.c @@ -41,7 +41,7 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts int32_t width, height; wlr_output_effective_resolution(wlr_output, &width, &height); - wlr_output_make_current(wlr_output); + wlr_output_make_current(wlr_output, NULL); wlr_renderer_begin(sample->renderer, wlr_output); float matrix[16]; diff --git a/include/backend/drm/renderer.h b/include/backend/drm/renderer.h index 45127cd0..a3f19fc3 100644 --- a/include/backend/drm/renderer.h +++ b/include/backend/drm/renderer.h @@ -45,7 +45,7 @@ bool wlr_drm_plane_surfaces_init(struct wlr_drm_plane *plane, struct wlr_drm_bac int32_t width, uint32_t height, uint32_t format); void wlr_drm_surface_finish(struct wlr_drm_surface *surf); -void wlr_drm_surface_make_current(struct wlr_drm_surface *surf); +bool wlr_drm_surface_make_current(struct wlr_drm_surface *surf, int *buffer_age); struct gbm_bo *wlr_drm_surface_swap_buffers(struct wlr_drm_surface *surf); struct gbm_bo *wlr_drm_surface_get_front(struct wlr_drm_surface *surf); void wlr_drm_surface_post(struct wlr_drm_surface *surf); diff --git a/include/rootston/output.h b/include/rootston/output.h index e8241de7..c0022d1a 100644 --- a/include/rootston/output.h +++ b/include/rootston/output.h @@ -5,6 +5,8 @@ #include #include +#define ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN 2 + struct roots_desktop; struct roots_output { @@ -15,9 +17,12 @@ struct roots_output { struct roots_view *fullscreen_view; struct timespec last_frame; - pixman_region32_t damage, previous_damage; + pixman_region32_t damage; bool frame_pending; + pixman_region32_t previous_damage[ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN]; + size_t previous_damage_idx; + struct wl_listener frame; struct wl_listener mode; struct wl_listener needs_swap; diff --git a/include/wlr/interfaces/wlr_output.h b/include/wlr/interfaces/wlr_output.h index 56404ec7..f2b65066 100644 --- a/include/wlr/interfaces/wlr_output.h +++ b/include/wlr/interfaces/wlr_output.h @@ -18,8 +18,8 @@ struct wlr_output_impl { int32_t hotspot_x, int32_t hotspot_y, bool update_pixels); bool (*move_cursor)(struct wlr_output *output, int x, int y); void (*destroy)(struct wlr_output *output); - void (*make_current)(struct wlr_output *output); - void (*swap_buffers)(struct wlr_output *output); + bool (*make_current)(struct wlr_output *output, int *buffer_age); + bool (*swap_buffers)(struct wlr_output *output); void (*set_gamma)(struct wlr_output *output, uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b); uint32_t (*get_gamma_size)(struct wlr_output *output); diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index bdb8d286..c292a6f8 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -11,8 +11,12 @@ struct wlr_egl { EGLConfig config; EGLContext context; - const char *egl_exts; - const char *gl_exts; + const char *egl_exts_str; + const char *gl_exts_str; + + struct { + bool buffer_age; + } egl_exts; struct wl_display *wl_display; }; @@ -65,4 +69,10 @@ bool wlr_egl_destroy_image(struct wlr_egl *egl, EGLImageKHR image); */ const char *egl_error(void); +bool wlr_egl_make_current(struct wlr_egl *egl, EGLSurface surface, + int *buffer_age); + +// TODO: remove +int wlr_egl_get_buffer_age(struct wlr_egl *egl, EGLSurface surface); + #endif diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 33d27501..3267a608 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -33,6 +33,8 @@ struct wlr_output_cursor { struct wl_listener surface_destroy; }; +#define WLR_OUTPUT_PREVIOUS_DAMAGE_COUNT 2 + struct wlr_output_impl; struct wlr_output { @@ -55,7 +57,7 @@ struct wlr_output { enum wl_output_transform transform; bool needs_swap; - pixman_region32_t damage, previous_damage; + pixman_region32_t damage; float transform_matrix[16]; // Note: some backends may have zero modes @@ -104,13 +106,19 @@ void wlr_output_set_scale(struct wlr_output *output, float scale); void wlr_output_destroy(struct wlr_output *output); void wlr_output_effective_resolution(struct wlr_output *output, int *width, int *height); -void wlr_output_make_current(struct wlr_output *output); +/** + * Makes the output GL context current. + * + * `buffer_age` is set to the drawing buffer age in number of frames or -1 if + * unknown. + */ +bool wlr_output_make_current(struct wlr_output *output, int *buffer_age); /** * Swaps the output buffers. If the time of the frame isn't known, set `when` to * NULL. If the compositor doesn't support damage tracking, set `damage` to * NULL. */ -void wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when, +bool wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when, pixman_region32_t *damage); void wlr_output_set_gamma(struct wlr_output *output, uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b); diff --git a/render/egl.c b/render/egl.c index fe20973c..9ac0b307 100644 --- a/render/egl.c +++ b/render/egl.c @@ -127,18 +127,23 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, } eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, egl->context); - egl->egl_exts = eglQueryString(egl->display, EGL_EXTENSIONS); - if (strstr(egl->egl_exts, "EGL_WL_bind_wayland_display") == NULL || - strstr(egl->egl_exts, "EGL_KHR_image_base") == NULL) { + egl->egl_exts_str = eglQueryString(egl->display, EGL_EXTENSIONS); + egl->gl_exts_str = (const char*) glGetString(GL_EXTENSIONS); + + wlr_log(L_INFO, "Using EGL %d.%d", (int)major, (int)minor); + wlr_log(L_INFO, "Supported EGL extensions: %s", egl->egl_exts_str); + wlr_log(L_INFO, "Using %s", glGetString(GL_VERSION)); + wlr_log(L_INFO, "Supported OpenGL ES extensions: %s", egl->gl_exts_str); + + if (strstr(egl->egl_exts_str, "EGL_WL_bind_wayland_display") == NULL || + strstr(egl->egl_exts_str, "EGL_KHR_image_base") == NULL) { wlr_log(L_ERROR, "Required egl extensions not supported"); goto error; } - egl->gl_exts = (const char*) glGetString(GL_EXTENSIONS); - wlr_log(L_INFO, "Using EGL %d.%d", (int)major, (int)minor); - wlr_log(L_INFO, "Supported EGL extensions: %s", egl->egl_exts); - wlr_log(L_INFO, "Using %s", glGetString(GL_VERSION)); - wlr_log(L_INFO, "Supported OpenGL ES extensions: %s", egl->gl_exts); + egl->egl_exts.buffer_age = + strstr(egl->egl_exts_str, "EGL_EXT_buffer_age") != NULL; + return true; error: @@ -208,3 +213,32 @@ EGLSurface wlr_egl_create_surface(struct wlr_egl *egl, void *window) { } return surf; } + +int wlr_egl_get_buffer_age(struct wlr_egl *egl, EGLSurface surface) { + if (!egl->egl_exts.buffer_age) { + return -1; + } + + EGLint buffer_age; + EGLBoolean ok = eglQuerySurface(egl->display, surface, + EGL_BUFFER_AGE_EXT, &buffer_age); + if (!ok) { + wlr_log(L_ERROR, "Failed to get EGL surface buffer age: %s", egl_error()); + return -1; + } + + return buffer_age; +} + +bool wlr_egl_make_current(struct wlr_egl *egl, EGLSurface surface, + int *buffer_age) { + if (!eglMakeCurrent(egl->display, surface, surface, egl->context)) { + wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error()); + return false; + } + + if (buffer_age != NULL) { + *buffer_age = wlr_egl_get_buffer_age(egl, surface); + } + return true; +} diff --git a/rootston/output.c b/rootston/output.c index 7f539347..13e78082 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -294,11 +294,26 @@ static void render_output(struct roots_output *output) { wlr_output_set_fullscreen_surface(wlr_output, NULL); } + int buffer_age = -1; + wlr_output_make_current(wlr_output, &buffer_age); + pixman_region32_t damage; pixman_region32_init(&damage); - pixman_region32_union(&damage, &output->damage, &output->previous_damage); - pixman_region32_intersect_rect(&damage, &damage, 0, 0, wlr_output->width, - wlr_output->height); + if (buffer_age <= 0 || buffer_age - 1 > ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN) { + // Buffer new or too old, damage the whole output + pixman_region32_union_rect(&damage, &damage, 0, 0, + wlr_output->width, wlr_output->height); + } else { + pixman_region32_copy(&damage, &output->damage); + + size_t idx = output->previous_damage_idx; + for (int i = 0; i < buffer_age - 1; i++) { + int j = (idx + i) % ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN; + pixman_region32_union(&damage, &damage, &output->previous_damage[j]); + } + } + pixman_region32_intersect_rect(&damage, &damage, 0, 0, + wlr_output->width, wlr_output->height); if (!pixman_region32_not_empty(&damage) && !wlr_output->needs_swap) { // Output doesn't need swap and isn't damaged, skip rendering completely @@ -308,7 +323,6 @@ static void render_output(struct roots_output *output) { wlr_log(L_DEBUG, "render"); - wlr_output_make_current(wlr_output); wlr_renderer_begin(server->renderer, wlr_output); glEnable(GL_SCISSOR_TEST); @@ -384,7 +398,10 @@ renderer_end: wlr_renderer_end(server->renderer); wlr_output_swap_buffers(wlr_output, &now, &damage); output->frame_pending = true; - pixman_region32_copy(&output->previous_damage, &output->damage); + output->previous_damage_idx += ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN - 1; + output->previous_damage_idx %= ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN; + pixman_region32_copy(&output->previous_damage[output->previous_damage_idx], + &output->damage); pixman_region32_clear(&output->damage); output->last_frame = desktop->last_frame = now; @@ -551,7 +568,9 @@ void output_add_notify(struct wl_listener *listener, void *data) { output->wlr_output = wlr_output; wl_list_insert(&desktop->outputs, &output->link); pixman_region32_init(&output->damage); - pixman_region32_init(&output->previous_damage); + for (size_t i = 0; i < ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN; ++i) { + pixman_region32_init(&output->previous_damage[i]); + } output->frame.notify = output_handle_frame; wl_signal_add(&wlr_output->events.frame, &output->frame); @@ -610,7 +629,9 @@ void output_remove_notify(struct wl_listener *listener, void *data) { // sample->compositor); pixman_region32_fini(&output->damage); - pixman_region32_fini(&output->previous_damage); + for (size_t i = 0; i < ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN; ++i) { + pixman_region32_fini(&output->previous_damage[i]); + } wl_list_remove(&output->link); wl_list_remove(&output->frame.link); wl_list_remove(&output->mode.link); diff --git a/types/wlr_output.c b/types/wlr_output.c index 4dd2ecc7..83b4166d 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -281,7 +281,6 @@ void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, wl_signal_init(&output->events.transform); wl_signal_init(&output->events.destroy); pixman_region32_init(&output->damage); - pixman_region32_init(&output->previous_damage); output->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &output->display_destroy); @@ -310,7 +309,6 @@ void wlr_output_destroy(struct wlr_output *output) { } pixman_region32_fini(&output->damage); - pixman_region32_fini(&output->previous_damage); if (output->impl && output->impl->destroy) { output->impl->destroy(output); @@ -332,8 +330,8 @@ void wlr_output_effective_resolution(struct wlr_output *output, *height /= output->scale; } -void wlr_output_make_current(struct wlr_output *output) { - output->impl->make_current(output); +bool wlr_output_make_current(struct wlr_output *output, int *buffer_age) { + return output->impl->make_current(output, buffer_age); } static void output_fullscreen_surface_get_box(struct wlr_output *output, @@ -466,17 +464,17 @@ surface_damage_finish: pixman_region32_fini(&surface_damage); } -void wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when, +bool wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when, pixman_region32_t *damage) { wl_signal_emit(&output->events.swap_buffers, damage); pixman_region32_t *render_damage = damage; if (damage == NULL) { + // Damage tracking not supported, repaint the whole output pixman_region32_t output_damage; pixman_region32_init(&output_damage); - pixman_region32_copy(&output_damage, &output->damage); - pixman_region32_union(&output_damage, &output_damage, - &output->previous_damage); + pixman_region32_union_rect(&output_damage, &output_damage, + 0, 0, output->width, output->height); render_damage = &output_damage; } @@ -503,14 +501,18 @@ void wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when, } // TODO: provide `damage` (not `render_damage`) to backend - output->impl->swap_buffers(output); + if (!output->impl->swap_buffers(output)) { + return false; + } + output->needs_swap = false; - pixman_region32_copy(&output->previous_damage, &output->damage); pixman_region32_clear(&output->damage); if (damage == NULL) { pixman_region32_fini(render_damage); } + + return true; } void wlr_output_set_gamma(struct wlr_output *output, diff --git a/types/wlr_screenshooter.c b/types/wlr_screenshooter.c index 4d591c45..e24b85f1 100644 --- a/types/wlr_screenshooter.c +++ b/types/wlr_screenshooter.c @@ -47,7 +47,6 @@ static void output_frame_notify(struct wl_listener *listener, void *_data) { struct wlr_renderer *renderer = state->screenshot->screenshooter->renderer; struct wlr_output *output = state->screenshot->output; - wlr_output_make_current(output); wlr_renderer_read_pixels(renderer, 0, 0, output->width, output->height, state->pixels); From c6aab6f56ccbc41563ef12e5fa1ed47082dffec6 Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 21 Jan 2018 11:11:25 +0100 Subject: [PATCH 30/75] Add docs and comments --- include/rootston/output.h | 6 ++++++ include/wlr/types/wlr_output.h | 23 ++++++++++++----------- rootston/output.c | 19 ++++++++++++++----- 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/include/rootston/output.h b/include/rootston/output.h index c0022d1a..89fe1d82 100644 --- a/include/rootston/output.h +++ b/include/rootston/output.h @@ -5,6 +5,11 @@ #include #include +/** + * Damage tracking requires to keep track of previous frames' damage. To allow + * damage tracking to work with triple buffering, an history of two frames is + * required. + */ #define ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN 2 struct roots_desktop; @@ -20,6 +25,7 @@ struct roots_output { pixman_region32_t damage; bool frame_pending; + // circular queue for previous damage pixman_region32_t previous_damage[ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN]; size_t previous_damage_idx; diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 3267a608..91429123 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -33,8 +33,6 @@ struct wlr_output_cursor { struct wl_listener surface_destroy; }; -#define WLR_OUTPUT_PREVIOUS_DAMAGE_COUNT 2 - struct wlr_output_impl; struct wlr_output { @@ -51,21 +49,21 @@ struct wlr_output { char serial[16]; int32_t phys_width, phys_height; // mm + // Note: some backends may have zero modes + struct wl_list modes; + struct wlr_output_mode *current_mode; + int32_t width, height; + int32_t refresh; // mHz, may be zero + bool enabled; float scale; enum wl_output_subpixel subpixel; enum wl_output_transform transform; bool needs_swap; - pixman_region32_t damage; + pixman_region32_t damage; // damage for cursors and fullscreen surface float transform_matrix[16]; - // Note: some backends may have zero modes - struct wl_list modes; - struct wlr_output_mode *current_mode; - int32_t width, height; - int32_t refresh; // mHz - struct { struct wl_signal frame; struct wl_signal needs_swap; @@ -107,16 +105,18 @@ void wlr_output_destroy(struct wlr_output *output); void wlr_output_effective_resolution(struct wlr_output *output, int *width, int *height); /** - * Makes the output GL context current. + * Makes the output rendering context current. * * `buffer_age` is set to the drawing buffer age in number of frames or -1 if - * unknown. + * unknown. This is useful for damage tracking. */ bool wlr_output_make_current(struct wlr_output *output, int *buffer_age); /** * Swaps the output buffers. If the time of the frame isn't known, set `when` to * NULL. If the compositor doesn't support damage tracking, set `damage` to * NULL. + * + * Swapping buffers schedules a `frame` event. */ bool wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when, pixman_region32_t *damage); @@ -126,6 +126,7 @@ uint32_t wlr_output_get_gamma_size(struct wlr_output *output); void wlr_output_set_fullscreen_surface(struct wlr_output *output, struct wlr_surface *surface); + struct wlr_output_cursor *wlr_output_cursor_create(struct wlr_output *output); /** * Sets the cursor image. The image must be already scaled for the output. diff --git a/rootston/output.c b/rootston/output.c index 13e78082..f8da9c77 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -31,6 +31,10 @@ static void rotate_child_position(double *sx, double *sy, double sw, double sh, } } +/** + * Checks whether a surface at (lx, ly) intersects an output. Sets `box` to the + * surface box in the output, in output-local coordinates. + */ static bool surface_intersect_output(struct wlr_surface *surface, struct wlr_output_layout *output_layout, struct wlr_output *wlr_output, double lx, double ly, struct wlr_box *box) { @@ -138,10 +142,8 @@ render_subsurfaces:; struct wlr_surface_state *state = subsurface->surface->current; double sx = state->subsurface_position.x; double sy = state->subsurface_position.y; - double sw = state->buffer_width / state->scale; - double sh = state->buffer_height / state->scale; - rotate_child_position(&sx, &sy, sw, sh, surface->current->width, - surface->current->height, rotation); + rotate_child_position(&sx, &sy, state->width, state->height, + surface->current->width, surface->current->height, rotation); render_surface(subsurface->surface, output, when, damage, lx + sx, ly + sy, rotation); @@ -297,6 +299,7 @@ static void render_output(struct roots_output *output) { int buffer_age = -1; wlr_output_make_current(wlr_output, &buffer_age); + // Check if we can use damage tracking pixman_region32_t damage; pixman_region32_init(&damage); if (buffer_age <= 0 || buffer_age - 1 > ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN) { @@ -306,8 +309,9 @@ static void render_output(struct roots_output *output) { } else { pixman_region32_copy(&damage, &output->damage); + // Accumulate damage from old buffers size_t idx = output->previous_damage_idx; - for (int i = 0; i < buffer_age - 1; i++) { + for (int i = 0; i < buffer_age - 1; ++i) { int j = (idx + i) % ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN; pixman_region32_union(&damage, &damage, &output->previous_damage[j]); } @@ -362,11 +366,13 @@ static void render_output(struct roots_output *output) { goto renderer_end; } + // Render all views struct roots_view *view; wl_list_for_each_reverse(view, &desktop->views, link) { render_view(view, output, &now, &damage); } + // Render drag icons struct wlr_drag_icon *drag_icon = NULL; struct roots_seat *seat = NULL; wl_list_for_each(seat, &server->input->seats, link) { @@ -398,6 +404,7 @@ renderer_end: wlr_renderer_end(server->renderer); wlr_output_swap_buffers(wlr_output, &now, &damage); output->frame_pending = true; + // same as decrementing, but works on unsigned integers output->previous_damage_idx += ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN - 1; output->previous_damage_idx %= ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN; pixman_region32_copy(&output->previous_damage[output->previous_damage_idx], @@ -421,6 +428,7 @@ static void handle_idle_render(void *data) { static void schedule_render(struct roots_output *output) { if (!output->frame_pending) { + // TODO: ask the backend to send a frame event when appropriate instead struct wl_event_loop *ev = wl_display_get_event_loop(output->desktop->server->wl_display); wl_event_loop_add_idle(ev, handle_idle_render, output); @@ -480,6 +488,7 @@ static void output_damage_from_surface(struct roots_output *output, return; } + // TODO: output scale, output transform support pixman_region32_t damage; pixman_region32_init(&damage); pixman_region32_copy(&damage, &surface->current->surface_damage); From eeffe113372686f3b44fdb0c4e86cf8d00ba9c54 Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 21 Jan 2018 14:22:33 +0100 Subject: [PATCH 31/75] surface: add wlr_surface new_subsurface and wlr_subsurface destroy events --- include/wlr/types/wlr_compositor.h | 2 +- include/wlr/types/wlr_surface.h | 5 +++++ types/wlr_compositor.c | 4 ++-- types/wlr_surface.c | 13 +++++++------ xwayland/xwm.c | 2 +- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/include/wlr/types/wlr_compositor.h b/include/wlr/types/wlr_compositor.h index ceeb64ca..8481c590 100644 --- a/include/wlr/types/wlr_compositor.h +++ b/include/wlr/types/wlr_compositor.h @@ -13,7 +13,7 @@ struct wlr_compositor { struct wl_listener display_destroy; struct { - struct wl_signal create_surface; + struct wl_signal new_surface; } events; }; diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index 9f88d044..50316abc 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -56,6 +56,10 @@ struct wlr_subsurface { struct wl_list parent_pending_link; struct wl_listener parent_destroy_listener; + + struct { + struct wl_signal destroy; + } events; }; struct wlr_surface { @@ -70,6 +74,7 @@ struct wlr_surface { struct { struct wl_signal commit; + struct wl_signal new_subsurface; struct wl_signal destroy; } events; diff --git a/types/wlr_compositor.c b/types/wlr_compositor.c index cf8c3f8f..a4bd7a16 100644 --- a/types/wlr_compositor.c +++ b/types/wlr_compositor.c @@ -35,7 +35,7 @@ static void wl_compositor_create_surface(struct wl_client *client, wl_list_insert(&compositor->surfaces, wl_resource_get_link(surface_resource)); - wl_signal_emit(&compositor->events.create_surface, surface); + wl_signal_emit(&compositor->events.new_surface, surface); } static void wl_compositor_create_region(struct wl_client *client, @@ -185,7 +185,7 @@ struct wlr_compositor *wlr_compositor_create(struct wl_display *display, wl_list_init(&compositor->wl_resources); wl_list_init(&compositor->surfaces); - wl_signal_init(&compositor->events.create_surface); + wl_signal_init(&compositor->events.new_surface); compositor->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &compositor->display_destroy); diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 58413818..29cdd1a0 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -424,7 +424,7 @@ static void wlr_surface_commit_pending(struct wlr_surface *surface) { // commit subsurface order struct wlr_subsurface *subsurface; wl_list_for_each_reverse(subsurface, &surface->subsurface_pending_list, - parent_pending_link) { + parent_pending_link) { wl_list_remove(&subsurface->parent_link); wl_list_insert(&surface->subsurface_list, &subsurface->parent_link); @@ -468,7 +468,6 @@ static void wlr_subsurface_parent_commit(struct wlr_subsurface *subsurface, bool synchronized) { struct wlr_surface *surface = subsurface->surface; if (synchronized || subsurface->synchronized) { - if (subsurface->has_cache) { wlr_surface_move_state(surface, subsurface->cached, surface->pending); wlr_surface_commit_pending(surface); @@ -604,6 +603,8 @@ static void wlr_surface_state_destroy(struct wlr_surface_state *state) { } void wlr_subsurface_destroy(struct wlr_subsurface *subsurface) { + wl_signal_emit(&subsurface->events.destroy, subsurface); + wlr_surface_state_destroy(subsurface->cached); if (subsurface->parent) { @@ -651,6 +652,7 @@ struct wlr_surface *wlr_surface_create(struct wl_resource *res, wl_signal_init(&surface->events.commit); wl_signal_init(&surface->events.destroy); + wl_signal_init(&surface->events.new_subsurface); wl_list_init(&surface->subsurface_list); wl_list_init(&surface->subsurface_pending_list); wl_resource_set_implementation(res, &surface_interface, @@ -740,10 +742,6 @@ static void subsurface_place_above(struct wl_client *client, struct wl_resource *resource, struct wl_resource *sibling_resource) { struct wlr_subsurface *subsurface = wl_resource_get_user_data(resource); - if (!subsurface) { - return; - } - struct wlr_surface *sibling_surface = wl_resource_get_user_data(sibling_resource); struct wlr_subsurface *sibling = @@ -849,6 +847,7 @@ void wlr_surface_make_subsurface(struct wlr_surface *surface, } subsurface->synchronized = true; subsurface->surface = surface; + wl_signal_init(&subsurface->events.destroy); // link parent subsurface->parent = parent; @@ -874,6 +873,8 @@ void wlr_surface_make_subsurface(struct wlr_surface *surface, subsurface_resource_destroy); surface->subsurface = subsurface; + + wl_signal_emit(&parent->events.new_subsurface, subsurface); } diff --git a/xwayland/xwm.c b/xwayland/xwm.c index dc349ab2..3bbaecfb 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -1406,7 +1406,7 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *wlr_xwayland) { xwm_selection_init(xwm); xwm->compositor_surface_create.notify = handle_compositor_surface_create; - wl_signal_add(&wlr_xwayland->compositor->events.create_surface, + wl_signal_add(&wlr_xwayland->compositor->events.new_surface, &xwm->compositor_surface_create); xwm_create_wm_window(xwm); From a636d72fc77ebcaa986fd1b72e85664e2fe586a3 Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 21 Jan 2018 14:50:37 +0100 Subject: [PATCH 32/75] rootston: track subsurface damage --- include/rootston/desktop.h | 2 +- include/rootston/view.h | 27 ++++++++++++ rootston/desktop.c | 90 +++++++++++++++++++++++++++++++++++++- rootston/output.c | 38 +++++++++++++--- rootston/wl_shell.c | 3 +- rootston/xdg_shell_v6.c | 3 +- rootston/xwayland.c | 17 ++++--- 7 files changed, 162 insertions(+), 18 deletions(-) diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h index 812bb42a..388fb55d 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -64,7 +64,7 @@ struct roots_view *desktop_view_at(struct roots_desktop *desktop, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy); void view_init(struct roots_view *view, struct roots_desktop *desktop); -void view_destroy(struct roots_view *view); +void view_finish(struct roots_view *view); void view_activate(struct roots_view *view, bool activate); void view_apply_damage(struct roots_view *view); void view_damage_whole(struct roots_view *view); diff --git a/include/rootston/view.h b/include/rootston/view.h index 579b148a..6c5e0573 100644 --- a/include/rootston/view.h +++ b/include/rootston/view.h @@ -91,7 +91,11 @@ struct roots_view { struct roots_xwayland_surface *roots_xwayland_surface; #endif }; + struct wlr_surface *wlr_surface; + struct wl_list children; // roots_view_child::link + + struct wl_listener new_subsurface; struct { struct wl_signal destroy; @@ -112,6 +116,21 @@ struct roots_view { void (*close)(struct roots_view *view); }; +struct roots_view_child { + struct roots_view *view; + struct wlr_surface *wlr_surface; + struct wl_list link; + + struct wl_listener commit; + struct wl_listener new_subsurface; +}; + +struct roots_subsurface { + struct roots_view_child view_child; + struct wlr_subsurface *wlr_subsurface; + struct wl_listener destroy; +}; + void view_get_box(const struct roots_view *view, struct wlr_box *box); void view_activate(struct roots_view *view, bool active); void view_move(struct roots_view *view, double x, double y); @@ -126,4 +145,12 @@ bool view_center(struct roots_view *view); void view_setup(struct roots_view *view); void view_teardown(struct roots_view *view); +void view_child_init(struct roots_view_child *child, struct roots_view *view, + struct wlr_surface *wlr_surface); +void view_child_finish(struct roots_view_child *child); + +struct roots_subsurface *subsurface_create(struct roots_view *view, + struct wlr_subsurface *wlr_subsurface); +void subsurface_destroy(struct roots_subsurface *subsurface); + #endif diff --git a/rootston/desktop.c b/rootston/desktop.c index e36ae6a4..191338a8 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -254,20 +254,106 @@ bool view_center(struct roots_view *view) { return true; } -void view_destroy(struct roots_view *view) { +void view_child_finish(struct roots_view_child *child) { + if (child == NULL) { + return; + } + view_damage_whole(child->view); + wl_list_remove(&child->link); + wl_list_remove(&child->commit.link); + wl_list_remove(&child->new_subsurface.link); +} + +static void view_child_handle_commit(struct wl_listener *listener, + void *data) { + struct roots_view_child *child = wl_container_of(listener, child, commit); + view_apply_damage(child->view); +} + +static void view_child_handle_new_subsurface(struct wl_listener *listener, + void *data) { + struct roots_view_child *child = + wl_container_of(listener, child, new_subsurface); + struct wlr_subsurface *wlr_subsurface = data; + subsurface_create(child->view, wlr_subsurface); +} + +void view_child_init(struct roots_view_child *child, struct roots_view *view, + struct wlr_surface *wlr_surface) { + child->view = view; + child->wlr_surface = wlr_surface; + child->commit.notify = view_child_handle_commit; + wl_signal_add(&wlr_surface->events.commit, &child->commit); + child->new_subsurface.notify = view_child_handle_new_subsurface; + wl_signal_add(&wlr_surface->events.new_subsurface, &child->new_subsurface); + wl_list_insert(&view->children, &child->link); +} + +static void subsurface_handle_destroy(struct wl_listener *listener, + void *data) { + struct roots_subsurface *subsurface = + wl_container_of(listener, subsurface, destroy); + subsurface_destroy(subsurface); +} + +struct roots_subsurface *subsurface_create(struct roots_view *view, + struct wlr_subsurface *wlr_subsurface) { + struct roots_subsurface *subsurface = + calloc(1, sizeof(struct roots_subsurface)); + if (subsurface == NULL) { + return NULL; + } + subsurface->wlr_subsurface = wlr_subsurface; + view_child_init(&subsurface->view_child, view, wlr_subsurface->surface); + subsurface->destroy.notify = subsurface_handle_destroy; + wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy); + return subsurface; +} + +void subsurface_destroy(struct roots_subsurface *subsurface) { + if (subsurface == NULL) { + return; + } + wl_list_remove(&subsurface->destroy.link); + view_child_finish(&subsurface->view_child); + free(subsurface); +} + +void view_finish(struct roots_view *view) { view_damage_whole(view); wl_signal_emit(&view->events.destroy, view); + wl_list_remove(&view->new_subsurface.link); + if (view->fullscreen_output) { view->fullscreen_output->fullscreen_view = NULL; } +} - free(view); +static void view_handle_new_subsurface(struct wl_listener *listener, + void *data) { + struct roots_view *view = wl_container_of(listener, view, new_subsurface); + struct wlr_subsurface *wlr_subsurface = data; + subsurface_create(view, wlr_subsurface); } void view_init(struct roots_view *view, struct roots_desktop *desktop) { + assert(view->wlr_surface); + view->desktop = desktop; wl_signal_init(&view->events.destroy); + wl_list_init(&view->children); + + struct wlr_subsurface *subsurface; + wl_list_for_each(subsurface, &view->wlr_surface->subsurface_list, + parent_link) { + subsurface_create(view, subsurface); + } + + view->new_subsurface.notify = view_handle_new_subsurface; + wl_signal_add(&view->wlr_surface->events.new_subsurface, + &view->new_subsurface); + view_damage_whole(view); } diff --git a/rootston/output.c b/rootston/output.c index f8da9c77..1c966e08 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -444,7 +444,7 @@ static void output_damage_whole(struct roots_output *output) { } static void output_damage_whole_surface(struct roots_output *output, - struct wlr_surface *surface, double lx, double ly) { + struct wlr_surface *surface, double lx, double ly, float rotation) { if (!wlr_surface_has_buffer(surface)) { return; } @@ -460,6 +460,18 @@ static void output_damage_whole_surface(struct roots_output *output, box.x, box.y, box.width, box.height); schedule_render(output); + + struct wlr_subsurface *subsurface; + wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) { + struct wlr_surface_state *state = subsurface->surface->current; + double sx = state->subsurface_position.x; + double sy = state->subsurface_position.y; + rotate_child_position(&sx, &sy, state->width, state->height, + surface->current->width, surface->current->height, rotation); + + output_damage_whole_surface(output, subsurface->surface, + lx + sx, ly + sy, rotation); + } } void output_damage_whole_view(struct roots_output *output, @@ -469,14 +481,15 @@ void output_damage_whole_view(struct roots_output *output, } if (view->wlr_surface != NULL) { - output_damage_whole_surface(output, view->wlr_surface, view->x, view->y); + output_damage_whole_surface(output, view->wlr_surface, + view->x, view->y, view->rotation); } - // TODO: subsurfaces, popups, etc + // TODO: popups, etc } static void output_damage_from_surface(struct roots_output *output, - struct wlr_surface *surface, double lx, double ly) { + struct wlr_surface *surface, double lx, double ly, float rotation) { if (!wlr_surface_has_buffer(surface)) { return; } @@ -497,6 +510,18 @@ static void output_damage_from_surface(struct roots_output *output, pixman_region32_fini(&damage); schedule_render(output); + + struct wlr_subsurface *subsurface; + wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) { + struct wlr_surface_state *state = subsurface->surface->current; + double sx = state->subsurface_position.x; + double sy = state->subsurface_position.y; + rotate_child_position(&sx, &sy, state->width, state->height, + surface->current->width, surface->current->height, rotation); + + output_damage_from_surface(output, subsurface->surface, + lx + sx, ly + sy, rotation); + } } void output_damage_from_view(struct roots_output *output, @@ -506,10 +531,11 @@ void output_damage_from_view(struct roots_output *output, } if (view->wlr_surface != NULL) { - output_damage_from_surface(output, view->wlr_surface, view->x, view->y); + output_damage_from_surface(output, view->wlr_surface, + view->x, view->y, view->rotation); } - // TODO: subsurfaces, popups, etc + // TODO: popups, etc } static void output_handle_mode(struct wl_listener *listener, void *data) { diff --git a/rootston/wl_shell.c b/rootston/wl_shell.c index f7b09db0..be658f40 100644 --- a/rootston/wl_shell.c +++ b/rootston/wl_shell.c @@ -118,7 +118,8 @@ static void handle_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&roots_surface->set_state.link); wl_list_remove(&roots_surface->surface_commit.link); wl_list_remove(&roots_surface->view->link); - view_destroy(roots_surface->view); + view_finish(roots_surface->view); + free(roots_surface->view); free(roots_surface); } diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c index 295be6a2..7337fb1e 100644 --- a/rootston/xdg_shell_v6.c +++ b/rootston/xdg_shell_v6.c @@ -231,7 +231,8 @@ static void handle_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&roots_xdg_surface->request_move.link); wl_list_remove(&roots_xdg_surface->request_resize.link); wl_list_remove(&roots_xdg_surface->view->link); - view_destroy(roots_xdg_surface->view); + view_finish(roots_xdg_surface->view); + free(roots_xdg_surface->view); free(roots_xdg_surface); } diff --git a/rootston/xwayland.c b/rootston/xwayland.c index 81f91b4f..6f9912e6 100644 --- a/rootston/xwayland.c +++ b/rootston/xwayland.c @@ -121,7 +121,8 @@ static void handle_destroy(struct wl_listener *listener, void *data) { if (xwayland_surface->mapped) { wl_list_remove(&roots_surface->view->link); } - view_destroy(roots_surface->view); + view_finish(roots_surface->view); + free(roots_surface->view); free(roots_surface); } @@ -233,24 +234,26 @@ static void handle_map_notify(struct wl_listener *listener, void *data) { view->wlr_surface = xsurface->surface; view->x = xsurface->x; view->y = xsurface->y; + wl_list_insert(&desktop->views, &view->link); + view_damage_whole(view); roots_surface->surface_commit.notify = handle_surface_commit; wl_signal_add(&xsurface->surface->events.commit, &roots_surface->surface_commit); - - wl_list_insert(&desktop->views, &view->link); } static void handle_unmap_notify(struct wl_listener *listener, void *data) { struct roots_xwayland_surface *roots_surface = wl_container_of(listener, roots_surface, unmap_notify); + struct roots_view *view = roots_surface->view; - view_damage_whole(roots_surface->view); - - roots_surface->view->wlr_surface = NULL; wl_list_remove(&roots_surface->surface_commit.link); - wl_list_remove(&roots_surface->view->link); + + view_damage_whole(view); + + view->wlr_surface = NULL; + wl_list_remove(&view->link); } void handle_xwayland_surface(struct wl_listener *listener, void *data) { From d8b36357e4c8d9edef7df4ecb465b7f728795f90 Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 21 Jan 2018 15:13:10 +0100 Subject: [PATCH 33/75] rootston: add roots_view_child::destroy --- include/rootston/view.h | 3 ++- rootston/desktop.c | 29 +++++++++++++++++++---------- rootston/xwayland.c | 11 +++++++++++ 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/include/rootston/view.h b/include/rootston/view.h index 6c5e0573..d07f9ca2 100644 --- a/include/rootston/view.h +++ b/include/rootston/view.h @@ -123,6 +123,8 @@ struct roots_view_child { struct wl_listener commit; struct wl_listener new_subsurface; + + void (*destroy)(struct roots_view_child *child); }; struct roots_subsurface { @@ -151,6 +153,5 @@ void view_child_finish(struct roots_view_child *child); struct roots_subsurface *subsurface_create(struct roots_view *view, struct wlr_subsurface *wlr_subsurface); -void subsurface_destroy(struct roots_subsurface *subsurface); #endif diff --git a/rootston/desktop.c b/rootston/desktop.c index 191338a8..4bb1de5f 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -280,6 +280,7 @@ static void view_child_handle_new_subsurface(struct wl_listener *listener, void view_child_init(struct roots_view_child *child, struct roots_view *view, struct wlr_surface *wlr_surface) { + assert(child->destroy); child->view = view; child->wlr_surface = wlr_surface; child->commit.notify = view_child_handle_commit; @@ -289,11 +290,22 @@ void view_child_init(struct roots_view_child *child, struct roots_view *view, wl_list_insert(&view->children, &child->link); } +static void subsurface_destroy(struct roots_view_child *child) { + assert(child->destroy == subsurface_destroy); + struct roots_subsurface *subsurface = (struct roots_subsurface *)child; + if (subsurface == NULL) { + return; + } + wl_list_remove(&subsurface->destroy.link); + view_child_finish(&subsurface->view_child); + free(subsurface); +} + static void subsurface_handle_destroy(struct wl_listener *listener, void *data) { struct roots_subsurface *subsurface = wl_container_of(listener, subsurface, destroy); - subsurface_destroy(subsurface); + subsurface_destroy((struct roots_view_child *)subsurface); } struct roots_subsurface *subsurface_create(struct roots_view *view, @@ -304,27 +316,24 @@ struct roots_subsurface *subsurface_create(struct roots_view *view, return NULL; } subsurface->wlr_subsurface = wlr_subsurface; + subsurface->view_child.destroy = subsurface_destroy; view_child_init(&subsurface->view_child, view, wlr_subsurface->surface); subsurface->destroy.notify = subsurface_handle_destroy; wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy); return subsurface; } -void subsurface_destroy(struct roots_subsurface *subsurface) { - if (subsurface == NULL) { - return; - } - wl_list_remove(&subsurface->destroy.link); - view_child_finish(&subsurface->view_child); - free(subsurface); -} - void view_finish(struct roots_view *view) { view_damage_whole(view); wl_signal_emit(&view->events.destroy, view); wl_list_remove(&view->new_subsurface.link); + struct roots_view_child *child, *tmp; + wl_list_for_each_safe(child, tmp, &view->children, link) { + child->destroy(child); + } + if (view->fullscreen_output) { view->fullscreen_output->fullscreen_view = NULL; } diff --git a/rootston/xwayland.c b/rootston/xwayland.c index 6f9912e6..24315e1a 100644 --- a/rootston/xwayland.c +++ b/rootston/xwayland.c @@ -236,6 +236,12 @@ static void handle_map_notify(struct wl_listener *listener, void *data) { view->y = xsurface->y; wl_list_insert(&desktop->views, &view->link); + struct wlr_subsurface *subsurface; + wl_list_for_each(subsurface, &view->wlr_surface->subsurface_list, + parent_link) { + subsurface_create(view, subsurface); + } + view_damage_whole(view); roots_surface->surface_commit.notify = handle_surface_commit; @@ -252,6 +258,11 @@ static void handle_unmap_notify(struct wl_listener *listener, void *data) { view_damage_whole(view); + struct roots_view_child *child, *tmp; + wl_list_for_each_safe(child, tmp, &view->children, link) { + child->destroy(child); + } + view->wlr_surface = NULL; wl_list_remove(&view->link); } From 66ae4071a7985fbc6e5d41f50e34ce4474ab4fe4 Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 21 Jan 2018 21:06:37 +0100 Subject: [PATCH 34/75] rootston: damage tracking for xdg popups --- include/rootston/view.h | 11 +- include/wlr/types/wlr_xdg_shell_v6.h | 5 +- rootston/output.c | 297 +++++++++++++-------------- rootston/xdg_shell_v6.c | 69 ++++++- types/wlr_xdg_shell_v6.c | 22 +- 5 files changed, 235 insertions(+), 169 deletions(-) diff --git a/include/rootston/view.h b/include/rootston/view.h index d07f9ca2..8cfdf321 100644 --- a/include/rootston/view.h +++ b/include/rootston/view.h @@ -23,13 +23,15 @@ struct roots_wl_shell_surface { struct roots_xdg_surface_v6 { struct roots_view *view; - struct wl_listener commit; struct wl_listener destroy; + struct wl_listener new_popup; struct wl_listener request_move; struct wl_listener request_resize; struct wl_listener request_maximize; struct wl_listener request_fullscreen; + struct wl_listener surface_commit; + uint32_t pending_move_resize_configure_serial; }; @@ -133,6 +135,13 @@ struct roots_subsurface { struct wl_listener destroy; }; +struct roots_xdg_popup_v6 { + struct roots_view_child view_child; + struct wlr_xdg_popup_v6 *wlr_popup; + struct wl_listener destroy; + struct wl_listener new_popup; +}; + void view_get_box(const struct roots_view *view, struct wlr_box *box); void view_activate(struct roots_view *view, bool active); void view_move(struct roots_view *view, double x, double y); diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 280bea27..c7b1a24b 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -34,6 +34,7 @@ struct wlr_xdg_client_v6 { struct wlr_xdg_popup_v6 { struct wlr_xdg_surface_v6 *base; + struct wl_list link; struct wl_resource *resource; bool committed; @@ -104,8 +105,7 @@ struct wlr_xdg_surface_v6 { struct wlr_xdg_popup_v6 *popup_state; }; - struct wl_list popups; - struct wl_list popup_link; + struct wl_list popups; // wlr_xdg_popup_v6::link bool configured; bool added; @@ -126,6 +126,7 @@ struct wlr_xdg_surface_v6 { struct { struct wl_signal destroy; struct wl_signal ping_timeout; + struct wl_signal new_popup; struct wl_signal request_maximize; struct wl_signal request_fullscreen; diff --git a/rootston/output.c b/rootston/output.c index 1c966e08..d2ea2ade 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -13,6 +13,9 @@ #include "rootston/output.h" #include "rootston/config.h" +typedef void (*surface_iterator_func_t)(struct wlr_surface *surface, + double lx, double ly, float rotation, void *data); + /** * Rotate a child's position relative to a parent. The parent size is (pw, ph), * the child position is (*sx, *sy) and its size is (sw, sh). @@ -31,6 +34,119 @@ static void rotate_child_position(double *sx, double *sy, double sw, double sh, } } +static void surface_for_each_surface(struct wlr_surface *surface, double lx, + double ly, float rotation, surface_iterator_func_t iterator, + void *user_data) { + iterator(surface, lx, ly, rotation, user_data); + + struct wlr_subsurface *subsurface; + wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) { + struct wlr_surface_state *state = subsurface->surface->current; + double sx = state->subsurface_position.x; + double sy = state->subsurface_position.y; + rotate_child_position(&sx, &sy, state->width, state->height, + surface->current->width, surface->current->height, rotation); + + surface_for_each_surface(subsurface->surface, lx + sx, ly + sy, + rotation, iterator, user_data); + } +} + +static void xdg_surface_v6_for_each_surface(struct wlr_xdg_surface_v6 *surface, + double base_x, double base_y, float rotation, + surface_iterator_func_t iterator, void *user_data) { + double width = surface->surface->current->width; + double height = surface->surface->current->height; + + struct wlr_xdg_popup_v6 *popup_state; + wl_list_for_each(popup_state, &surface->popups, link) { + struct wlr_xdg_surface_v6 *popup = popup_state->base; + if (!popup->configured) { + continue; + } + + double popup_width = popup->surface->current->width; + double popup_height = popup->surface->current->height; + + double popup_sx, popup_sy; + wlr_xdg_surface_v6_popup_get_position(popup, &popup_sx, &popup_sy); + rotate_child_position(&popup_sx, &popup_sy, popup_width, popup_height, + width, height, rotation); + + surface_for_each_surface(popup->surface, base_x + popup_sx, + base_y + popup_sy, rotation, iterator, user_data); + xdg_surface_v6_for_each_surface(popup, base_x + popup_sx, + base_y + popup_sy, rotation, iterator, user_data); + } +} + +static void wl_shell_surface_for_each_surface( + struct wlr_wl_shell_surface *surface, double lx, double ly, + float rotation, bool is_child, surface_iterator_func_t iterator, + void *user_data) { + if (is_child || surface->state != WLR_WL_SHELL_SURFACE_STATE_POPUP) { + surface_for_each_surface(surface->surface, lx, ly, rotation, iterator, + user_data); + + double width = surface->surface->current->width; + double height = surface->surface->current->height; + + struct wlr_wl_shell_surface *popup; + wl_list_for_each(popup, &surface->popups, popup_link) { + double popup_width = popup->surface->current->width; + double popup_height = popup->surface->current->height; + + double popup_x = popup->transient_state->x; + double popup_y = popup->transient_state->y; + rotate_child_position(&popup_x, &popup_y, popup_width, popup_height, + width, height, rotation); + + wl_shell_surface_for_each_surface(popup, lx + popup_x, ly + popup_y, + rotation, true, iterator, user_data); + } + } +} + +static void view_for_each_surface(struct roots_view *view, + surface_iterator_func_t iterator, void *user_data) { + switch (view->type) { + case ROOTS_XDG_SHELL_V6_VIEW: + surface_for_each_surface(view->wlr_surface, view->x, view->y, + view->rotation, iterator, user_data); + xdg_surface_v6_for_each_surface(view->xdg_surface_v6, view->x, view->y, + view->rotation, iterator, user_data); + break; + case ROOTS_WL_SHELL_VIEW: + wl_shell_surface_for_each_surface(view->wl_shell_surface, view->x, + view->y, view->rotation, false, iterator, user_data); + break; + case ROOTS_XWAYLAND_VIEW: + surface_for_each_surface(view->wlr_surface, view->x, view->y, + view->rotation, iterator, user_data); + break; + } +} + +static void xwayland_children_for_each_surface( + struct wlr_xwayland_surface *surface, + surface_iterator_func_t iterator, void *user_data) { + struct wlr_xwayland_surface *child; + wl_list_for_each(child, &surface->children, parent_link) { + if (child->surface != NULL && child->added) { + surface_for_each_surface(child->surface, child->x, child->y, 0, + iterator, user_data); + } + xwayland_children_for_each_surface(child, iterator, user_data); + } +} + + +struct render_data { + struct roots_output *output; + struct timespec *when; + pixman_region32_t *damage; +}; + /** * Checks whether a surface at (lx, ly) intersects an output. Sets `box` to the * surface box in the output, in output-local coordinates. @@ -52,9 +168,13 @@ static bool surface_intersect_output(struct wlr_surface *surface, return wlr_output_layout_intersects(output_layout, wlr_output, &layout_box); } -static void render_surface(struct wlr_surface *surface, - struct roots_output *output, struct timespec *when, - pixman_region32_t *damage, double lx, double ly, float rotation) { +static void render_surface(struct wlr_surface *surface, double lx, double ly, + float rotation, void *_data) { + struct render_data *data = _data; + struct roots_output *output = data->output; + struct timespec *when = data->when; + pixman_region32_t *damage = data->damage; + if (!wlr_surface_has_buffer(surface)) { return; } @@ -63,7 +183,7 @@ static void render_surface(struct wlr_surface *surface, bool intersects = surface_intersect_output(surface, output->desktop->layout, output->wlr_output, lx, ly, &box); if (!intersects) { - goto render_subsurfaces; + return; } // TODO: output scale, output transform support @@ -135,107 +255,6 @@ static void render_surface(struct wlr_surface *surface, surface_damage_finish: pixman_region32_fini(&surface_damage); - -render_subsurfaces:; - struct wlr_subsurface *subsurface; - wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) { - struct wlr_surface_state *state = subsurface->surface->current; - double sx = state->subsurface_position.x; - double sy = state->subsurface_position.y; - rotate_child_position(&sx, &sy, state->width, state->height, - surface->current->width, surface->current->height, rotation); - - render_surface(subsurface->surface, output, when, damage, - lx + sx, ly + sy, rotation); - } -} - -static void render_xdg_v6_popups(struct wlr_xdg_surface_v6 *surface, - struct roots_output *output, struct timespec *when, - pixman_region32_t *damage, double base_x, double base_y, - float rotation) { - double width = surface->surface->current->width; - double height = surface->surface->current->height; - - struct wlr_xdg_surface_v6 *popup; - wl_list_for_each(popup, &surface->popups, popup_link) { - if (!popup->configured) { - continue; - } - - double popup_width = popup->surface->current->width; - double popup_height = popup->surface->current->height; - - double popup_sx, popup_sy; - wlr_xdg_surface_v6_popup_get_position(popup, &popup_sx, &popup_sy); - rotate_child_position(&popup_sx, &popup_sy, popup_width, popup_height, - width, height, rotation); - - render_surface(popup->surface, output, when, damage, - base_x + popup_sx, base_y + popup_sy, rotation); - render_xdg_v6_popups(popup, output, when, damage, - base_x + popup_sx, base_y + popup_sy, rotation); - } -} - -static void render_wl_shell_surface(struct wlr_wl_shell_surface *surface, - struct roots_output *output, struct timespec *when, - pixman_region32_t *damage, double lx, double ly, float rotation, - bool is_child) { - if (is_child || surface->state != WLR_WL_SHELL_SURFACE_STATE_POPUP) { - render_surface(surface->surface, output, when, damage, lx, ly, - rotation); - - double width = surface->surface->current->width; - double height = surface->surface->current->height; - - struct wlr_wl_shell_surface *popup; - wl_list_for_each(popup, &surface->popups, popup_link) { - double popup_width = popup->surface->current->width; - double popup_height = popup->surface->current->height; - - double popup_x = popup->transient_state->x; - double popup_y = popup->transient_state->y; - rotate_child_position(&popup_x, &popup_y, popup_width, popup_height, - width, height, rotation); - - render_wl_shell_surface(popup, output, when, damage, - lx + popup_x, ly + popup_y, rotation, true); - } - } -} - -static void render_xwayland_children(struct wlr_xwayland_surface *surface, - struct roots_output *output, struct timespec *when, - pixman_region32_t *damage) { - struct wlr_xwayland_surface *child; - wl_list_for_each(child, &surface->children, parent_link) { - if (child->surface != NULL && child->added) { - render_surface(child->surface, output, when, damage, - child->x, child->y, 0); - } - render_xwayland_children(child, output, when, damage); - } -} - -static void render_view(struct roots_view *view, struct roots_output *output, - struct timespec *when, pixman_region32_t *damage) { - switch (view->type) { - case ROOTS_XDG_SHELL_V6_VIEW: - render_surface(view->wlr_surface, output, when, damage, - view->x, view->y, view->rotation); - render_xdg_v6_popups(view->xdg_surface_v6, output, when, damage, - view->x, view->y, view->rotation); - break; - case ROOTS_WL_SHELL_VIEW: - render_wl_shell_surface(view->wl_shell_surface, output, when, damage, - view->x, view->y, view->rotation, false); - break; - case ROOTS_XWAYLAND_VIEW: - render_surface(view->wlr_surface, output, when, damage, - view->x, view->y, view->rotation); - break; - } } static bool has_standalone_surface(struct roots_view *view) { @@ -325,7 +344,11 @@ static void render_output(struct roots_output *output) { goto damage_finish; } - wlr_log(L_DEBUG, "render"); + struct render_data data = { + .output = output, + .when = &now, + .damage = &damage, + }; wlr_renderer_begin(server->renderer, wlr_output); glEnable(GL_SCISSOR_TEST); @@ -353,14 +376,14 @@ static void render_output(struct roots_output *output) { goto renderer_end; } - render_view(view, output, &now, &damage); + view_for_each_surface(view, render_surface, &data); // During normal rendering the xwayland window tree isn't traversed // because all windows are rendered. Here we only want to render // the fullscreen window's children so we have to traverse the tree. if (view->type == ROOTS_XWAYLAND_VIEW) { - render_xwayland_children(view->xwayland_surface, output, &now, - &damage); + xwayland_children_for_each_surface(view->xwayland_surface, + render_surface, &data); } goto renderer_end; @@ -369,7 +392,7 @@ static void render_output(struct roots_output *output) { // Render all views struct roots_view *view; wl_list_for_each_reverse(view, &desktop->views, link) { - render_view(view, output, &now, &damage); + view_for_each_surface(view, render_surface, &data); } // Render drag icons @@ -386,14 +409,14 @@ static void render_output(struct roots_output *output) { if (drag_icon->is_pointer) { icon_x = cursor->x + drag_icon->sx; icon_y = cursor->y + drag_icon->sy; - render_surface(icon, output, &now, &damage, icon_x, icon_y, 0); + render_surface(icon, icon_x, icon_y, 0, &data); } else { struct wlr_touch_point *point = wlr_seat_touch_get_point(seat->seat, drag_icon->touch_id); if (point) { icon_x = seat->touch_x + drag_icon->sx; icon_y = seat->touch_y + drag_icon->sy; - render_surface(icon, output, &now, &damage, icon_x, icon_y, 0); + render_surface(icon, icon_x, icon_y, 0, &data); } } } @@ -443,8 +466,10 @@ static void output_damage_whole(struct roots_output *output) { schedule_render(output); } -static void output_damage_whole_surface(struct roots_output *output, - struct wlr_surface *surface, double lx, double ly, float rotation) { +static void damage_whole_surface(struct wlr_surface *surface, + double lx, double ly, float rotation, void *data) { + struct roots_output *output = data; + if (!wlr_surface_has_buffer(surface)) { return; } @@ -460,18 +485,6 @@ static void output_damage_whole_surface(struct roots_output *output, box.x, box.y, box.width, box.height); schedule_render(output); - - struct wlr_subsurface *subsurface; - wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) { - struct wlr_surface_state *state = subsurface->surface->current; - double sx = state->subsurface_position.x; - double sy = state->subsurface_position.y; - rotate_child_position(&sx, &sy, state->width, state->height, - surface->current->width, surface->current->height, rotation); - - output_damage_whole_surface(output, subsurface->surface, - lx + sx, ly + sy, rotation); - } } void output_damage_whole_view(struct roots_output *output, @@ -480,16 +493,13 @@ void output_damage_whole_view(struct roots_output *output, return; } - if (view->wlr_surface != NULL) { - output_damage_whole_surface(output, view->wlr_surface, - view->x, view->y, view->rotation); - } - - // TODO: popups, etc + view_for_each_surface(view, damage_whole_surface, output); } -static void output_damage_from_surface(struct roots_output *output, - struct wlr_surface *surface, double lx, double ly, float rotation) { +static void damage_from_surface(struct wlr_surface *surface, + double lx, double ly, float rotation, void *data) { + struct roots_output *output = data; + if (!wlr_surface_has_buffer(surface)) { return; } @@ -510,18 +520,6 @@ static void output_damage_from_surface(struct roots_output *output, pixman_region32_fini(&damage); schedule_render(output); - - struct wlr_subsurface *subsurface; - wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) { - struct wlr_surface_state *state = subsurface->surface->current; - double sx = state->subsurface_position.x; - double sy = state->subsurface_position.y; - rotate_child_position(&sx, &sy, state->width, state->height, - surface->current->width, surface->current->height, rotation); - - output_damage_from_surface(output, subsurface->surface, - lx + sx, ly + sy, rotation); - } } void output_damage_from_view(struct roots_output *output, @@ -530,12 +528,7 @@ void output_damage_from_view(struct roots_output *output, return; } - if (view->wlr_surface != NULL) { - output_damage_from_surface(output, view->wlr_surface, - view->x, view->y, view->rotation); - } - - // TODO: popups, etc + view_for_each_surface(view, damage_from_surface, output); } static void output_handle_mode(struct wl_listener *listener, void *data) { diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c index 7337fb1e..0a3ca72c 100644 --- a/rootston/xdg_shell_v6.c +++ b/rootston/xdg_shell_v6.c @@ -10,6 +10,52 @@ #include "rootston/server.h" #include "rootston/input.h" +static void popup_destroy(struct roots_view_child *child) { + assert(child->destroy == popup_destroy); + struct roots_xdg_popup_v6 *popup = (struct roots_xdg_popup_v6 *)child; + if (popup == NULL) { + return; + } + wl_list_remove(&popup->destroy.link); + wl_list_remove(&popup->new_popup.link); + view_child_finish(&popup->view_child); + free(popup); +} + +static void popup_handle_destroy(struct wl_listener *listener, void *data) { + struct roots_xdg_popup_v6 *popup = + wl_container_of(listener, popup, destroy); + popup_destroy((struct roots_view_child *)popup); +} + +static struct roots_xdg_popup_v6 *popup_create(struct roots_view *view, + struct wlr_xdg_popup_v6 *wlr_popup); + +static void popup_handle_new_popup(struct wl_listener *listener, void *data) { + struct roots_xdg_popup_v6 *popup = + wl_container_of(listener, popup, new_popup); + struct wlr_xdg_popup_v6 *wlr_popup = data; + popup_create(popup->view_child.view, wlr_popup); +} + +static struct roots_xdg_popup_v6 *popup_create(struct roots_view *view, + struct wlr_xdg_popup_v6 *wlr_popup) { + struct roots_xdg_popup_v6 *popup = + calloc(1, sizeof(struct roots_xdg_popup_v6)); + if (popup == NULL) { + return NULL; + } + popup->wlr_popup = wlr_popup; + popup->view_child.destroy = popup_destroy; + view_child_init(&popup->view_child, view, wlr_popup->base->surface); + popup->destroy.notify = popup_handle_destroy; + wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy); + popup->new_popup.notify = popup_handle_new_popup; + wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup); + return popup; +} + + static void get_size(const struct roots_view *view, struct wlr_box *box) { assert(view->type == ROOTS_XDG_SHELL_V6_VIEW); struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6; @@ -191,9 +237,9 @@ static void handle_request_fullscreen(struct wl_listener *listener, view_set_fullscreen(view, e->fullscreen, e->output); } -static void handle_commit(struct wl_listener *listener, void *data) { +static void handle_surface_commit(struct wl_listener *listener, void *data) { struct roots_xdg_surface_v6 *roots_surface = - wl_container_of(listener, roots_surface, commit); + wl_container_of(listener, roots_surface, surface_commit); struct roots_view *view = roots_surface->view; struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6; @@ -223,13 +269,23 @@ static void handle_commit(struct wl_listener *listener, void *data) { } } +static void handle_new_popup(struct wl_listener *listener, void *data) { + struct roots_xdg_surface_v6 *roots_xdg_surface = + wl_container_of(listener, roots_xdg_surface, new_popup); + struct wlr_xdg_popup_v6 *wlr_popup = data; + popup_create(roots_xdg_surface->view, wlr_popup); +} + static void handle_destroy(struct wl_listener *listener, void *data) { struct roots_xdg_surface_v6 *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, destroy); - wl_list_remove(&roots_xdg_surface->commit.link); + wl_list_remove(&roots_xdg_surface->surface_commit.link); wl_list_remove(&roots_xdg_surface->destroy.link); + wl_list_remove(&roots_xdg_surface->new_popup.link); wl_list_remove(&roots_xdg_surface->request_move.link); wl_list_remove(&roots_xdg_surface->request_resize.link); + wl_list_remove(&roots_xdg_surface->request_maximize.link); + wl_list_remove(&roots_xdg_surface->request_fullscreen.link); wl_list_remove(&roots_xdg_surface->view->link); view_finish(roots_xdg_surface->view); free(roots_xdg_surface->view); @@ -257,8 +313,9 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { if (!roots_surface) { return; } - roots_surface->commit.notify = handle_commit; - wl_signal_add(&surface->surface->events.commit, &roots_surface->commit); + roots_surface->surface_commit.notify = handle_surface_commit; + wl_signal_add(&surface->surface->events.commit, + &roots_surface->surface_commit); roots_surface->destroy.notify = handle_destroy; wl_signal_add(&surface->events.destroy, &roots_surface->destroy); roots_surface->request_move.notify = handle_request_move; @@ -272,6 +329,8 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { roots_surface->request_fullscreen.notify = handle_request_fullscreen; wl_signal_add(&surface->events.request_fullscreen, &roots_surface->request_fullscreen); + roots_surface->new_popup.notify = handle_new_popup; + wl_signal_add(&surface->events.new_popup, &roots_surface->new_popup); struct roots_view *view = calloc(1, sizeof(struct roots_view)); if (!view) { diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index 1c46197e..daf5f867 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -203,7 +203,7 @@ static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) { } } - wl_list_remove(&surface->popup_link); + wl_list_remove(&surface->popup_state->link); free(surface->popup_state); } @@ -502,12 +502,13 @@ static void xdg_surface_get_popup(struct wl_client *client, surface->popup_state->parent = parent; surface->popup_state->geometry = xdg_positioner_get_geometry(positioner, surface, parent); - wl_list_insert(&surface->popup_state->parent->popups, - &surface->popup_link); + wl_list_insert(&parent->popups, &surface->popup_state->link); wl_resource_set_implementation(surface->popup_state->resource, &zxdg_popup_v6_implementation, surface, xdg_popup_resource_destroy); + + wl_signal_emit(&parent->events.new_popup, surface->popup_state); } @@ -1184,6 +1185,7 @@ static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, wl_signal_init(&surface->events.request_show_window_menu); wl_signal_init(&surface->events.destroy); wl_signal_init(&surface->events.ping_timeout); + wl_signal_init(&surface->events.new_popup); wl_signal_add(&surface->surface->events.destroy, &surface->surface_destroy_listener); @@ -1401,14 +1403,16 @@ struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6_popup_at( // XXX: I think this is so complicated because we're mixing geometry // coordinates with surface coordinates. Input handling should only deal // with surface coordinates. - struct wlr_xdg_surface_v6 *popup; - wl_list_for_each(popup, &surface->popups, popup_link) { + struct wlr_xdg_popup_v6 *popup_state; + wl_list_for_each(popup_state, &surface->popups, link) { + struct wlr_xdg_surface_v6 *popup = popup_state->base; + double _popup_sx = - surface->geometry->x + popup->popup_state->geometry.x; + surface->geometry->x + popup_state->geometry.x; double _popup_sy = - surface->geometry->y + popup->popup_state->geometry.y; - int popup_width = popup->popup_state->geometry.width; - int popup_height = popup->popup_state->geometry.height; + surface->geometry->y + popup_state->geometry.y; + int popup_width = popup_state->geometry.width; + int popup_height = popup_state->geometry.height; struct wlr_xdg_surface_v6 *_popup = wlr_xdg_surface_v6_popup_at(popup, From f704c3d42b80ad28bfd096e5467a5219c0778e3b Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 21 Jan 2018 22:08:38 +0100 Subject: [PATCH 35/75] rootston: fix damage tracking for fullscreen xwayland views --- rootston/output.c | 32 ++++++++++++++++++++++++++++---- xwayland/xwm.c | 2 +- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/rootston/output.c b/rootston/output.c index d2ea2ade..644fca92 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -121,8 +121,10 @@ static void view_for_each_surface(struct roots_view *view, view->y, view->rotation, false, iterator, user_data); break; case ROOTS_XWAYLAND_VIEW: - surface_for_each_surface(view->wlr_surface, view->x, view->y, - view->rotation, iterator, user_data); + if (view->wlr_surface != NULL) { + surface_for_each_surface(view->wlr_surface, view->x, view->y, + view->rotation, iterator, user_data); + } break; } } @@ -466,6 +468,28 @@ static void output_damage_whole(struct roots_output *output) { schedule_render(output); } +static bool view_accept_damage(struct roots_output *output, + struct roots_view *view) { + if (output->fullscreen_view == NULL) { + return true; + } + if (output->fullscreen_view == view) { + return true; + } + if (output->fullscreen_view->type == ROOTS_XWAYLAND_VIEW && + view->type == ROOTS_XWAYLAND_VIEW) { + // Special case: accept damage from children + struct wlr_xwayland_surface *xsurface = view->xwayland_surface; + while (xsurface != NULL) { + if (output->fullscreen_view->xwayland_surface == xsurface) { + return true; + } + xsurface = xsurface->parent; + } + } + return false; +} + static void damage_whole_surface(struct wlr_surface *surface, double lx, double ly, float rotation, void *data) { struct roots_output *output = data; @@ -489,7 +513,7 @@ static void damage_whole_surface(struct wlr_surface *surface, void output_damage_whole_view(struct roots_output *output, struct roots_view *view) { - if (output->fullscreen_view != NULL && output->fullscreen_view != view) { + if (!view_accept_damage(output, view)) { return; } @@ -524,7 +548,7 @@ static void damage_from_surface(struct wlr_surface *surface, void output_damage_from_view(struct roots_output *output, struct roots_view *view) { - if (output->fullscreen_view != NULL && output->fullscreen_view != view) { + if (!view_accept_damage(output, view)) { return; } diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 3bbaecfb..b9536d96 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -315,7 +315,7 @@ static void read_surface_parent(struct wlr_xwm *xwm, wl_list_init(&xsurface->parent_link); } - wlr_log(L_DEBUG, "XCB_ATOM_WM_TRANSIENT_FOR: %p", xid); + wlr_log(L_DEBUG, "XCB_ATOM_WM_TRANSIENT_FOR: %p", xsurface->parent); wl_signal_emit(&xsurface->events.set_parent, xsurface); } From a8cb02f585dcee9d72beb97c8fc78e2e63d6ac2d Mon Sep 17 00:00:00 2001 From: emersion Date: Mon, 22 Jan 2018 10:34:23 +0100 Subject: [PATCH 36/75] surface: add damage when subsurface moves --- types/wlr_surface.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 36dfc63d..9896fe1b 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -272,6 +272,9 @@ static void wlr_surface_move_state(struct wlr_surface *surface, bool update_damage = false; bool update_size = false; + int oldw = state->width; + int oldh = state->height; + if ((next->invalid & WLR_SURFACE_INVALID_SCALE)) { state->scale = next->scale; update_size = true; @@ -327,13 +330,25 @@ static void wlr_surface_move_state(struct wlr_surface *surface, pixman_region32_copy(&state->input, &next->input); } if ((next->invalid & WLR_SURFACE_INVALID_SUBSURFACE_POSITION)) { + // Subsurface has moved + int dx = state->subsurface_position.x - next->subsurface_position.x; + int dy = state->subsurface_position.y - next->subsurface_position.y; + state->subsurface_position.x = next->subsurface_position.x; state->subsurface_position.y = next->subsurface_position.y; next->subsurface_position.x = 0; next->subsurface_position.y = 0; + + if (dx != 0 || dy != 0) { + pixman_region32_union_rect(&state->surface_damage, + &state->surface_damage, dx, dy, oldw, oldh); + pixman_region32_union_rect(&state->surface_damage, + &state->surface_damage, 0, 0, state->width, state->height); + } } if ((next->invalid & WLR_SURFACE_INVALID_FRAME_CALLBACK_LIST)) { - wl_list_insert_list(&state->frame_callback_list, &next->frame_callback_list); + wl_list_insert_list(&state->frame_callback_list, + &next->frame_callback_list); wl_list_init(&next->frame_callback_list); } @@ -381,10 +396,12 @@ static void wlr_surface_apply_damage(struct wlr_surface *surface, if (reupload_buffer) { wlr_texture_upload_shm(surface->texture, format, buffer); } else { - pixman_region32_t damage = surface->current->buffer_damage; - if (!pixman_region32_not_empty(&damage)) { - goto release; - } + pixman_region32_t damage; + pixman_region32_init(&damage); + pixman_region32_copy(&damage, &surface->current->buffer_damage); + pixman_region32_intersect_rect(&damage, &damage, 0, 0, + surface->current->buffer_width, surface->current->buffer_height); + int n; pixman_box32_t *rects = pixman_region32_rectangles(&damage, &n); for (int i = 0; i < n; ++i) { @@ -397,6 +414,8 @@ static void wlr_surface_apply_damage(struct wlr_surface *surface, break; } } + + pixman_region32_fini(&damage); } release: From 3f1c4f5be799a63ddd75284847bf0e78f77369bf Mon Sep 17 00:00:00 2001 From: emersion Date: Mon, 22 Jan 2018 16:01:32 +0100 Subject: [PATCH 37/75] rootston: damage tracking for wl_shell --- include/rootston/view.h | 9 ++++ include/wlr/types/wlr_wl_shell.h | 1 + rootston/wl_shell.c | 73 +++++++++++++++++++++++++++++++- types/wlr_wl_shell.c | 2 + 4 files changed, 83 insertions(+), 2 deletions(-) diff --git a/include/rootston/view.h b/include/rootston/view.h index 8cfdf321..99e47deb 100644 --- a/include/rootston/view.h +++ b/include/rootston/view.h @@ -11,6 +11,7 @@ struct roots_wl_shell_surface { struct roots_view *view; struct wl_listener destroy; + struct wl_listener new_popup; struct wl_listener request_move; struct wl_listener request_resize; struct wl_listener request_maximize; @@ -135,6 +136,14 @@ struct roots_subsurface { struct wl_listener destroy; }; +struct roots_wl_shell_popup { + struct roots_view_child view_child; + struct wlr_wl_shell_surface *wlr_wl_shell_surface; + struct wl_listener destroy; + struct wl_listener set_state; + struct wl_listener new_popup; +}; + struct roots_xdg_popup_v6 { struct roots_view_child view_child; struct wlr_xdg_popup_v6 *wlr_popup; diff --git a/include/wlr/types/wlr_wl_shell.h b/include/wlr/types/wlr_wl_shell.h index 375477c7..00f2bb69 100644 --- a/include/wlr/types/wlr_wl_shell.h +++ b/include/wlr/types/wlr_wl_shell.h @@ -79,6 +79,7 @@ struct wlr_wl_shell_surface { struct { struct wl_signal destroy; struct wl_signal ping_timeout; + struct wl_signal new_popup; struct wl_signal request_move; struct wl_signal request_resize; diff --git a/rootston/wl_shell.c b/rootston/wl_shell.c index be658f40..1fc48452 100644 --- a/rootston/wl_shell.c +++ b/rootston/wl_shell.c @@ -10,6 +10,61 @@ #include "rootston/server.h" #include "rootston/input.h" +static void popup_destroy(struct roots_view_child *child) { + assert(child->destroy == popup_destroy); + struct roots_wl_shell_popup *popup = (struct roots_wl_shell_popup *)child; + if (popup == NULL) { + return; + } + wl_list_remove(&popup->destroy.link); + wl_list_remove(&popup->set_state.link); + wl_list_remove(&popup->new_popup.link); + view_child_finish(&popup->view_child); + free(popup); +} + +static void popup_handle_destroy(struct wl_listener *listener, void *data) { + struct roots_wl_shell_popup *popup = + wl_container_of(listener, popup, destroy); + popup_destroy((struct roots_view_child *)popup); +} + +static void popup_handle_set_state(struct wl_listener *listener, void *data) { + struct roots_wl_shell_popup *popup = + wl_container_of(listener, popup, set_state); + popup_destroy((struct roots_view_child *)popup); +} + +static struct roots_wl_shell_popup *popup_create(struct roots_view *view, + struct wlr_wl_shell_surface *wlr_wl_shell_surface); + +static void popup_handle_new_popup(struct wl_listener *listener, void *data) { + struct roots_wl_shell_popup *popup = + wl_container_of(listener, popup, new_popup); + struct wlr_wl_shell_surface *wlr_wl_shell_surface = data; + popup_create(popup->view_child.view, wlr_wl_shell_surface); +} + +static struct roots_wl_shell_popup *popup_create(struct roots_view *view, + struct wlr_wl_shell_surface *wlr_wl_shell_surface) { + struct roots_wl_shell_popup *popup = + calloc(1, sizeof(struct roots_wl_shell_popup)); + if (popup == NULL) { + return NULL; + } + popup->wlr_wl_shell_surface = wlr_wl_shell_surface; + popup->view_child.destroy = popup_destroy; + view_child_init(&popup->view_child, view, wlr_wl_shell_surface->surface); + popup->destroy.notify = popup_handle_destroy; + wl_signal_add(&wlr_wl_shell_surface->events.destroy, &popup->destroy); + popup->set_state.notify = popup_handle_set_state; + wl_signal_add(&wlr_wl_shell_surface->events.set_state, &popup->set_state); + popup->new_popup.notify = popup_handle_new_popup; + wl_signal_add(&wlr_wl_shell_surface->events.new_popup, &popup->new_popup); + return popup; +} + + static void resize(struct roots_view *view, uint32_t width, uint32_t height) { assert(view->type == ROOTS_WL_SHELL_VIEW); struct wlr_wl_shell_surface *surf = view->wl_shell_surface; @@ -107,6 +162,13 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) { view_update_position(view, x, y); } +static void handle_new_popup(struct wl_listener *listener, void *data) { + struct roots_wl_shell_surface *roots_surface = + wl_container_of(listener, roots_surface, new_popup); + struct wlr_wl_shell_surface *wlr_wl_shell_surface = data; + popup_create(roots_surface->view, wlr_wl_shell_surface); +} + static void handle_destroy(struct wl_listener *listener, void *data) { struct roots_wl_shell_surface *roots_surface = wl_container_of(listener, roots_surface, destroy); @@ -126,9 +188,14 @@ static void handle_destroy(struct wl_listener *listener, void *data) { void handle_wl_shell_surface(struct wl_listener *listener, void *data) { struct roots_desktop *desktop = wl_container_of(listener, desktop, wl_shell_surface); - struct wlr_wl_shell_surface *surface = data; - wlr_log(L_DEBUG, "new shell surface: title=%s, class=%s", + + if (surface->state == WLR_WL_SHELL_SURFACE_STATE_POPUP) { + wlr_log(L_DEBUG, "new wl shell popup"); + return; + } + + wlr_log(L_DEBUG, "new wl shell surface: title=%s, class=%s", surface->title, surface->class); wlr_wl_shell_surface_ping(surface); @@ -139,6 +206,8 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) { } roots_surface->destroy.notify = handle_destroy; wl_signal_add(&surface->events.destroy, &roots_surface->destroy); + roots_surface->new_popup.notify = handle_new_popup; + wl_signal_add(&surface->events.new_popup, &roots_surface->new_popup); roots_surface->request_move.notify = handle_request_move; wl_signal_add(&surface->events.request_move, &roots_surface->request_move); roots_surface->request_resize.notify = handle_request_resize; diff --git a/types/wlr_wl_shell.c b/types/wlr_wl_shell.c index 03ce2c20..dd6514df 100644 --- a/types/wlr_wl_shell.c +++ b/types/wlr_wl_shell.c @@ -221,6 +221,7 @@ static void shell_surface_popup_set_parent(struct wlr_wl_shell_surface *surface, if (parent) { wl_list_remove(&surface->popup_link); wl_list_insert(&parent->popups, &surface->popup_link); + wl_signal_emit(&parent->events.new_popup, surface); } } @@ -519,6 +520,7 @@ static void shell_protocol_get_shell_surface(struct wl_client *client, wl_signal_init(&wl_surface->events.destroy); wl_signal_init(&wl_surface->events.ping_timeout); + wl_signal_init(&wl_surface->events.new_popup); wl_signal_init(&wl_surface->events.request_move); wl_signal_init(&wl_surface->events.request_resize); wl_signal_init(&wl_surface->events.request_fullscreen); From 415a2b7c569457ebf85d7ae066cc19bee196d22e Mon Sep 17 00:00:00 2001 From: emersion Date: Mon, 22 Jan 2018 16:42:22 +0100 Subject: [PATCH 38/75] render: add wlr_renderer_clear and wlr_renderer_scissor --- examples/output-layout.c | 1 + examples/rotation.c | 1 + examples/tablet.c | 1 + examples/touch.c | 1 + include/wlr/render.h | 4 ++++ include/wlr/render/egl.h | 3 --- include/wlr/render/interface.h | 4 ++++ render/gles2/renderer.c | 40 ++++++++++++++++++++++++---------- render/wlr_renderer.c | 9 ++++++++ rootston/output.c | 26 ++++++++++++++-------- 10 files changed, 67 insertions(+), 23 deletions(-) diff --git a/examples/output-layout.c b/examples/output-layout.c index b97d3723..0c85ba7f 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -102,6 +102,7 @@ static void handle_output_frame(struct output_state *output, wlr_output_make_current(wlr_output, NULL); wlr_renderer_begin(sample->renderer, wlr_output); + wlr_renderer_clear(sample->renderer, 0.25f, 0.25f, 0.25f, 1); animate_cat(sample, output->output); diff --git a/examples/rotation.c b/examples/rotation.c index 64de73f9..4f7b1567 100644 --- a/examples/rotation.c +++ b/examples/rotation.c @@ -44,6 +44,7 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts wlr_output_make_current(wlr_output, NULL); wlr_renderer_begin(sample->renderer, wlr_output); + wlr_renderer_clear(sample->renderer, 0.25f, 0.25f, 0.25f, 1); float matrix[16]; for (int y = -128 + (int)odata->y_offs; y < height; y += 128) { diff --git a/examples/tablet.c b/examples/tablet.c index 35326664..f12ecbc4 100644 --- a/examples/tablet.c +++ b/examples/tablet.c @@ -44,6 +44,7 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts wlr_output_make_current(wlr_output, NULL); wlr_renderer_begin(sample->renderer, wlr_output); + wlr_renderer_clear(sample->renderer, 0.25f, 0.25f, 0.25f, 1); float matrix[16], view[16]; float distance = 0.8f * (1 - sample->distance); diff --git a/examples/touch.c b/examples/touch.c index 74642b96..2ef2712f 100644 --- a/examples/touch.c +++ b/examples/touch.c @@ -43,6 +43,7 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts wlr_output_make_current(wlr_output, NULL); wlr_renderer_begin(sample->renderer, wlr_output); + wlr_renderer_clear(sample->renderer, 0.25f, 0.25f, 0.25f, 1); float matrix[16]; struct touch_point *p; diff --git a/include/wlr/render.h b/include/wlr/render.h index 5027064d..bfd9e829 100644 --- a/include/wlr/render.h +++ b/include/wlr/render.h @@ -5,6 +5,7 @@ #include #include #include +#include #include struct wlr_texture; @@ -12,6 +13,9 @@ struct wlr_renderer; void wlr_renderer_begin(struct wlr_renderer *r, struct wlr_output *output); void wlr_renderer_end(struct wlr_renderer *r); +void wlr_renderer_clear(struct wlr_renderer *r, float red, float green, + float blue, float alpha); +void wlr_renderer_scissor(struct wlr_renderer *r, struct wlr_box *box); /** * Requests a texture handle from this renderer. */ diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index c292a6f8..6979fd9b 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -72,7 +72,4 @@ const char *egl_error(void); bool wlr_egl_make_current(struct wlr_egl *egl, EGLSurface surface, int *buffer_age); -// TODO: remove -int wlr_egl_get_buffer_age(struct wlr_egl *egl, EGLSurface surface); - #endif diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index bbc5acb4..3927795d 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -6,6 +6,7 @@ #include #include #include +#include #include struct wlr_renderer_impl; @@ -17,6 +18,9 @@ struct wlr_renderer { struct wlr_renderer_impl { void (*begin)(struct wlr_renderer *renderer, struct wlr_output *output); void (*end)(struct wlr_renderer *renderer); + void (*clear)(struct wlr_renderer *renderer, float red, float green, + float blue, float alpha); + void (*scissor)(struct wlr_renderer *renderer, struct wlr_box *box); struct wlr_texture *(*texture_create)(struct wlr_renderer *renderer); bool (*render_with_matrix)(struct wlr_renderer *renderer, struct wlr_texture *texture, const float (*matrix)[16]); diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 32f2eb02..3909fd84 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -105,7 +105,7 @@ static void init_globals() { init_default_shaders(); } -static void wlr_gles2_begin(struct wlr_renderer *_renderer, +static void wlr_gles2_begin(struct wlr_renderer *wlr_renderer, struct wlr_output *output) { GL_CALL(glViewport(0, 0, output->width, output->height)); @@ -117,14 +117,30 @@ static void wlr_gles2_begin(struct wlr_renderer *_renderer, // for users to sling matricies themselves } -static void wlr_gles2_end(struct wlr_renderer *renderer) { +static void wlr_gles2_end(struct wlr_renderer *wlr_renderer) { // no-op } +static void wlr_gles2_clear(struct wlr_renderer *wlr_renderer, float red, + float green, float blue, float alpha) { + glClearColor(red, green, blue, alpha); + glClear(GL_COLOR_BUFFER_BIT); +} + +static void wlr_gles2_scissor(struct wlr_renderer *wlr_renderer, + struct wlr_box *box) { + if (box != NULL) { + glScissor(box->x, box->y, box->width, box->height); + glEnable(GL_SCISSOR_TEST); + } else { + glDisable(GL_SCISSOR_TEST); + } +} + static struct wlr_texture *wlr_gles2_texture_create( - struct wlr_renderer *_renderer) { + struct wlr_renderer *wlr_renderer) { struct wlr_gles2_renderer *renderer = - (struct wlr_gles2_renderer *)_renderer; + (struct wlr_gles2_renderer *)wlr_renderer; return gles2_texture_create(renderer->egl); } @@ -154,7 +170,7 @@ static void draw_quad() { GL_CALL(glDisableVertexAttribArray(1)); } -static bool wlr_gles2_render_texture(struct wlr_renderer *_renderer, +static bool wlr_gles2_render_texture(struct wlr_renderer *wlr_renderer, struct wlr_texture *texture, const float (*matrix)[16]) { if (!texture || !texture->valid) { wlr_log(L_ERROR, "attempt to render invalid texture"); @@ -169,7 +185,7 @@ static bool wlr_gles2_render_texture(struct wlr_renderer *_renderer, return true; } -static void wlr_gles2_render_quad(struct wlr_renderer *renderer, +static void wlr_gles2_render_quad(struct wlr_renderer *wlr_renderer, const float (*color)[4], const float (*matrix)[16]) { GL_CALL(glUseProgram(shaders.quad)); GL_CALL(glUniformMatrix4fv(0, 1, GL_TRUE, *matrix)); @@ -177,7 +193,7 @@ static void wlr_gles2_render_quad(struct wlr_renderer *renderer, draw_quad(); } -static void wlr_gles2_render_ellipse(struct wlr_renderer *renderer, +static void wlr_gles2_render_ellipse(struct wlr_renderer *wlr_renderer, const float (*color)[4], const float (*matrix)[16]) { GL_CALL(glUseProgram(shaders.ellipse)); GL_CALL(glUniformMatrix4fv(0, 1, GL_TRUE, *matrix)); @@ -197,10 +213,10 @@ static const enum wl_shm_format *wlr_gles2_formats( return formats; } -static bool wlr_gles2_buffer_is_drm(struct wlr_renderer *_renderer, +static bool wlr_gles2_buffer_is_drm(struct wlr_renderer *wlr_renderer, struct wl_resource *buffer) { struct wlr_gles2_renderer *renderer = - (struct wlr_gles2_renderer *)_renderer; + (struct wlr_gles2_renderer *)wlr_renderer; EGLint format; return wlr_egl_query_buffer(renderer->egl, buffer, EGL_TEXTURE_FORMAT, &format); @@ -216,8 +232,8 @@ static void rgba_to_argb(uint32_t *data, size_t height, size_t stride) { } } -static void wlr_gles2_read_pixels(struct wlr_renderer *renderer, int x, int y, - int width, int height, void *out_data) { +static void wlr_gles2_read_pixels(struct wlr_renderer *wlr_renderer, + int x, int y, int width, int height, void *out_data) { glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, out_data); rgba_to_argb(out_data, height, width*4); } @@ -225,6 +241,8 @@ static void wlr_gles2_read_pixels(struct wlr_renderer *renderer, int x, int y, static struct wlr_renderer_impl wlr_renderer_impl = { .begin = wlr_gles2_begin, .end = wlr_gles2_end, + .clear = wlr_gles2_clear, + .scissor = wlr_gles2_scissor, .texture_create = wlr_gles2_texture_create, .render_with_matrix = wlr_gles2_render_texture, .render_quad = wlr_gles2_render_quad, diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index ef0c31be..ba7d4b74 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -23,6 +23,15 @@ void wlr_renderer_end(struct wlr_renderer *r) { r->impl->end(r); } +void wlr_renderer_clear(struct wlr_renderer *r, float red, float green, + float blue, float alpha) { + r->impl->clear(r, red, green, blue, alpha); +} + +void wlr_renderer_scissor(struct wlr_renderer *r, struct wlr_box *box) { + r->impl->scissor(r, box); +} + struct wlr_texture *wlr_render_texture_create(struct wlr_renderer *r) { return r->impl->texture_create(r); } diff --git a/rootston/output.c b/rootston/output.c index 644fca92..b6879965 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include @@ -247,8 +246,13 @@ static void render_surface(struct wlr_surface *surface, double lx, double ly, pixman_box32_t *rects = pixman_region32_rectangles(&surface_damage, &nrects); for (int i = 0; i < nrects; ++i) { - glScissor(rects[i].x1, output->wlr_output->height - rects[i].y2, - rects[i].x2 - rects[i].x1, rects[i].y2 - rects[i].y1); + struct wlr_box scissor = { + .x = rects[i].x1, + .y = output->wlr_output->height - rects[i].y2, + .width = rects[i].x2 - rects[i].x1, + .height = rects[i].y2 - rects[i].y1, + }; + wlr_renderer_scissor(output->desktop->server->renderer, &scissor); wlr_render_with_matrix(output->desktop->server->renderer, surface->texture, &matrix); } @@ -353,7 +357,6 @@ static void render_output(struct roots_output *output) { }; wlr_renderer_begin(server->renderer, wlr_output); - glEnable(GL_SCISSOR_TEST); if (!pixman_region32_not_empty(&damage)) { // Output isn't damaged but needs buffer swap @@ -363,10 +366,15 @@ static void render_output(struct roots_output *output) { int nrects; pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); for (int i = 0; i < nrects; ++i) { - glScissor(rects[i].x1, wlr_output->height - rects[i].y2, - rects[i].x2 - rects[i].x1, rects[i].y2 - rects[i].y1); - glClearColor(clear_color[0], clear_color[1], clear_color[2], 1); - glClear(GL_COLOR_BUFFER_BIT); + struct wlr_box scissor = { + .x = rects[i].x1, + .y = wlr_output->height - rects[i].y2, + .width = rects[i].x2 - rects[i].x1, + .height = rects[i].y2 - rects[i].y1, + }; + wlr_renderer_scissor(output->desktop->server->renderer, &scissor); + wlr_renderer_clear(output->desktop->server->renderer, + clear_color[0], clear_color[1], clear_color[2], 1); } // If a view is fullscreen on this output, render it @@ -425,7 +433,7 @@ static void render_output(struct roots_output *output) { } renderer_end: - glDisable(GL_SCISSOR_TEST); + wlr_renderer_scissor(output->desktop->server->renderer, NULL); wlr_renderer_end(server->renderer); wlr_output_swap_buffers(wlr_output, &now, &damage); output->frame_pending = true; From 4d282c859099321b1e799a2ab344480f186359ef Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 23 Jan 2018 13:37:58 +0100 Subject: [PATCH 39/75] rootston: damage tracking for drag icons --- include/rootston/seat.h | 15 +++++++++++- include/wlr/types/wlr_data_device.h | 4 +-- include/wlr/types/wlr_seat.h | 2 ++ rootston/seat.c | 38 +++++++++++++++++++++++------ types/wlr_data_device.c | 6 ++++- types/wlr_seat.c | 3 +++ 6 files changed, 57 insertions(+), 11 deletions(-) diff --git a/include/rootston/seat.h b/include/rootston/seat.h index cf5dd3b2..c71f7de0 100644 --- a/include/rootston/seat.h +++ b/include/rootston/seat.h @@ -17,12 +17,15 @@ struct roots_seat { struct wl_list views; // roots_seat_view::link bool has_focus; + struct wl_list drag_icons; // roots_drag_icon::link + struct wl_list keyboards; struct wl_list pointers; struct wl_list touch; struct wl_list tablet_tools; - struct wl_listener seat_destroy; + struct wl_listener new_drag_icon; + struct wl_listener destroy; }; struct roots_seat_view { @@ -33,6 +36,16 @@ struct roots_seat_view { struct wl_listener view_destroy; }; +struct roots_drag_icon { + struct roots_seat *seat; + struct wlr_drag_icon *wlr_drag_icon; + struct wl_list link; + + struct wl_listener surface_commit; + struct wl_listener map; + struct wl_listener destroy; +}; + struct roots_pointer { struct roots_seat *seat; struct wlr_input_device *device; diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index 54514b4c..ff4a0f7e 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -71,10 +71,10 @@ struct wlr_drag_icon { bool is_pointer; int32_t touch_id; - int32_t sx; - int32_t sy; + int32_t sx, sy; struct { + struct wl_signal map; // emitted when mapped or unmapped struct wl_signal destroy; } events; diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index c2a89f33..ffdabd98 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -209,6 +209,8 @@ struct wlr_seat { struct wl_signal selection; struct wl_signal primary_selection; + struct wl_signal new_drag_icon; + struct wl_signal destroy; } events; diff --git a/rootston/seat.c b/rootston/seat.c index 1a0e6253..5817e13c 100644 --- a/rootston/seat.c +++ b/rootston/seat.c @@ -241,16 +241,37 @@ static void roots_seat_init_cursor(struct roots_seat *seat) { seat->cursor->tool_tip.notify = handle_tool_tip; wl_signal_add(&seat->seat->events.request_set_cursor, - &seat->cursor->request_set_cursor); + &seat->cursor->request_set_cursor); seat->cursor->request_set_cursor.notify = handle_request_set_cursor; } +static void roots_seat_handle_new_drag_icon(struct wl_listener *listener, + void *data) { + struct roots_seat *seat = wl_container_of(listener, seat, new_drag_icon); + struct wlr_drag_icon *wlr_drag_icon = data; + + struct roots_drag_icon *icon = calloc(1, sizeof(struct roots_drag_icon)); + if (icon == NULL) { + return; + } + icon->seat = seat; + icon->wlr_drag_icon = wlr_drag_icon; + + icon->surface_commit.notify = roots_drag_icon_handle_surface_commit; + wl_signal_add(&wlr_drag_icon->events.surface_commit, &icon->surface_commit); + icon->map.notify = roots_drag_icon_handle_map; + wl_signal_add(&wlr_drag_icon->events.map, &icon->map); + icon->destroy.notify = roots_drag_icon_handle_destroy; + wl_signal_add(&wlr_drag_icon->events.destroy, &icon->destroy); + + wl_list_insert(&seat->drag_icons, &icon->link); +} + static void seat_view_destroy(struct roots_seat_view *seat_view); -static void roots_seat_handle_seat_destroy(struct wl_listener *listener, +static void roots_seat_handle_destroy(struct wl_listener *listener, void *data) { - struct roots_seat *seat = - wl_container_of(listener, seat, seat_destroy); + struct roots_seat *seat = wl_container_of(listener, seat, destroy); // TODO: probably more to be freed here wl_list_remove(&seat->seat_destroy.link); @@ -262,7 +283,7 @@ static void roots_seat_handle_seat_destroy(struct wl_listener *listener, } void roots_seat_destroy(struct roots_seat *seat) { - roots_seat_handle_seat_destroy(&seat->seat_destroy, seat->seat); + roots_seat_handle_destroy(&seat->destroy, seat->seat); wlr_seat_destroy(seat->seat); } @@ -277,6 +298,7 @@ struct roots_seat *roots_seat_create(struct roots_input *input, char *name) { wl_list_init(&seat->touch); wl_list_init(&seat->tablet_tools); wl_list_init(&seat->views); + wl_list_init(&seat->drag_icons); seat->input = input; @@ -295,8 +317,10 @@ struct roots_seat *roots_seat_create(struct roots_input *input, char *name) { wl_list_insert(&input->seats, &seat->link); - seat->seat_destroy.notify = roots_seat_handle_seat_destroy; - wl_signal_add(&seat->seat->events.destroy, &seat->seat_destroy); + seat->new_drag_icon.notify = roots_seat_handle_new_drag_icon; + wl_signal_add(&seat->seat->events.new_drag_icon, &seat->new_drag_icon); + seat->destroy.notify = roots_seat_handle_seat_destroy; + wl_signal_add(&seat->seat->events.destroy, &seat->destroy); return seat; } diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c index 5a6bc198..243c460d 100644 --- a/types/wlr_data_device.c +++ b/types/wlr_data_device.c @@ -454,6 +454,7 @@ static void wlr_drag_end(struct wlr_drag *drag) { if (drag->icon) { drag->icon->mapped = false; wl_list_remove(&drag->icon_destroy.link); + wl_signal_emit(&drag->icon->events.map, drag->icon); } free(drag); @@ -673,8 +674,8 @@ static struct wlr_drag_icon *wlr_drag_icon_create( icon->is_pointer = is_pointer; icon->touch_id = touch_id; icon->mapped = true; - wl_list_insert(&client->seat->drag_icons, &icon->link); + wl_signal_init(&icon->events.map); wl_signal_init(&icon->events.destroy); wl_signal_add(&icon->surface->events.destroy, &icon->surface_destroy); @@ -686,6 +687,9 @@ static struct wlr_drag_icon *wlr_drag_icon_create( wl_signal_add(&client->events.destroy, &icon->seat_client_destroy); icon->seat_client_destroy.notify = handle_drag_icon_seat_client_destroy; + wl_list_insert(&client->seat->drag_icons, &icon->link); + wl_signal_emit(&client->seat->events.new_drag_icon, icon); + return icon; } diff --git a/types/wlr_seat.c b/types/wlr_seat.c index 019cb567..79c4f6f6 100644 --- a/types/wlr_seat.c +++ b/types/wlr_seat.c @@ -454,7 +454,10 @@ struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) { wl_list_init(&wlr_seat->clients); wl_list_init(&wlr_seat->drag_icons); + wl_signal_init(&wlr_seat->events.new_drag_icon); + wl_signal_init(&wlr_seat->events.request_set_cursor); + wl_signal_init(&wlr_seat->events.selection); wl_signal_init(&wlr_seat->events.primary_selection); From 2ad7df868097d557ed3cc41dfa60e0637f8a08e8 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 23 Jan 2018 13:37:58 +0100 Subject: [PATCH 40/75] rootston: damage tracking for drag icons --- include/rootston/output.h | 5 ++ include/rootston/seat.h | 21 ++++++- include/wlr/types/wlr_data_device.h | 4 +- include/wlr/types/wlr_seat.h | 2 + rootston/cursor.c | 5 ++ rootston/output.c | 30 ++++----- rootston/seat.c | 97 ++++++++++++++++++++++++++--- types/wlr_data_device.c | 6 +- types/wlr_seat.c | 3 + 9 files changed, 142 insertions(+), 31 deletions(-) diff --git a/include/rootston/output.h b/include/rootston/output.h index 89fe1d82..81f20788 100644 --- a/include/rootston/output.h +++ b/include/rootston/output.h @@ -37,9 +37,14 @@ struct roots_output { void output_add_notify(struct wl_listener *listener, void *data); void output_remove_notify(struct wl_listener *listener, void *data); +struct roots_view; +struct roots_drag_icon; + void output_damage_whole_view(struct roots_output *output, struct roots_view *view); void output_damage_from_view(struct roots_output *output, struct roots_view *view); +void output_damage_whole_drag_icon(struct roots_output *output, + struct roots_drag_icon *icon); #endif diff --git a/include/rootston/seat.h b/include/rootston/seat.h index cf5dd3b2..4dec582e 100644 --- a/include/rootston/seat.h +++ b/include/rootston/seat.h @@ -17,12 +17,15 @@ struct roots_seat { struct wl_list views; // roots_seat_view::link bool has_focus; + struct wl_list drag_icons; // roots_drag_icon::link + struct wl_list keyboards; struct wl_list pointers; struct wl_list touch; struct wl_list tablet_tools; - struct wl_listener seat_destroy; + struct wl_listener new_drag_icon; + struct wl_listener destroy; }; struct roots_seat_view { @@ -33,6 +36,18 @@ struct roots_seat_view { struct wl_listener view_destroy; }; +struct roots_drag_icon { + struct roots_seat *seat; + struct wlr_drag_icon *wlr_drag_icon; + struct wl_list link; + + double x, y; + + struct wl_listener surface_commit; + struct wl_listener map; + struct wl_listener destroy; +}; + struct roots_pointer { struct roots_seat *seat; struct wlr_input_device *device; @@ -84,4 +99,8 @@ void roots_seat_begin_resize(struct roots_seat *seat, struct roots_view *view, void roots_seat_begin_rotate(struct roots_seat *seat, struct roots_view *view); +void roots_drag_icon_update_position(struct roots_drag_icon *icon); + +void roots_drag_icon_damage_whole(struct roots_drag_icon *icon); + #endif diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index 54514b4c..ff4a0f7e 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -71,10 +71,10 @@ struct wlr_drag_icon { bool is_pointer; int32_t touch_id; - int32_t sx; - int32_t sy; + int32_t sx, sy; struct { + struct wl_signal map; // emitted when mapped or unmapped struct wl_signal destroy; } events; diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index c2a89f33..ffdabd98 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -209,6 +209,8 @@ struct wlr_seat { struct wl_signal selection; struct wl_signal primary_selection; + struct wl_signal new_drag_icon; + struct wl_signal destroy; } events; diff --git a/rootston/cursor.c b/rootston/cursor.c index 8bd514cc..824cd917 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -58,6 +58,11 @@ static void roots_cursor_update_position(struct roots_cursor *cursor, } else { wlr_seat_pointer_clear_focus(seat->seat); } + + struct roots_drag_icon *drag_icon; + wl_list_for_each(drag_icon, &seat->drag_icons, link) { + roots_drag_icon_update_position(drag_icon); + } break; case ROOTS_CURSOR_MOVE: view = roots_seat_get_focus(seat); diff --git a/rootston/output.c b/rootston/output.c index b6879965..1b2a17d8 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -406,29 +406,15 @@ static void render_output(struct roots_output *output) { } // Render drag icons - struct wlr_drag_icon *drag_icon = NULL; + struct roots_drag_icon *drag_icon = NULL; struct roots_seat *seat = NULL; wl_list_for_each(seat, &server->input->seats, link) { - wl_list_for_each(drag_icon, &seat->seat->drag_icons, link) { - if (!drag_icon->mapped) { + wl_list_for_each(drag_icon, &seat->drag_icons, link) { + if (!drag_icon->wlr_drag_icon->mapped) { continue; } - struct wlr_surface *icon = drag_icon->surface; - struct wlr_cursor *cursor = seat->cursor->cursor; - double icon_x = 0, icon_y = 0; - if (drag_icon->is_pointer) { - icon_x = cursor->x + drag_icon->sx; - icon_y = cursor->y + drag_icon->sy; - render_surface(icon, icon_x, icon_y, 0, &data); - } else { - struct wlr_touch_point *point = - wlr_seat_touch_get_point(seat->seat, drag_icon->touch_id); - if (point) { - icon_x = seat->touch_x + drag_icon->sx; - icon_y = seat->touch_y + drag_icon->sy; - render_surface(icon, icon_x, icon_y, 0, &data); - } - } + render_surface(drag_icon->wlr_drag_icon->surface, + drag_icon->x, drag_icon->y, 0, &data); } } @@ -528,6 +514,12 @@ void output_damage_whole_view(struct roots_output *output, view_for_each_surface(view, damage_whole_surface, output); } +void output_damage_whole_drag_icon(struct roots_output *output, + struct roots_drag_icon *icon) { + surface_for_each_surface(icon->wlr_drag_icon->surface, icon->x, icon->y, 0, + damage_whole_surface, output); +} + static void damage_from_surface(struct wlr_surface *surface, double lx, double ly, float rotation, void *data) { struct roots_output *output = data; diff --git a/rootston/seat.c b/rootston/seat.c index 1a0e6253..e5f38b0b 100644 --- a/rootston/seat.c +++ b/rootston/seat.c @@ -241,19 +241,97 @@ static void roots_seat_init_cursor(struct roots_seat *seat) { seat->cursor->tool_tip.notify = handle_tool_tip; wl_signal_add(&seat->seat->events.request_set_cursor, - &seat->cursor->request_set_cursor); + &seat->cursor->request_set_cursor); seat->cursor->request_set_cursor.notify = handle_request_set_cursor; } +static void roots_drag_icon_handle_surface_commit(struct wl_listener *listener, + void *data) { + struct roots_drag_icon *icon = + wl_container_of(listener, icon, surface_commit); + roots_drag_icon_damage_whole(icon); +} + +static void roots_drag_icon_handle_map(struct wl_listener *listener, + void *data) { + struct roots_drag_icon *icon = + wl_container_of(listener, icon, map); + roots_drag_icon_damage_whole(icon); +} + +static void roots_drag_icon_handle_destroy(struct wl_listener *listener, + void *data) { + struct roots_drag_icon *icon = + wl_container_of(listener, icon, destroy); + roots_drag_icon_damage_whole(icon); + + wl_list_remove(&icon->link); + wl_list_remove(&icon->surface_commit.link); + wl_list_remove(&icon->map.link); + wl_list_remove(&icon->destroy.link); + free(icon); +} + +static void roots_seat_handle_new_drag_icon(struct wl_listener *listener, + void *data) { + struct roots_seat *seat = wl_container_of(listener, seat, new_drag_icon); + struct wlr_drag_icon *wlr_drag_icon = data; + + struct roots_drag_icon *icon = calloc(1, sizeof(struct roots_drag_icon)); + if (icon == NULL) { + return; + } + icon->seat = seat; + icon->wlr_drag_icon = wlr_drag_icon; + + icon->surface_commit.notify = roots_drag_icon_handle_surface_commit; + wl_signal_add(&wlr_drag_icon->surface->events.commit, &icon->surface_commit); + icon->map.notify = roots_drag_icon_handle_map; + wl_signal_add(&wlr_drag_icon->events.map, &icon->map); + icon->destroy.notify = roots_drag_icon_handle_destroy; + wl_signal_add(&wlr_drag_icon->events.destroy, &icon->destroy); + + wl_list_insert(&seat->drag_icons, &icon->link); +} + +void roots_drag_icon_update_position(struct roots_drag_icon *icon) { + roots_drag_icon_damage_whole(icon); + + struct wlr_drag_icon *wlr_icon = icon->wlr_drag_icon; + struct roots_seat *seat = icon->seat; + struct wlr_cursor *cursor = seat->cursor->cursor; + if (wlr_icon->is_pointer) { + icon->x = cursor->x + wlr_icon->sx; + icon->y = cursor->y + wlr_icon->sy; + } else { + struct wlr_touch_point *point = + wlr_seat_touch_get_point(seat->seat, wlr_icon->touch_id); + if (point == NULL) { + return; + } + icon->x = seat->touch_x + wlr_icon->sx; + icon->y = seat->touch_y + wlr_icon->sy; + } + + roots_drag_icon_damage_whole(icon); +} + +void roots_drag_icon_damage_whole(struct roots_drag_icon *icon) { + struct roots_output *output; + wl_list_for_each(output, &icon->seat->input->server->desktop->outputs, + link) { + output_damage_whole_drag_icon(output, icon); + } +} + static void seat_view_destroy(struct roots_seat_view *seat_view); -static void roots_seat_handle_seat_destroy(struct wl_listener *listener, +static void roots_seat_handle_destroy(struct wl_listener *listener, void *data) { - struct roots_seat *seat = - wl_container_of(listener, seat, seat_destroy); + struct roots_seat *seat = wl_container_of(listener, seat, destroy); // TODO: probably more to be freed here - wl_list_remove(&seat->seat_destroy.link); + wl_list_remove(&seat->destroy.link); struct roots_seat_view *view, *nview; wl_list_for_each_safe(view, nview, &seat->views, link) { @@ -262,7 +340,7 @@ static void roots_seat_handle_seat_destroy(struct wl_listener *listener, } void roots_seat_destroy(struct roots_seat *seat) { - roots_seat_handle_seat_destroy(&seat->seat_destroy, seat->seat); + roots_seat_handle_destroy(&seat->destroy, seat->seat); wlr_seat_destroy(seat->seat); } @@ -277,6 +355,7 @@ struct roots_seat *roots_seat_create(struct roots_input *input, char *name) { wl_list_init(&seat->touch); wl_list_init(&seat->tablet_tools); wl_list_init(&seat->views); + wl_list_init(&seat->drag_icons); seat->input = input; @@ -295,8 +374,10 @@ struct roots_seat *roots_seat_create(struct roots_input *input, char *name) { wl_list_insert(&input->seats, &seat->link); - seat->seat_destroy.notify = roots_seat_handle_seat_destroy; - wl_signal_add(&seat->seat->events.destroy, &seat->seat_destroy); + seat->new_drag_icon.notify = roots_seat_handle_new_drag_icon; + wl_signal_add(&seat->seat->events.new_drag_icon, &seat->new_drag_icon); + seat->destroy.notify = roots_seat_handle_destroy; + wl_signal_add(&seat->seat->events.destroy, &seat->destroy); return seat; } diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c index 5a6bc198..243c460d 100644 --- a/types/wlr_data_device.c +++ b/types/wlr_data_device.c @@ -454,6 +454,7 @@ static void wlr_drag_end(struct wlr_drag *drag) { if (drag->icon) { drag->icon->mapped = false; wl_list_remove(&drag->icon_destroy.link); + wl_signal_emit(&drag->icon->events.map, drag->icon); } free(drag); @@ -673,8 +674,8 @@ static struct wlr_drag_icon *wlr_drag_icon_create( icon->is_pointer = is_pointer; icon->touch_id = touch_id; icon->mapped = true; - wl_list_insert(&client->seat->drag_icons, &icon->link); + wl_signal_init(&icon->events.map); wl_signal_init(&icon->events.destroy); wl_signal_add(&icon->surface->events.destroy, &icon->surface_destroy); @@ -686,6 +687,9 @@ static struct wlr_drag_icon *wlr_drag_icon_create( wl_signal_add(&client->events.destroy, &icon->seat_client_destroy); icon->seat_client_destroy.notify = handle_drag_icon_seat_client_destroy; + wl_list_insert(&client->seat->drag_icons, &icon->link); + wl_signal_emit(&client->seat->events.new_drag_icon, icon); + return icon; } diff --git a/types/wlr_seat.c b/types/wlr_seat.c index 019cb567..79c4f6f6 100644 --- a/types/wlr_seat.c +++ b/types/wlr_seat.c @@ -454,7 +454,10 @@ struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) { wl_list_init(&wlr_seat->clients); wl_list_init(&wlr_seat->drag_icons); + wl_signal_init(&wlr_seat->events.new_drag_icon); + wl_signal_init(&wlr_seat->events.request_set_cursor); + wl_signal_init(&wlr_seat->events.selection); wl_signal_init(&wlr_seat->events.primary_selection); From 4223fbc76330f000a209c0f03426fd3867f21057 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 25 Jan 2018 19:15:20 +0100 Subject: [PATCH 41/75] rootston: damage tracking scale support --- include/wlr/util/region.h | 9 +++++++++ rootston/output.c | 8 +++++--- util/meson.build | 2 ++ util/region.c | 29 +++++++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 include/wlr/util/region.h create mode 100644 util/region.c diff --git a/include/wlr/util/region.h b/include/wlr/util/region.h new file mode 100644 index 00000000..416adbf2 --- /dev/null +++ b/include/wlr/util/region.h @@ -0,0 +1,9 @@ +#ifndef WLR_UTIL_REGION_H +#define WLR_UTIL_REGION_H + +#include + +void wlr_region_scale(pixman_region32_t *dst, pixman_region32_t *src, + float scale); + +#endif diff --git a/rootston/output.c b/rootston/output.c index 2283ad16..5f08edf1 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "rootston/server.h" #include "rootston/output.h" #include "rootston/config.h" @@ -186,7 +187,7 @@ static void render_surface(struct wlr_surface *surface, double lx, double ly, return; } - // TODO: output scale, output transform support + // TODO: output transform support pixman_region32_t damage; pixman_region32_init(&damage); pixman_region32_union_rect(&damage, &damage, box.x, box.y, @@ -257,7 +258,7 @@ static void render_decorations(struct roots_view *view, struct wlr_box box; get_decoration_box(view, output, &box); - // TODO: output scale, output transform support + // TODO: output transform support pixman_region32_t damage; pixman_region32_init(&damage); pixman_region32_union_rect(&damage, &damage, box.x, box.y, @@ -583,10 +584,11 @@ static void damage_from_surface(struct wlr_surface *surface, return; } - // TODO: output scale, output transform support + // TODO: output transform support pixman_region32_t damage; pixman_region32_init(&damage); pixman_region32_copy(&damage, &surface->current->surface_damage); + wlr_region_scale(&damage, &damage, output->wlr_output->scale); pixman_region32_translate(&damage, box.x, box.y); pixman_region32_union(&output->damage, &output->damage, &damage); pixman_region32_fini(&damage); diff --git a/util/meson.build b/util/meson.build index 21930693..6796f818 100644 --- a/util/meson.build +++ b/util/meson.build @@ -3,6 +3,8 @@ lib_wlr_util = static_library( files( 'log.c', 'os-compatibility.c', + 'region.c', ), include_directories: wlr_inc, + dependencies: [pixman], ) diff --git a/util/region.c b/util/region.c new file mode 100644 index 00000000..da66d92c --- /dev/null +++ b/util/region.c @@ -0,0 +1,29 @@ +#include +#include +#include + +void wlr_region_scale(pixman_region32_t *dst, pixman_region32_t *src, + float scale) { + if (scale == 1) { + pixman_region32_copy(dst, src); + return; + } + + int nrects; + pixman_box32_t *src_rects = pixman_region32_rectangles(src, &nrects); + + pixman_box32_t *dst_rects = malloc(nrects * sizeof(pixman_box32_t)); + if (dst_rects == NULL) { + return; + } + + for (int i = 0; i < nrects; ++i) { + dst_rects[i].x1 = floor(src_rects[i].x1 * scale); + dst_rects[i].x2 = ceil(src_rects[i].x2 * scale); + dst_rects[i].y1 = floor(src_rects[i].y1 * scale); + dst_rects[i].y2 = ceil(src_rects[i].y2 * scale); + } + + pixman_region32_fini(dst); + pixman_region32_init_rects(dst, dst_rects, nrects); +} From a98ece68d32031dbd81b0064fad659515fc09f76 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 25 Jan 2018 21:54:51 +0100 Subject: [PATCH 42/75] util: add docs for wlr_region_scale --- include/wlr/util/region.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/wlr/util/region.h b/include/wlr/util/region.h index 416adbf2..e268436b 100644 --- a/include/wlr/util/region.h +++ b/include/wlr/util/region.h @@ -3,6 +3,12 @@ #include +/** + * Scales a region, ie. multiplies all its coordinates by `scale`. + * + * The resulting coordinates are rounded up or down so that the new region is + * at least as big as the original one. + */ void wlr_region_scale(pixman_region32_t *dst, pixman_region32_t *src, float scale); From ece2c1e4e200192bde19a2590b5a31f244e09524 Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 26 Jan 2018 22:11:09 +0100 Subject: [PATCH 43/75] Damage tracking for transformed outputs --- backend/drm/drm.c | 15 +++--- backend/wayland/wl_seat.c | 12 +++-- include/rootston/output.h | 4 +- include/wlr/types/wlr_box.h | 8 +++- include/wlr/types/wlr_output.h | 3 +- include/wlr/util/region.h | 7 +++ rootston/output.c | 79 +++++++++++++++++------------- types/wlr_box.c | 45 +++++++++-------- types/wlr_output.c | 2 + types/wlr_surface.c | 88 +++------------------------------- util/meson.build | 2 +- util/region.c | 74 ++++++++++++++++++++++++++++ 12 files changed, 185 insertions(+), 154 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 4ba36bc4..5ab51e82 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -581,15 +581,14 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, } struct wlr_box hotspot = { - .width = plane->surf.width, - .height = plane->surf.height, .x = hotspot_x, .y = hotspot_y, }; enum wl_output_transform transform = wlr_output_transform_invert(output->transform); struct wlr_box transformed_hotspot; - wlr_box_transform(&hotspot, transform, &transformed_hotspot); + wlr_box_transform(&hotspot, transform, + plane->surf.width, plane->surf.height, &transformed_hotspot); plane->cursor_hotspot_x = transformed_hotspot.x; plane->cursor_hotspot_y = transformed_hotspot.y; @@ -650,15 +649,15 @@ static bool wlr_drm_connector_move_cursor(struct wlr_output *output, } struct wlr_drm_plane *plane = conn->crtc->cursor; - struct wlr_box box; - box.x = x; - box.y = y; - wlr_output_effective_resolution(output, &box.width, &box.height); + struct wlr_box box = { .x = x, .y = y }; + + int width, height; + wlr_output_effective_resolution(output, &width, &height); enum wl_output_transform transform = wlr_output_transform_invert(output->transform); struct wlr_box transformed_box; - wlr_box_transform(&box, transform, &transformed_box); + wlr_box_transform(&box, transform, width, height, &transformed_box); if (plane != NULL) { transformed_box.x -= plane->cursor_hotspot_x; diff --git a/backend/wayland/wl_seat.c b/backend/wayland/wl_seat.c index 90f7d44c..37489678 100644 --- a/backend/wayland/wl_seat.c +++ b/backend/wayland/wl_seat.c @@ -54,14 +54,16 @@ static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, struct wlr_output *wlr_output = &wlr_wl_pointer->current_output->wlr_output; - struct wlr_box box; + int width, height; wl_egl_window_get_attached_size(wlr_wl_pointer->current_output->egl_window, - &box.width, &box.height); - box.x = wl_fixed_to_int(surface_x); - box.y = wl_fixed_to_int(surface_y); + &width, &height); + struct wlr_box box = { + .x = wl_fixed_to_int(surface_x), + .y = wl_fixed_to_int(surface_y), + }; struct wlr_box transformed; - wlr_box_transform(&box, wlr_output->transform, &transformed); + wlr_box_transform(&box, wlr_output->transform, width, height, &transformed); transformed.x /= wlr_output->scale; transformed.y /= wlr_output->scale; diff --git a/include/rootston/output.h b/include/rootston/output.h index 81f20788..11f53d83 100644 --- a/include/rootston/output.h +++ b/include/rootston/output.h @@ -7,7 +7,7 @@ /** * Damage tracking requires to keep track of previous frames' damage. To allow - * damage tracking to work with triple buffering, an history of two frames is + * damage tracking to work with triple buffering, a history of two frames is * required. */ #define ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN 2 @@ -22,7 +22,7 @@ struct roots_output { struct roots_view *fullscreen_view; struct timespec last_frame; - pixman_region32_t damage; + pixman_region32_t damage; // in ouput-local coordinates bool frame_pending; // circular queue for previous damage diff --git a/include/wlr/types/wlr_box.h b/include/wlr/types/wlr_box.h index 0588201c..d6cc3509 100644 --- a/include/wlr/types/wlr_box.h +++ b/include/wlr/types/wlr_box.h @@ -2,6 +2,7 @@ #define WLR_TYPES_WLR_BOX_H #include +#include struct wlr_box { int x, y; @@ -18,8 +19,11 @@ bool wlr_box_contains_point(const struct wlr_box *box, double x, double y); bool wlr_box_empty(const struct wlr_box *box); -enum wl_output_transform; +/** + * Transforms a box inside a `width` x `height` box. + */ void wlr_box_transform(const struct wlr_box *box, - enum wl_output_transform transform, struct wlr_box *dest); + enum wl_output_transform transform, int width, int height, + struct wlr_box *dest); #endif diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 823c3b5e..4eefbf55 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -61,7 +61,8 @@ struct wlr_output { enum wl_output_transform transform; bool needs_swap; - pixman_region32_t damage; // damage for cursors and fullscreen surface + // damage for cursors and fullscreen surface, in output-local coordinates + pixman_region32_t damage; float transform_matrix[16]; struct { diff --git a/include/wlr/util/region.h b/include/wlr/util/region.h index e268436b..5d2b37e1 100644 --- a/include/wlr/util/region.h +++ b/include/wlr/util/region.h @@ -2,6 +2,7 @@ #define WLR_UTIL_REGION_H #include +#include /** * Scales a region, ie. multiplies all its coordinates by `scale`. @@ -12,4 +13,10 @@ void wlr_region_scale(pixman_region32_t *dst, pixman_region32_t *src, float scale); +/** + * Applies a transform to a region inside a box of size `width` x `height`. + */ +void wlr_region_transform(pixman_region32_t *dst, pixman_region32_t *src, + enum wl_output_transform transform, int width, int height); + #endif diff --git a/rootston/output.c b/rootston/output.c index 5f08edf1..c6341b6a 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -170,6 +170,39 @@ static bool surface_intersect_output(struct wlr_surface *surface, return wlr_output_layout_intersects(output_layout, wlr_output, &layout_box); } +static void output_get_transformed_size(struct wlr_output *wlr_output, + int *width, int *height) { + if (wlr_output->transform % 2 == 0) { + *width = wlr_output->width; + *height = wlr_output->height; + } else { + *width = wlr_output->height; + *height = wlr_output->width; + } +} + +static void scissor_output(struct roots_output *output, pixman_box32_t *rect) { + struct wlr_output *wlr_output = output->wlr_output; + + struct wlr_box box = { + .x = rect->x1, + .y = rect->y1, + .width = rect->x2 - rect->x1, + .height = rect->y2 - rect->y1, + }; + + int ow, oh; + output_get_transformed_size(output->wlr_output, &ow, &oh); + + // Scissor is in renderer coordinates, ie. upside down + enum wl_output_transform transform = wlr_output_transform_compose( + wlr_output_transform_invert(wlr_output->transform), + WL_OUTPUT_TRANSFORM_FLIPPED_180); + wlr_box_transform(&box, transform, ow, oh, &box); + + wlr_renderer_scissor(output->desktop->server->renderer, &box); +} + static void render_surface(struct wlr_surface *surface, double lx, double ly, float rotation, void *_data) { struct render_data *data = _data; @@ -187,7 +220,6 @@ static void render_surface(struct wlr_surface *surface, double lx, double ly, return; } - // TODO: output transform support pixman_region32_t damage; pixman_region32_init(&damage); pixman_region32_union_rect(&damage, &damage, box.x, box.y, @@ -205,16 +237,9 @@ static void render_surface(struct wlr_surface *surface, double lx, double ly, &output->wlr_output->transform_matrix); int nrects; - pixman_box32_t *rects = - pixman_region32_rectangles(&damage, &nrects); + pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); for (int i = 0; i < nrects; ++i) { - struct wlr_box scissor = { - .x = rects[i].x1, - .y = output->wlr_output->height - rects[i].y2, - .width = rects[i].x2 - rects[i].x1, - .height = rects[i].y2 - rects[i].y1, - }; - wlr_renderer_scissor(output->desktop->server->renderer, &scissor); + scissor_output(output, &rects[i]); wlr_render_with_matrix(output->desktop->server->renderer, surface->texture, &matrix); } @@ -258,7 +283,6 @@ static void render_decorations(struct roots_view *view, struct wlr_box box; get_decoration_box(view, output, &box); - // TODO: output transform support pixman_region32_t damage; pixman_region32_init(&damage); pixman_region32_union_rect(&damage, &damage, box.x, box.y, @@ -278,13 +302,7 @@ static void render_decorations(struct roots_view *view, pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); for (int i = 0; i < nrects; ++i) { - struct wlr_box scissor = { - .x = rects[i].x1, - .y = output->wlr_output->height - rects[i].y2, - .width = rects[i].x2 - rects[i].x1, - .height = rects[i].y2 - rects[i].y1, - }; - wlr_renderer_scissor(output->desktop->server->renderer, &scissor); + scissor_output(output, &rects[i]); wlr_render_colored_quad(output->desktop->server->renderer, &color, &matrix); } @@ -359,13 +377,15 @@ static void render_output(struct roots_output *output) { int buffer_age = -1; wlr_output_make_current(wlr_output, &buffer_age); + int width, height; + output_get_transformed_size(output->wlr_output, &width, &height); + // Check if we can use damage tracking pixman_region32_t damage; pixman_region32_init(&damage); if (buffer_age <= 0 || buffer_age - 1 > ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN) { // Buffer new or too old, damage the whole output - pixman_region32_union_rect(&damage, &damage, 0, 0, - wlr_output->width, wlr_output->height); + pixman_region32_union_rect(&damage, &damage, 0, 0, width, height); } else { pixman_region32_copy(&damage, &output->damage); @@ -376,8 +396,7 @@ static void render_output(struct roots_output *output) { pixman_region32_union(&damage, &damage, &output->previous_damage[j]); } } - pixman_region32_intersect_rect(&damage, &damage, 0, 0, - wlr_output->width, wlr_output->height); + pixman_region32_intersect_rect(&damage, &damage, 0, 0, width, height); if (!pixman_region32_not_empty(&damage) && !wlr_output->needs_swap) { // Output doesn't need swap and isn't damaged, skip rendering completely @@ -401,13 +420,7 @@ static void render_output(struct roots_output *output) { int nrects; pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); for (int i = 0; i < nrects; ++i) { - struct wlr_box scissor = { - .x = rects[i].x1, - .y = wlr_output->height - rects[i].y2, - .width = rects[i].x2 - rects[i].x1, - .height = rects[i].y2 - rects[i].y1, - }; - wlr_renderer_scissor(output->desktop->server->renderer, &scissor); + scissor_output(output, &rects[i]); wlr_renderer_clear(output->desktop->server->renderer, clear_color[0], clear_color[1], clear_color[2], 1); } @@ -491,8 +504,11 @@ static void schedule_render(struct roots_output *output) { } static void output_damage_whole(struct roots_output *output) { - pixman_region32_union_rect(&output->damage, &output->damage, - 0, 0, output->wlr_output->width, output->wlr_output->height); + int width, height; + output_get_transformed_size(output->wlr_output, &width, &height); + + pixman_region32_union_rect(&output->damage, &output->damage, 0, 0, + width, height); schedule_render(output); } @@ -584,7 +600,6 @@ static void damage_from_surface(struct wlr_surface *surface, return; } - // TODO: output transform support pixman_region32_t damage; pixman_region32_init(&damage); pixman_region32_copy(&damage, &surface->current->surface_damage); diff --git a/types/wlr_box.c b/types/wlr_box.c index 9afd7ef0..3217a7d0 100644 --- a/types/wlr_box.c +++ b/types/wlr_box.c @@ -67,47 +67,50 @@ bool wlr_box_contains_point(const struct wlr_box *box, double x, double y) { } void wlr_box_transform(const struct wlr_box *box, - enum wl_output_transform transform, struct wlr_box *dest) { + enum wl_output_transform transform, int width, int height, + struct wlr_box *dest) { + struct wlr_box src = *box; + if (transform % 2 == 0) { - dest->width = box->width; - dest->height = box->height; + dest->width = src.width; + dest->height = src.height; } else { - dest->width = box->height; - dest->height = box->width; + dest->width = src.height; + dest->height = src.width; } switch (transform) { case WL_OUTPUT_TRANSFORM_NORMAL: - dest->x = box->x; - dest->y = box->y; + dest->x = src.x; + dest->y = src.y; break; case WL_OUTPUT_TRANSFORM_90: - dest->x = box->y; - dest->y = box->width - box->x; + dest->x = src.y; + dest->y = width - src.x - src.width; break; case WL_OUTPUT_TRANSFORM_180: - dest->x = box->width - box->x; - dest->y = box->height - box->y; + dest->x = width - src.x - src.width; + dest->y = height - src.y - src.height; break; case WL_OUTPUT_TRANSFORM_270: - dest->x = box->height - box->y; - dest->y = box->x; + dest->x = height - src.y - src.height; + dest->y = src.x; break; case WL_OUTPUT_TRANSFORM_FLIPPED: - dest->x = box->width - box->x; - dest->y = box->y; + dest->x = width - src.x - src.width; + dest->y = src.y; break; case WL_OUTPUT_TRANSFORM_FLIPPED_90: - dest->x = box->height - box->y; - dest->y = box->width - box->x; + dest->x = height - src.y - src.height; + dest->y = width - src.x - src.width; break; case WL_OUTPUT_TRANSFORM_FLIPPED_180: - dest->x = box->x; - dest->y = box->height - box->y; + dest->x = src.x; + dest->y = height - src.y - src.height; break; case WL_OUTPUT_TRANSFORM_FLIPPED_270: - dest->x = box->y; - dest->y = box->x; + dest->x = src.y; + dest->y = src.x; break; } } diff --git a/types/wlr_output.c b/types/wlr_output.c index a6dc7f1b..f23f1749 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -14,6 +14,7 @@ #include #include #include +#include static void wl_output_send_to_resource(struct wl_resource *resource) { assert(resource); @@ -554,6 +555,7 @@ static void output_fullscreen_surface_handle_commit( pixman_region32_t damage; pixman_region32_init(&damage); pixman_region32_copy(&damage, &surface->current->surface_damage); + wlr_region_scale(&damage, &damage, output->scale); pixman_region32_translate(&damage, box.x, box.y); pixman_region32_union(&output->damage, &output->damage, &damage); pixman_region32_fini(&damage); diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 9896fe1b..abe830f4 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -185,85 +186,6 @@ static bool wlr_surface_update_size(struct wlr_surface *surface, return update_damage; } -static void wlr_surface_to_buffer_region(int scale, - enum wl_output_transform transform, pixman_region32_t *surface_region, - pixman_region32_t *buffer_region, int width, int height) { - int nrects; - pixman_box32_t *src_rects = - pixman_region32_rectangles(surface_region, &nrects); - pixman_box32_t *dest_rects = malloc(nrects * sizeof(*dest_rects)); - if (dest_rects == NULL) { - return; - } - - for (int i = 0; i < nrects; i++) { - switch (transform) { - default: - case WL_OUTPUT_TRANSFORM_NORMAL: - dest_rects[i].x1 = src_rects[i].x1; - dest_rects[i].y1 = src_rects[i].y1; - dest_rects[i].x2 = src_rects[i].x2; - dest_rects[i].y2 = src_rects[i].y2; - break; - case WL_OUTPUT_TRANSFORM_90: - dest_rects[i].x1 = height - src_rects[i].y2; - dest_rects[i].y1 = src_rects[i].x1; - dest_rects[i].x2 = height - src_rects[i].y1; - dest_rects[i].y2 = src_rects[i].x2; - break; - case WL_OUTPUT_TRANSFORM_180: - dest_rects[i].x1 = width - src_rects[i].x2; - dest_rects[i].y1 = height - src_rects[i].y2; - dest_rects[i].x2 = width - src_rects[i].x1; - dest_rects[i].y2 = height - src_rects[i].y1; - break; - case WL_OUTPUT_TRANSFORM_270: - dest_rects[i].x1 = src_rects[i].y1; - dest_rects[i].y1 = width - src_rects[i].x2; - dest_rects[i].x2 = src_rects[i].y2; - dest_rects[i].y2 = width - src_rects[i].x1; - break; - case WL_OUTPUT_TRANSFORM_FLIPPED: - dest_rects[i].x1 = width - src_rects[i].x2; - dest_rects[i].y1 = src_rects[i].y1; - dest_rects[i].x2 = width - src_rects[i].x1; - dest_rects[i].y2 = src_rects[i].y2; - break; - case WL_OUTPUT_TRANSFORM_FLIPPED_90: - dest_rects[i].x1 = height - src_rects[i].y2; - dest_rects[i].y1 = width - src_rects[i].x2; - dest_rects[i].x2 = height - src_rects[i].y1; - dest_rects[i].y2 = width - src_rects[i].x1; - break; - case WL_OUTPUT_TRANSFORM_FLIPPED_180: - dest_rects[i].x1 = src_rects[i].x1; - dest_rects[i].y1 = height - src_rects[i].y2; - dest_rects[i].x2 = src_rects[i].x2; - dest_rects[i].y2 = height - src_rects[i].y1; - break; - case WL_OUTPUT_TRANSFORM_FLIPPED_270: - dest_rects[i].x1 = src_rects[i].y1; - dest_rects[i].y1 = src_rects[i].x1; - dest_rects[i].x2 = src_rects[i].y2; - dest_rects[i].y2 = src_rects[i].x2; - break; - } - } - - if (scale != 1) { - for (int i = 0; i < nrects; i++) { - dest_rects[i].x1 *= scale; - dest_rects[i].x2 *= scale; - dest_rects[i].y1 *= scale; - dest_rects[i].y2 *= scale; - } - } - - pixman_region32_fini(buffer_region); - pixman_region32_init_rects(buffer_region, dest_rects, nrects); - free(dest_rects); -} - /** * Append pending state to current state and clear pending state. */ @@ -314,9 +236,11 @@ static void wlr_surface_move_state(struct wlr_surface *surface, if (update_damage) { pixman_region32_t buffer_damage; pixman_region32_init(&buffer_damage); - wlr_surface_to_buffer_region(state->scale, state->transform, - &state->surface_damage, &buffer_damage, state->width, - state->height); + pixman_region32_copy(&buffer_damage, &state->surface_damage); + wlr_region_transform(&buffer_damage, &buffer_damage, + wlr_output_transform_invert(state->transform), + state->width, state->height); + wlr_region_scale(&buffer_damage, &buffer_damage, state->scale); pixman_region32_union(&state->buffer_damage, &state->buffer_damage, &buffer_damage); pixman_region32_fini(&buffer_damage); diff --git a/util/meson.build b/util/meson.build index 6796f818..34aa428b 100644 --- a/util/meson.build +++ b/util/meson.build @@ -6,5 +6,5 @@ lib_wlr_util = static_library( 'region.c', ), include_directories: wlr_inc, - dependencies: [pixman], + dependencies: [wayland_server, pixman], ) diff --git a/util/region.c b/util/region.c index da66d92c..9c4712f9 100644 --- a/util/region.c +++ b/util/region.c @@ -26,4 +26,78 @@ void wlr_region_scale(pixman_region32_t *dst, pixman_region32_t *src, pixman_region32_fini(dst); pixman_region32_init_rects(dst, dst_rects, nrects); + free(dst_rects); +} + +void wlr_region_transform(pixman_region32_t *dst, pixman_region32_t *src, + enum wl_output_transform transform, int width, int height) { + if (transform == WL_OUTPUT_TRANSFORM_NORMAL) { + pixman_region32_copy(dst, src); + return; + } + + int nrects; + pixman_box32_t *src_rects = pixman_region32_rectangles(src, &nrects); + + pixman_box32_t *dst_rects = malloc(nrects * sizeof(pixman_box32_t)); + if (dst_rects == NULL) { + return; + } + + for (int i = 0; i < nrects; ++i) { + switch (transform) { + case WL_OUTPUT_TRANSFORM_NORMAL: + dst_rects[i].x1 = src_rects[i].x1; + dst_rects[i].y1 = src_rects[i].y1; + dst_rects[i].x2 = src_rects[i].x2; + dst_rects[i].y2 = src_rects[i].y2; + break; + case WL_OUTPUT_TRANSFORM_90: + dst_rects[i].x1 = src_rects[i].y1; + dst_rects[i].y1 = width - src_rects[i].x2; + dst_rects[i].x2 = src_rects[i].y2; + dst_rects[i].y2 = width - src_rects[i].x1; + break; + case WL_OUTPUT_TRANSFORM_180: + dst_rects[i].x1 = width - src_rects[i].x2; + dst_rects[i].y1 = height - src_rects[i].y2; + dst_rects[i].x2 = width - src_rects[i].x1; + dst_rects[i].y2 = height - src_rects[i].y1; + break; + case WL_OUTPUT_TRANSFORM_270: + dst_rects[i].x1 = height - src_rects[i].y2; + dst_rects[i].y1 = src_rects[i].x1; + dst_rects[i].x2 = height - src_rects[i].y1; + dst_rects[i].y2 = src_rects[i].x2; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED: + dst_rects[i].x1 = width - src_rects[i].x2; + dst_rects[i].y1 = src_rects[i].y1; + dst_rects[i].x2 = width - src_rects[i].x1; + dst_rects[i].y2 = src_rects[i].y2; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_90: + dst_rects[i].x1 = height - src_rects[i].y2; + dst_rects[i].y1 = width - src_rects[i].x2; + dst_rects[i].x2 = height - src_rects[i].y1; + dst_rects[i].y2 = width - src_rects[i].x1; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_180: + dst_rects[i].x1 = src_rects[i].x1; + dst_rects[i].y1 = height - src_rects[i].y2; + dst_rects[i].x2 = src_rects[i].x2; + dst_rects[i].y2 = height - src_rects[i].y1; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_270: + dst_rects[i].x1 = src_rects[i].y1; + dst_rects[i].y1 = src_rects[i].x1; + dst_rects[i].x2 = src_rects[i].y2; + dst_rects[i].y2 = src_rects[i].x2; + break; + } + } + + pixman_region32_fini(dst); + pixman_region32_init_rects(dst, dst_rects, nrects); + free(dst_rects); } From 8d58ed502b6022e6a5e99bca98f6c45cc6deba0a Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 26 Jan 2018 22:39:23 +0100 Subject: [PATCH 44/75] output: add wlr_output_schedule_frame --- backend/drm/drm.c | 2 +- backend/headless/output.c | 2 +- backend/wayland/output.c | 8 ++++---- backend/x11/backend.c | 4 ++-- include/rootston/output.h | 1 - include/wlr/interfaces/wlr_output.h | 1 + include/wlr/types/wlr_output.h | 6 ++++++ rootston/output.c | 26 ++++---------------------- types/wlr_output.c | 22 ++++++++++++++++++++++ 9 files changed, 41 insertions(+), 31 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 5ab51e82..c3ff0d55 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -881,7 +881,7 @@ static void page_flip_handler(int fd, unsigned seq, } if (drm->session->active) { - wl_signal_emit(&conn->output.events.frame, &conn->output); + wlr_output_send_frame(&conn->output); } } diff --git a/backend/headless/output.c b/backend/headless/output.c index a9a538ed..46f9d212 100644 --- a/backend/headless/output.c +++ b/backend/headless/output.c @@ -85,7 +85,7 @@ bool wlr_output_is_headless(struct wlr_output *wlr_output) { static int signal_frame(void *data) { struct wlr_headless_output *output = data; - wl_signal_emit(&output->wlr_output.events.frame, &output->wlr_output); + wlr_output_send_frame(&output->wlr_output); wl_event_source_timer_update(output->frame_timer, output->frame_delay); return 0; } diff --git a/backend/wayland/output.c b/backend/wayland/output.c index 5de18d41..4fec1955 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -17,11 +17,11 @@ int os_create_anonymous_file(off_t size); static struct wl_callback_listener frame_listener; -static void surface_frame_callback(void *data, struct wl_callback *cb, uint32_t time) { +static void surface_frame_callback(void *data, struct wl_callback *cb, + uint32_t time) { struct wlr_wl_backend_output *output = data; - struct wlr_output *wlr_output = (struct wlr_output *)output; - assert(wlr_output); - wl_signal_emit(&wlr_output->events.frame, wlr_output); + assert(output); + wlr_output_send_frame(&output->wlr_output); wl_callback_destroy(cb); output->frame_callback = NULL; } diff --git a/backend/x11/backend.c b/backend/x11/backend.c index b9ea7d0f..ae7c13be 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -44,7 +44,7 @@ static bool handle_x11_event(struct wlr_x11_backend *x11, xcb_generic_event_t *e switch (event->response_type) { case XCB_EXPOSE: { - wl_signal_emit(&output->wlr_output.events.frame, output); + wlr_output_send_frame(&output->wlr_output); break; } case XCB_KEY_PRESS: @@ -174,7 +174,7 @@ static int x11_event(int fd, uint32_t mask, void *data) { static int signal_frame(void *data) { struct wlr_x11_backend *x11 = data; - wl_signal_emit(&x11->output.wlr_output.events.frame, &x11->output); + wlr_output_send_frame(&x11->output.wlr_output); wl_event_source_timer_update(x11->frame_timer, 16); return 0; } diff --git a/include/rootston/output.h b/include/rootston/output.h index 11f53d83..a9f9bc2b 100644 --- a/include/rootston/output.h +++ b/include/rootston/output.h @@ -23,7 +23,6 @@ struct roots_output { struct timespec last_frame; pixman_region32_t damage; // in ouput-local coordinates - bool frame_pending; // circular queue for previous damage pixman_region32_t previous_damage[ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN]; diff --git a/include/wlr/interfaces/wlr_output.h b/include/wlr/interfaces/wlr_output.h index f2b65066..652be45e 100644 --- a/include/wlr/interfaces/wlr_output.h +++ b/include/wlr/interfaces/wlr_output.h @@ -33,5 +33,6 @@ void wlr_output_update_custom_mode(struct wlr_output *output, int32_t width, int32_t height, int32_t refresh); void wlr_output_update_enabled(struct wlr_output *output, bool enabled); void wlr_output_update_needs_swap(struct wlr_output *output); +void wlr_output_send_frame(struct wlr_output *output); #endif diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 4eefbf55..7e9439af 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -63,6 +63,7 @@ struct wlr_output { bool needs_swap; // damage for cursors and fullscreen surface, in output-local coordinates pixman_region32_t damage; + bool frame_pending; float transform_matrix[16]; struct { @@ -123,6 +124,11 @@ bool wlr_output_make_current(struct wlr_output *output, int *buffer_age); */ bool wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when, pixman_region32_t *damage); +/** + * Manually schedules a `frame` event. If a `frame` event is already pending, + * it is a no-op. + */ +void wlr_output_schedule_frame(struct wlr_output *output); void wlr_output_set_gamma(struct wlr_output *output, uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b); uint32_t wlr_output_get_gamma_size(struct wlr_output *output); diff --git a/rootston/output.c b/rootston/output.c index c6341b6a..f928184b 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -338,7 +338,6 @@ static void render_output(struct roots_output *output) { struct roots_server *server = desktop->server; if (!wlr_output->enabled) { - output->frame_pending = false; return; } @@ -400,7 +399,6 @@ static void render_output(struct roots_output *output) { if (!pixman_region32_not_empty(&damage) && !wlr_output->needs_swap) { // Output doesn't need swap and isn't damaged, skip rendering completely - output->frame_pending = false; goto damage_finish; } @@ -470,7 +468,6 @@ renderer_end: wlr_renderer_scissor(output->desktop->server->renderer, NULL); wlr_renderer_end(server->renderer); wlr_output_swap_buffers(wlr_output, &now, &damage); - output->frame_pending = true; // same as decrementing, but works on unsigned integers output->previous_damage_idx += ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN - 1; output->previous_damage_idx %= ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN; @@ -488,21 +485,6 @@ static void output_handle_frame(struct wl_listener *listener, void *data) { render_output(output); } -static void handle_idle_render(void *data) { - struct roots_output *output = data; - render_output(output); -} - -static void schedule_render(struct roots_output *output) { - if (!output->frame_pending) { - // TODO: ask the backend to send a frame event when appropriate instead - struct wl_event_loop *ev = - wl_display_get_event_loop(output->desktop->server->wl_display); - wl_event_loop_add_idle(ev, handle_idle_render, output); - output->frame_pending = true; - } -} - static void output_damage_whole(struct roots_output *output) { int width, height; output_get_transformed_size(output->wlr_output, &width, &height); @@ -510,7 +492,7 @@ static void output_damage_whole(struct roots_output *output) { pixman_region32_union_rect(&output->damage, &output->damage, 0, 0, width, height); - schedule_render(output); + wlr_output_schedule_frame(output->wlr_output); } static bool view_accept_damage(struct roots_output *output, @@ -553,7 +535,7 @@ static void damage_whole_surface(struct wlr_surface *surface, pixman_region32_union_rect(&output->damage, &output->damage, box.x, box.y, box.width, box.height); - schedule_render(output); + wlr_output_schedule_frame(output->wlr_output); } static void damage_whole_decoration(struct roots_view *view, @@ -608,7 +590,7 @@ static void damage_from_surface(struct wlr_surface *surface, pixman_region32_union(&output->damage, &output->damage, &damage); pixman_region32_fini(&damage); - schedule_render(output); + wlr_output_schedule_frame(output->wlr_output); } void output_damage_from_view(struct roots_output *output, @@ -630,7 +612,7 @@ static void output_handle_needs_swap(struct wl_listener *listener, void *data) { wl_container_of(listener, output, needs_swap); pixman_region32_union(&output->damage, &output->damage, &output->wlr_output->damage); - schedule_render(output); + wlr_output_schedule_frame(output->wlr_output); } static void set_mode(struct wlr_output *output, diff --git a/types/wlr_output.c b/types/wlr_output.c index f23f1749..5676b0a8 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -499,6 +499,7 @@ bool wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when, return false; } + output->frame_pending = true; output->needs_swap = false; pixman_region32_clear(&output->damage); @@ -509,6 +510,27 @@ bool wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when, return true; } +void wlr_output_send_frame(struct wlr_output *output) { + output->frame_pending = false; + wl_signal_emit(&output->events.frame, output); +} + +static void schedule_frame_handle_idle_timer(void *data) { + struct wlr_output *output = data; + wlr_output_send_frame(output); +} + +void wlr_output_schedule_frame(struct wlr_output *output) { + if (output->frame_pending) { + return; + } + + // TODO: ask the backend to send a frame event when appropriate instead + struct wl_event_loop *ev = wl_display_get_event_loop(output->display); + wl_event_loop_add_idle(ev, schedule_frame_handle_idle_timer, output); + output->frame_pending = true; +} + void wlr_output_set_gamma(struct wlr_output *output, uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b) { if (output->impl->set_gamma) { From a011a1cb075bed2235162f1af7e88d0ee534acad Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 26 Jan 2018 22:41:19 +0100 Subject: [PATCH 45/75] screenshooter: request a buffer swap --- types/wlr_screenshooter.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/types/wlr_screenshooter.c b/types/wlr_screenshooter.c index e24b85f1..0ee01519 100644 --- a/types/wlr_screenshooter.c +++ b/types/wlr_screenshooter.c @@ -138,6 +138,10 @@ static void screenshooter_shoot(struct wl_client *client, state->screenshot = screenshot; state->frame_listener.notify = output_frame_notify; wl_signal_add(&output->events.swap_buffers, &state->frame_listener); + + // Schedule a buffer swap + output->needs_swap = true; + wlr_output_schedule_frame(output); } static struct orbital_screenshooter_interface screenshooter_impl = { From 7111dd79efb6cccf39866051a92090cfc9ea5c67 Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 27 Jan 2018 10:43:17 +0100 Subject: [PATCH 46/75] rootston: damage tracking for rotated views --- include/rootston/view.h | 1 + include/wlr/types/wlr_box.h | 6 ++++++ rootston/cursor.c | 2 +- rootston/desktop.c | 18 ++++++++++++++---- rootston/output.c | 31 +++++++++++++++++++++++-------- types/wlr_box.c | 29 +++++++++++++++++++++++++++++ 6 files changed, 74 insertions(+), 13 deletions(-) diff --git a/include/rootston/view.h b/include/rootston/view.h index 35660d64..c9d1deb2 100644 --- a/include/rootston/view.h +++ b/include/rootston/view.h @@ -164,6 +164,7 @@ void view_move_resize(struct roots_view *view, double x, double y, void view_maximize(struct roots_view *view, bool maximized); void view_set_fullscreen(struct roots_view *view, bool fullscreen, struct wlr_output *output); +void view_rotate(struct roots_view *view, float rotation); void view_close(struct roots_view *view); bool view_center(struct roots_view *view); void view_setup(struct roots_view *view); diff --git a/include/wlr/types/wlr_box.h b/include/wlr/types/wlr_box.h index d6cc3509..fc86f0ac 100644 --- a/include/wlr/types/wlr_box.h +++ b/include/wlr/types/wlr_box.h @@ -26,4 +26,10 @@ void wlr_box_transform(const struct wlr_box *box, enum wl_output_transform transform, int width, int height, struct wlr_box *dest); +/** + * Creates the smallest box that contains a rotated box. + */ +void wlr_box_rotated_bounds(const struct wlr_box *box, float rotation, + struct wlr_box *dest); + #endif diff --git a/rootston/cursor.c b/rootston/cursor.c index a09211b7..158c4708 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -203,7 +203,7 @@ static void roots_cursor_update_position(struct roots_cursor *cursor, float angle = atan2(vx*uy - vy*ux, vx*ux + vy*uy); int steps = 12; angle = round(angle/M_PI*steps) / (steps/M_PI); - view->rotation = cursor->view_rotation + angle; + view_rotate(view, cursor->view_rotation + angle); } break; } diff --git a/rootston/desktop.c b/rootston/desktop.c index b2d586f4..25930d2a 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -200,7 +200,7 @@ void view_maximize(struct roots_view *view, bool maximized) { view_move_resize(view, output_box->x, output_box->y, output_box->width, output_box->height); - view->rotation = 0; + view_rotate(view, 0); } if (view->maximized && !maximized) { @@ -208,7 +208,7 @@ void view_maximize(struct roots_view *view, bool maximized) { view_move_resize(view, view->saved.x, view->saved.y, view->saved.width, view->saved.height); - view->rotation = view->saved.rotation; + view_rotate(view, view->saved.rotation); } } @@ -249,7 +249,7 @@ void view_set_fullscreen(struct roots_view *view, bool fullscreen, wlr_output_layout_get_box(view->desktop->layout, output); view_move_resize(view, output_box->x, output_box->y, output_box->width, output_box->height); - view->rotation = 0; + view_rotate(view, 0); roots_output->fullscreen_view = view; view->fullscreen_output = roots_output; @@ -258,13 +258,23 @@ void view_set_fullscreen(struct roots_view *view, bool fullscreen, if (was_fullscreen && !fullscreen) { view_move_resize(view, view->saved.x, view->saved.y, view->saved.width, view->saved.height); - view->rotation = view->saved.rotation; + view_rotate(view, view->saved.rotation); view->fullscreen_output->fullscreen_view = NULL; view->fullscreen_output = NULL; } } +void view_rotate(struct roots_view *view, float rotation) { + if (view->rotation == rotation) { + return; + } + + view_damage_whole(view); + view->rotation = rotation; + view_damage_whole(view); +} + void view_close(struct roots_view *view) { if (view->close) { view->close(view); diff --git a/rootston/output.c b/rootston/output.c index f928184b..d4cd1efd 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -155,7 +155,7 @@ struct render_data { */ static bool surface_intersect_output(struct wlr_surface *surface, struct wlr_output_layout *output_layout, struct wlr_output *wlr_output, - double lx, double ly, struct wlr_box *box) { + double lx, double ly, float rotation, struct wlr_box *box) { double ox = lx, oy = ly; wlr_output_layout_output_coords(output_layout, wlr_output, &ox, &oy); box->x = ox * wlr_output->scale; @@ -167,6 +167,7 @@ static bool surface_intersect_output(struct wlr_surface *surface, .x = lx, .y = ly, .width = surface->current->width, .height = surface->current->height, }; + wlr_box_rotated_bounds(&layout_box, -rotation, &layout_box); return wlr_output_layout_intersects(output_layout, wlr_output, &layout_box); } @@ -215,15 +216,18 @@ static void render_surface(struct wlr_surface *surface, double lx, double ly, struct wlr_box box; bool intersects = surface_intersect_output(surface, output->desktop->layout, - output->wlr_output, lx, ly, &box); + output->wlr_output, lx, ly, rotation, &box); if (!intersects) { return; } + struct wlr_box rotated; + wlr_box_rotated_bounds(&box, -rotation, &rotated); + pixman_region32_t damage; pixman_region32_init(&damage); - pixman_region32_union_rect(&damage, &damage, box.x, box.y, - box.width, box.height); + pixman_region32_union_rect(&damage, &damage, rotated.x, rotated.y, + rotated.width, rotated.height); pixman_region32_intersect(&damage, &damage, data->damage); bool damaged = pixman_region32_not_empty(&damage); if (!damaged) { @@ -415,6 +419,8 @@ static void render_output(struct roots_output *output) { goto renderer_end; } + wlr_renderer_clear(output->desktop->server->renderer, 1, 1, 1, 1); + int nrects; pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); for (int i = 0; i < nrects; ++i) { @@ -526,12 +532,14 @@ static void damage_whole_surface(struct wlr_surface *surface, } struct wlr_box box; - bool intersects = surface_intersect_output(surface, - output->desktop->layout, output->wlr_output, lx, ly, &box); + bool intersects = surface_intersect_output(surface, output->desktop->layout, + output->wlr_output, lx, ly, rotation, &box); if (!intersects) { return; } + wlr_box_rotated_bounds(&box, -rotation, &box); + pixman_region32_union_rect(&output->damage, &output->damage, box.x, box.y, box.width, box.height); @@ -547,6 +555,8 @@ static void damage_whole_decoration(struct roots_view *view, struct wlr_box box; get_decoration_box(view, output, &box); + wlr_box_rotated_bounds(&box, -view->rotation, &box); + pixman_region32_union_rect(&output->damage, &output->damage, box.x, box.y, box.width, box.height); } @@ -576,8 +586,8 @@ static void damage_from_surface(struct wlr_surface *surface, } struct wlr_box box; - bool intersects = surface_intersect_output(surface, - output->desktop->layout, output->wlr_output, lx, ly, &box); + bool intersects = surface_intersect_output(surface, output->desktop->layout, + output->wlr_output, lx, ly, rotation, &box); if (!intersects) { return; } @@ -599,6 +609,11 @@ void output_damage_from_view(struct roots_output *output, return; } + if (view->rotation != 0) { + output_damage_whole_view(output, view); + return; + } + view_for_each_surface(view, damage_from_surface, output); } diff --git a/types/wlr_box.c b/types/wlr_box.c index 3217a7d0..a7388209 100644 --- a/types/wlr_box.c +++ b/types/wlr_box.c @@ -114,3 +114,32 @@ void wlr_box_transform(const struct wlr_box *box, break; } } + +void wlr_box_rotated_bounds(const struct wlr_box *box, float rotation, + struct wlr_box *dest) { + if (rotation == 0) { + *dest = *box; + return; + } + + double ox = box->x + (double)box->width/2; + double oy = box->y + (double)box->height/2; + + double c = fabs(cos(rotation)); + double s = fabs(sin(rotation)); + + double x1 = ox + (box->x - ox) * c + (box->y - oy) * s; + double x2 = ox + + (box->x + box->width - ox) * c + + (box->y + box->height - oy) * s; + + double y1 = oy + (box->x - ox) * s + (box->y - oy) * c; + double y2 = oy + + (box->x + box->width - ox) * s + + (box->y + box->height - oy) * c; + + dest->x = fmin(x1, x2); + dest->width = fmax(x1, x2) - fmin(x1, x2); + dest->y = fmin(y1, y2); + dest->height = fmax(y1, y2) - fmin(y1, y2); +} From 7adf13e2840bf57a2b96b73462fc7c6ca8e363da Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 27 Jan 2018 11:16:42 +0100 Subject: [PATCH 47/75] Fix flickering when switching VT --- backend/drm/drm.c | 10 ++++++++++ rootston/output.c | 2 -- types/wlr_output.c | 5 ----- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index c3ff0d55..b9aae948 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -192,6 +192,9 @@ static bool wlr_drm_connector_make_current(struct wlr_output *output, static bool wlr_drm_connector_swap_buffers(struct wlr_output *output) { struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; struct wlr_drm_backend *drm = (struct wlr_drm_backend *)output->backend; + if (!drm->session->active) { + return false; + } struct wlr_drm_crtc *crtc = conn->crtc; if (!crtc) { @@ -516,6 +519,10 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, struct wlr_drm_backend *drm = (struct wlr_drm_backend *)output->backend; struct wlr_drm_renderer *renderer = &drm->renderer; + if (!drm->session->active) { + return false; + } + struct wlr_drm_crtc *crtc = conn->crtc; if (!crtc) { return false; @@ -644,6 +651,9 @@ static bool wlr_drm_connector_move_cursor(struct wlr_output *output, int x, int y) { struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; struct wlr_drm_backend *drm = (struct wlr_drm_backend *)output->backend; + if (!drm->session->active) { + return false; + } if (!conn->crtc) { return false; } diff --git a/rootston/output.c b/rootston/output.c index d4cd1efd..a31462be 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -419,8 +419,6 @@ static void render_output(struct roots_output *output) { goto renderer_end; } - wlr_renderer_clear(output->desktop->server->renderer, 1, 1, 1, 1); - int nrects; pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); for (int i = 0; i < nrects; ++i) { diff --git a/types/wlr_output.c b/types/wlr_output.c index 5676b0a8..1f48f86d 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -184,11 +184,6 @@ void wlr_output_update_mode(struct wlr_output *output, void wlr_output_update_custom_mode(struct wlr_output *output, int32_t width, int32_t height, int32_t refresh) { - if (output->width == width && output->height == height && - output->refresh == refresh) { - return; - } - output->width = width; output->height = height; wlr_output_update_matrix(output); From 861d5bdff2e33e453fdddc26cdeef2233c2f8ea7 Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 27 Jan 2018 21:49:40 +0100 Subject: [PATCH 48/75] surface: fix damage when resizing a surface in QT apps --- types/wlr_surface.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/types/wlr_surface.c b/types/wlr_surface.c index abe830f4..f93b2563 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -169,14 +169,13 @@ static bool wlr_surface_update_size(struct wlr_surface *surface, wl_list_init(&state->frame_callback_list); bool update_damage = false; - if (width < state->width) { - pixman_region32_union_rect(&state->surface_damage, &state->surface_damage, - width, 0, state->width - width, state->height); - update_damage = true; - } - if (height < state->height) { - pixman_region32_union_rect(&state->surface_damage, &state->surface_damage, - 0, height, state->width, state->height - height); + if (width != state->width || height != state->height) { + // Damage the whole surface on resize + // This isn't in the spec, but Weston does it and QT expects it + pixman_region32_union_rect(&state->surface_damage, + &state->surface_damage, 0, 0, state->width, state->height); + pixman_region32_union_rect(&state->surface_damage, + &state->surface_damage, 0, 0, width, height); update_damage = true; } From 63736be2143a1821fe0b378e56c7e70f1f3cafec Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 28 Jan 2018 10:11:31 +0100 Subject: [PATCH 49/75] rootston: fix damage tracking for SSD --- include/rootston/desktop.h | 1 + include/rootston/view.h | 7 ++----- rootston/desktop.c | 25 +++++++++++++------------ rootston/wl_shell.c | 4 ++++ rootston/xdg_shell_v6.c | 15 +++++++++++---- rootston/xwayland.c | 7 +++++++ 6 files changed, 38 insertions(+), 21 deletions(-) diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h index 388fb55d..1232121a 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -69,6 +69,7 @@ void view_activate(struct roots_view *view, bool activate); void view_apply_damage(struct roots_view *view); void view_damage_whole(struct roots_view *view); void view_update_position(struct roots_view *view, double x, double y); +void view_update_size(struct roots_view *view, uint32_t width, uint32_t height); void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data); void handle_wl_shell_surface(struct wl_listener *listener, void *data); diff --git a/include/rootston/view.h b/include/rootston/view.h index c9d1deb2..9312c8c3 100644 --- a/include/rootston/view.h +++ b/include/rootston/view.h @@ -62,6 +62,7 @@ struct roots_view { struct wl_list link; // roots_desktop::views double x, y; + uint32_t width, height; float rotation; bool decorated; @@ -108,11 +109,7 @@ struct roots_view { struct wl_signal destroy; } events; - // TODO: This would probably be better as a field that's updated on a - // configure event from the xdg_shell - // If not then this should follow the typical type/impl pattern we use - // elsewhere - void (*get_size)(const struct roots_view *view, struct wlr_box *box); + // TODO: this should follow the typical type/impl pattern we use elsewhere void (*activate)(struct roots_view *view, bool active); void (*move)(struct roots_view *view, double x, double y); void (*resize)(struct roots_view *view, uint32_t width, uint32_t height); diff --git a/rootston/desktop.c b/rootston/desktop.c index 25930d2a..9abcfa33 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -24,18 +24,8 @@ void view_get_box(const struct roots_view *view, struct wlr_box *box) { box->x = view->x; box->y = view->y; - if (view->get_size) { - view->get_size(view, box); - } else { - if (view->wlr_surface == NULL) { - // View is unmapped - box->width = box->height = 0; - return; - } - - box->width = view->wlr_surface->current->width; - box->height = view->wlr_surface->current->height; - } + box->width = view->width; + box->height = view->height; } void view_get_deco_box(const struct roots_view *view, struct wlr_box *box) { @@ -469,6 +459,17 @@ void view_update_position(struct roots_view *view, double x, double y) { view_damage_whole(view); } +void view_update_size(struct roots_view *view, uint32_t width, uint32_t height) { + if (view->width == width && view->height == height) { + return; + } + + view_damage_whole(view); + view->width = width; + view->height = height; + view_damage_whole(view); +} + static bool view_at(struct roots_view *view, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { if (view->type == ROOTS_WL_SHELL_VIEW && diff --git a/rootston/wl_shell.c b/rootston/wl_shell.c index 1fc48452..267e2cf5 100644 --- a/rootston/wl_shell.c +++ b/rootston/wl_shell.c @@ -147,6 +147,8 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) { int width = wlr_surface->current->width; int height = wlr_surface->current->height; + view_update_size(view, width, height); + double x = view->x; double y = view->y; if (view->pending_move_resize.update_x) { @@ -231,6 +233,8 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) { return; } view->type = ROOTS_WL_SHELL_VIEW; + view->width = surface->surface->current->width; + view->height = surface->surface->current->height; view->wl_shell_surface = surface; view->roots_wl_shell_surface = roots_surface; diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c index 0a3ca72c..b354b77b 100644 --- a/rootston/xdg_shell_v6.c +++ b/rootston/xdg_shell_v6.c @@ -245,12 +245,13 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) { view_apply_damage(view); + struct wlr_box size; + get_size(view, &size); + view_update_size(view, size.width, size.height); + uint32_t pending_serial = roots_surface->pending_move_resize_configure_serial; if (pending_serial > 0 && pending_serial >= surface->configure_serial) { - struct wlr_box size; - get_size(view, &size); - double x = view->x; double y = view->y; if (view->pending_move_resize.update_x) { @@ -338,10 +339,10 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { return; } view->type = ROOTS_XDG_SHELL_V6_VIEW; + view->xdg_surface_v6 = surface; view->roots_xdg_surface_v6 = roots_surface; view->wlr_surface = surface->surface; - view->get_size = get_size; view->activate = activate; view->resize = resize; view->move_resize = move_resize; @@ -349,6 +350,12 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { view->set_fullscreen = set_fullscreen; view->close = close; roots_surface->view = view; + + struct wlr_box box; + get_size(view, &box); + view->width = box.width; + view->height = box.height; + view_init(view, desktop); wl_list_insert(&desktop->views, &view->link); diff --git a/rootston/xwayland.c b/rootston/xwayland.c index c0bc9ae7..a3e12d00 100644 --- a/rootston/xwayland.c +++ b/rootston/xwayland.c @@ -209,6 +209,8 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) { int width = wlr_surface->current->width; int height = wlr_surface->current->height; + view_update_size(view, width, height); + double x = view->x; double y = view->y; if (view->pending_move_resize.update_x) { @@ -234,6 +236,8 @@ static void handle_map_notify(struct wl_listener *listener, void *data) { view->wlr_surface = xsurface->surface; view->x = xsurface->x; view->y = xsurface->y; + view->width = xsurface->surface->current->width; + view->height = xsurface->surface->current->height; wl_list_insert(&desktop->views, &view->link); struct wlr_subsurface *subsurface; @@ -264,6 +268,7 @@ static void handle_unmap_notify(struct wl_listener *listener, void *data) { } view->wlr_surface = NULL; + view->width = view->height = 0; wl_list_remove(&view->link); } @@ -314,6 +319,8 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { view->type = ROOTS_XWAYLAND_VIEW; view->x = (double)surface->x; view->y = (double)surface->y; + view->width = surface->surface->current->width; + view->height = surface->surface->current->height; view->xwayland_surface = surface; view->roots_xwayland_surface = roots_surface; From 485aa8746865cc34ead2ef7e6cd76ed98ce89c47 Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 28 Jan 2018 10:40:38 +0100 Subject: [PATCH 50/75] output: fix fullscreen on transformed outputs --- types/wlr_output.c | 61 +++++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/types/wlr_output.c b/types/wlr_output.c index 1f48f86d..00590136 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -323,6 +323,37 @@ bool wlr_output_make_current(struct wlr_output *output, int *buffer_age) { return output->impl->make_current(output, buffer_age); } +static void output_get_transformed_size(struct wlr_output *output, + int *width, int *height) { + if (output->transform % 2 == 0) { + *width = output->width; + *height = output->height; + } else { + *width = output->height; + *height = output->width; + } +} + +static void output_scissor(struct wlr_output *output, pixman_box32_t *rect) { + struct wlr_box box = { + .x = rect->x1, + .y = rect->y1, + .width = rect->x2 - rect->x1, + .height = rect->y2 - rect->y1, + }; + + int ow, oh; + output_get_transformed_size(output, &ow, &oh); + + // Scissor is in renderer coordinates, ie. upside down + enum wl_output_transform transform = wlr_output_transform_compose( + wlr_output_transform_invert(output->transform), + WL_OUTPUT_TRANSFORM_FLIPPED_180); + wlr_box_transform(&box, transform, ow, oh, &box); + + glScissor(box.x, box.y, box.width, box.height); +} + static void output_fullscreen_surface_get_box(struct wlr_output *output, struct wlr_surface *surface, struct wlr_box *box) { int width, height; @@ -353,22 +384,17 @@ static void output_fullscreen_surface_render(struct wlr_output *output, struct wlr_box box; output_fullscreen_surface_get_box(output, surface, &box); - float translate[16]; - wlr_matrix_translate(&translate, box.x, box.y, 0); - - float scale[16]; - wlr_matrix_scale(&scale, box.width, box.height, 1); - float matrix[16]; - wlr_matrix_mul(&translate, &scale, &matrix); - wlr_matrix_mul(&output->transform_matrix, &matrix, &matrix); + enum wl_output_transform transform = + wlr_output_transform_invert(surface->current->transform); + wlr_matrix_project_box(&matrix, &box, transform, 0, + &output->transform_matrix); int nrects; pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); glEnable(GL_SCISSOR_TEST); for (int i = 0; i < nrects; ++i) { - glScissor(rects[i].x1, output->height - rects[i].y2, - rects[i].x2 - rects[i].x1, rects[i].y2 - rects[i].y1); + output_scissor(output, &rects[i]); glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); wlr_render_with_matrix(surface->renderer, surface->texture, &matrix); @@ -423,24 +449,15 @@ static void output_cursor_render(struct wlr_output_cursor *cursor, glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - float translate[16]; - wlr_matrix_translate(&translate, box.x, box.y, 0); - - float scale[16]; - wlr_matrix_scale(&scale, box.width, box.height, 1); - float matrix[16]; - wlr_matrix_mul(&translate, &scale, &matrix); - wlr_matrix_mul(&cursor->output->transform_matrix, &matrix, &matrix); - - wlr_render_with_matrix(renderer, texture, &matrix); + wlr_matrix_project_box(&matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0, + &cursor->output->transform_matrix); int nrects; pixman_box32_t *rects = pixman_region32_rectangles(&surface_damage, &nrects); glEnable(GL_SCISSOR_TEST); for (int i = 0; i < nrects; ++i) { - glScissor(rects[i].x1, cursor->output->height - rects[i].y2, - rects[i].x2 - rects[i].x1, rects[i].y2 - rects[i].y1); + output_scissor(cursor->output, &rects[i]); wlr_render_with_matrix(renderer, texture, &matrix); } glDisable(GL_SCISSOR_TEST); From 692d33bf8b752cc3b8a0b7f2b29c2b49dd4f718b Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 28 Jan 2018 12:14:23 +0100 Subject: [PATCH 51/75] rootston: fix clipped SSD for rotated views --- rootston/output.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/rootston/output.c b/rootston/output.c index a31462be..f0710b11 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -287,10 +287,13 @@ static void render_decorations(struct roots_view *view, struct wlr_box box; get_decoration_box(view, output, &box); + struct wlr_box rotated; + wlr_box_rotated_bounds(&box, -view->rotation, &rotated); + pixman_region32_t damage; pixman_region32_init(&damage); - pixman_region32_union_rect(&damage, &damage, box.x, box.y, - box.width, box.height); + pixman_region32_union_rect(&damage, &damage, rotated.x, rotated.y, + rotated.width, rotated.height); pixman_region32_intersect(&damage, &damage, data->damage); bool damaged = pixman_region32_not_empty(&damage); if (!damaged) { From e049610b47b2d6191e1b0feb72eda1431d12f37c Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 28 Jan 2018 21:29:51 +0100 Subject: [PATCH 52/75] surface: copy buffer damage to surface damage --- types/wlr_surface.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/types/wlr_surface.c b/types/wlr_surface.c index f93b2563..045e3670 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -233,16 +233,30 @@ static void wlr_surface_move_state(struct wlr_surface *surface, update_damage = true; } if (update_damage) { - pixman_region32_t buffer_damage; + pixman_region32_t buffer_damage, surface_damage; pixman_region32_init(&buffer_damage); + pixman_region32_init(&surface_damage); + + // Surface to buffer damage pixman_region32_copy(&buffer_damage, &state->surface_damage); wlr_region_transform(&buffer_damage, &buffer_damage, wlr_output_transform_invert(state->transform), state->width, state->height); wlr_region_scale(&buffer_damage, &buffer_damage, state->scale); - pixman_region32_union(&state->buffer_damage, - &state->buffer_damage, &buffer_damage); + + // Buffer to surface damage + pixman_region32_copy(&surface_damage, &state->buffer_damage); + wlr_region_transform(&surface_damage, &surface_damage, state->transform, + state->buffer_width, state->buffer_height); + wlr_region_scale(&surface_damage, &surface_damage, 1.0f/state->scale); + + pixman_region32_union(&state->buffer_damage, &state->buffer_damage, + &buffer_damage); + pixman_region32_union(&state->surface_damage, &state->surface_damage, + &surface_damage); + pixman_region32_fini(&buffer_damage); + pixman_region32_fini(&surface_damage); } if ((next->invalid & WLR_SURFACE_INVALID_OPAQUE_REGION)) { // TODO: process buffer From be888df4c37e33c33ae0a7bb2a1b512538ee0d35 Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 28 Jan 2018 21:38:29 +0100 Subject: [PATCH 53/75] rootston: fix build without xwayland --- rootston/output.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rootston/output.c b/rootston/output.c index c46ba115..14840e5b 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -518,6 +518,7 @@ static bool view_accept_damage(struct roots_output *output, if (output->fullscreen_view == view) { return true; } +#ifdef WLR_HAS_XWAYLAND if (output->fullscreen_view->type == ROOTS_XWAYLAND_VIEW && view->type == ROOTS_XWAYLAND_VIEW) { // Special case: accept damage from children @@ -529,6 +530,7 @@ static bool view_accept_damage(struct roots_output *output, xsurface = xsurface->parent; } } +#endif return false; } From 7881d039b6824eb245496becebf02d3eea55a909 Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 28 Jan 2018 21:56:21 +0100 Subject: [PATCH 54/75] rootston: fix output_damage_whole This should fix artifacts when leaving fullscreen on rotated outputs. --- types/wlr_output.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/types/wlr_output.c b/types/wlr_output.c index 00590136..8995ef5f 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -563,8 +563,11 @@ void wlr_output_update_needs_swap(struct wlr_output *output) { } static void output_damage_whole(struct wlr_output *output) { + int width, height; + wlr_output_effective_resolution(output, &width, &height); + pixman_region32_union_rect(&output->damage, &output->damage, 0, 0, - output->width, output->height); + width, height); wlr_output_update_needs_swap(output); } From 20e6861021ddce3c12f896aa2a961a4da23f98ad Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 28 Jan 2018 22:39:24 +0100 Subject: [PATCH 55/75] Do not flush damage if swapping buffers failed This should solve issues with multiple outputs on DRM backend. --- backend/drm/drm.c | 2 +- rootston/output.c | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 024bc929..a9cfa276 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -210,7 +210,7 @@ static bool wlr_drm_connector_swap_buffers(struct wlr_output *output) { if (conn->pageflip_pending) { wlr_log(L_ERROR, "Skipping pageflip"); - return true; + return false; } if (drm->iface->crtc_pageflip(drm, conn, crtc, fb_id, NULL)) { diff --git a/rootston/output.c b/rootston/output.c index 14840e5b..04a45d1f 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -387,7 +387,9 @@ static void render_output(struct roots_output *output) { } int buffer_age = -1; - wlr_output_make_current(wlr_output, &buffer_age); + if (!wlr_output_make_current(wlr_output, &buffer_age)) { + return; + } int width, height; output_get_transformed_size(output->wlr_output, &width, &height); @@ -482,7 +484,9 @@ static void render_output(struct roots_output *output) { renderer_end: wlr_renderer_scissor(output->desktop->server->renderer, NULL); wlr_renderer_end(server->renderer); - wlr_output_swap_buffers(wlr_output, &now, &damage); + if (!wlr_output_swap_buffers(wlr_output, &now, &damage)) { + goto damage_finish; + } // same as decrementing, but works on unsigned integers output->previous_damage_idx += ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN - 1; output->previous_damage_idx %= ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN; From b47e8c4a1d745c0eb7904079a9d45f201937247b Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 28 Jan 2018 23:33:38 +0100 Subject: [PATCH 56/75] backend/drm: do not retry pageflip when swapping buffers --- backend/drm/drm.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index a9cfa276..a1227d15 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -213,13 +213,11 @@ static bool wlr_drm_connector_swap_buffers(struct wlr_output *output) { return false; } - if (drm->iface->crtc_pageflip(drm, conn, crtc, fb_id, NULL)) { - conn->pageflip_pending = true; - } else { - wl_event_source_timer_update(conn->retry_pageflip, - 1000000.0f / conn->output.current_mode->refresh); + if (!drm->iface->crtc_pageflip(drm, conn, crtc, fb_id, NULL)) { + return false; } + conn->pageflip_pending = true; return true; } From 4cc58288cb75bd7fdeec1ef04bd4fc6cce55d09f Mon Sep 17 00:00:00 2001 From: emersion Date: Mon, 29 Jan 2018 09:07:29 +0100 Subject: [PATCH 57/75] rootston: fix damage when changing views z-index --- rootston/seat.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rootston/seat.c b/rootston/seat.c index 55866ce6..5b11af4a 100644 --- a/rootston/seat.c +++ b/rootston/seat.c @@ -764,6 +764,8 @@ void roots_seat_set_focus(struct roots_seat *seat, struct roots_view *view) { wl_list_remove(&seat_view->link); wl_list_insert(&seat->views, &seat_view->link); + view_damage_whole(view); + struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->seat); if (keyboard != NULL) { wlr_seat_keyboard_notify_enter(seat->seat, view->wlr_surface, From 2cc989e09716eed5974dc9a76b7b6dbee9c3d730 Mon Sep 17 00:00:00 2001 From: emersion Date: Mon, 29 Jan 2018 23:21:30 +0100 Subject: [PATCH 58/75] output: restrict provided damage to output bounds --- types/wlr_output.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/types/wlr_output.c b/types/wlr_output.c index 8995ef5f..f2bb6bfc 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -474,14 +474,16 @@ bool wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when, pixman_region32_t *damage) { wl_signal_emit(&output->events.swap_buffers, damage); - pixman_region32_t *render_damage = damage; - if (damage == NULL) { - // Damage tracking not supported, repaint the whole output - pixman_region32_t output_damage; - pixman_region32_init(&output_damage); - pixman_region32_union_rect(&output_damage, &output_damage, - 0, 0, output->width, output->height); - render_damage = &output_damage; + int width, height; + output_get_transformed_size(output, &width, &height); + + pixman_region32_t render_damage; + pixman_region32_init(&render_damage); + pixman_region32_union_rect(&render_damage, &render_damage, 0, 0, + width, height); + if (damage != NULL) { + // Damage tracking supported + pixman_region32_intersect(&render_damage, &render_damage, damage); } if (when == NULL) { @@ -490,10 +492,10 @@ bool wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when, when = &now; } - if (pixman_region32_not_empty(render_damage)) { + if (pixman_region32_not_empty(&render_damage)) { if (output->fullscreen_surface != NULL) { output_fullscreen_surface_render(output, output->fullscreen_surface, - when, render_damage); + when, &render_damage); } struct wlr_output_cursor *cursor; @@ -502,7 +504,7 @@ bool wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when, output->hardware_cursor == cursor) { continue; } - output_cursor_render(cursor, when, render_damage); + output_cursor_render(cursor, when, &render_damage); } } @@ -515,10 +517,7 @@ bool wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when, output->needs_swap = false; pixman_region32_clear(&output->damage); - if (damage == NULL) { - pixman_region32_fini(render_damage); - } - + pixman_region32_fini(&render_damage); return true; } From d0961a02af36aee2b051ac6775c928a1f64ebc70 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 30 Jan 2018 10:00:58 +0100 Subject: [PATCH 59/75] render: add wlr_renderer_scissor docs --- include/wlr/render.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/wlr/render.h b/include/wlr/render.h index 46ee0fa3..c277ab17 100644 --- a/include/wlr/render.h +++ b/include/wlr/render.h @@ -15,6 +15,11 @@ void wlr_renderer_begin(struct wlr_renderer *r, struct wlr_output *output); void wlr_renderer_end(struct wlr_renderer *r); void wlr_renderer_clear(struct wlr_renderer *r, float red, float green, float blue, float alpha); +/** + * Defines a scissor box. Only pixels that lie within the scissor box can be + * modified by drawing functions. Providing a NULL `box` disables the scissor + * box. + */ void wlr_renderer_scissor(struct wlr_renderer *r, struct wlr_box *box); /** * Requests a texture handle from this renderer. From d498855b9d6f8d7f0ccde42a026fb0619d99b8a2 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 30 Jan 2018 10:23:35 +0100 Subject: [PATCH 60/75] backend/drm: fix hw cursor position on rotated and scaled outputs output: add wlr_output_transformed_resolution --- backend/drm/drm.c | 19 ++++++++----------- include/wlr/types/wlr_output.h | 8 ++++++++ rootston/output.c | 17 +++-------------- types/wlr_output.c | 34 ++++++++++++++-------------------- 4 files changed, 33 insertions(+), 45 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index a1227d15..1b0b9b2b 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -591,11 +591,10 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, }; enum wl_output_transform transform = wlr_output_transform_invert(output->transform); - struct wlr_box transformed_hotspot; wlr_box_transform(&hotspot, transform, - plane->surf.width, plane->surf.height, &transformed_hotspot); - plane->cursor_hotspot_x = transformed_hotspot.x; - plane->cursor_hotspot_y = transformed_hotspot.y; + plane->surf.width, plane->surf.height, &hotspot); + plane->cursor_hotspot_x = hotspot.x; + plane->cursor_hotspot_y = hotspot.y; if (!update_pixels) { // Only update the cursor hotspot @@ -660,20 +659,18 @@ static bool wlr_drm_connector_move_cursor(struct wlr_output *output, struct wlr_box box = { .x = x, .y = y }; int width, height; - wlr_output_effective_resolution(output, &width, &height); + wlr_output_transformed_resolution(output, &width, &height); enum wl_output_transform transform = wlr_output_transform_invert(output->transform); - struct wlr_box transformed_box; - wlr_box_transform(&box, transform, width, height, &transformed_box); + wlr_box_transform(&box, transform, width, height, &box); if (plane != NULL) { - transformed_box.x -= plane->cursor_hotspot_x; - transformed_box.y -= plane->cursor_hotspot_y; + box.x -= plane->cursor_hotspot_x; + box.y -= plane->cursor_hotspot_y; } - bool ok = drm->iface->crtc_move_cursor(drm, conn->crtc, transformed_box.x, - transformed_box.y); + bool ok = drm->iface->crtc_move_cursor(drm, conn->crtc, box.x, box.y); if (ok) { wlr_output_update_needs_swap(output); } diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 7e9439af..5b6ba3e7 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -106,6 +106,14 @@ void wlr_output_set_transform(struct wlr_output *output, void wlr_output_set_position(struct wlr_output *output, int32_t lx, int32_t ly); void wlr_output_set_scale(struct wlr_output *output, float scale); void wlr_output_destroy(struct wlr_output *output); +/** + * Computes the transformed output resolution. + */ +void wlr_output_transformed_resolution(struct wlr_output *output, + int *width, int *height); +/** + * Computes the transformed and scaled output resolution. + */ void wlr_output_effective_resolution(struct wlr_output *output, int *width, int *height); /** diff --git a/rootston/output.c b/rootston/output.c index 04a45d1f..e90f0491 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -175,17 +175,6 @@ static bool surface_intersect_output(struct wlr_surface *surface, return wlr_output_layout_intersects(output_layout, wlr_output, &layout_box); } -static void output_get_transformed_size(struct wlr_output *wlr_output, - int *width, int *height) { - if (wlr_output->transform % 2 == 0) { - *width = wlr_output->width; - *height = wlr_output->height; - } else { - *width = wlr_output->height; - *height = wlr_output->width; - } -} - static void scissor_output(struct roots_output *output, pixman_box32_t *rect) { struct wlr_output *wlr_output = output->wlr_output; @@ -197,7 +186,7 @@ static void scissor_output(struct roots_output *output, pixman_box32_t *rect) { }; int ow, oh; - output_get_transformed_size(output->wlr_output, &ow, &oh); + wlr_output_transformed_resolution(output->wlr_output, &ow, &oh); // Scissor is in renderer coordinates, ie. upside down enum wl_output_transform transform = wlr_output_transform_compose( @@ -392,7 +381,7 @@ static void render_output(struct roots_output *output) { } int width, height; - output_get_transformed_size(output->wlr_output, &width, &height); + wlr_output_transformed_resolution(output->wlr_output, &width, &height); // Check if we can use damage tracking pixman_region32_t damage; @@ -506,7 +495,7 @@ static void output_handle_frame(struct wl_listener *listener, void *data) { static void output_damage_whole(struct roots_output *output) { int width, height; - output_get_transformed_size(output->wlr_output, &width, &height); + wlr_output_transformed_resolution(output->wlr_output, &width, &height); pixman_region32_union_rect(&output->damage, &output->damage, 0, 0, width, height); diff --git a/types/wlr_output.c b/types/wlr_output.c index f2bb6bfc..8c9de541 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -306,24 +306,7 @@ void wlr_output_destroy(struct wlr_output *output) { } } -void wlr_output_effective_resolution(struct wlr_output *output, - int *width, int *height) { - if (output->transform % 2 == 1) { - *width = output->height; - *height = output->width; - } else { - *width = output->width; - *height = output->height; - } - *width /= output->scale; - *height /= output->scale; -} - -bool wlr_output_make_current(struct wlr_output *output, int *buffer_age) { - return output->impl->make_current(output, buffer_age); -} - -static void output_get_transformed_size(struct wlr_output *output, +void wlr_output_transformed_resolution(struct wlr_output *output, int *width, int *height) { if (output->transform % 2 == 0) { *width = output->width; @@ -334,6 +317,17 @@ static void output_get_transformed_size(struct wlr_output *output, } } +void wlr_output_effective_resolution(struct wlr_output *output, + int *width, int *height) { + wlr_output_transformed_resolution(output, width, height); + *width /= output->scale; + *height /= output->scale; +} + +bool wlr_output_make_current(struct wlr_output *output, int *buffer_age) { + return output->impl->make_current(output, buffer_age); +} + static void output_scissor(struct wlr_output *output, pixman_box32_t *rect) { struct wlr_box box = { .x = rect->x1, @@ -343,7 +337,7 @@ static void output_scissor(struct wlr_output *output, pixman_box32_t *rect) { }; int ow, oh; - output_get_transformed_size(output, &ow, &oh); + wlr_output_transformed_resolution(output, &ow, &oh); // Scissor is in renderer coordinates, ie. upside down enum wl_output_transform transform = wlr_output_transform_compose( @@ -475,7 +469,7 @@ bool wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when, wl_signal_emit(&output->events.swap_buffers, damage); int width, height; - output_get_transformed_size(output, &width, &height); + wlr_output_transformed_resolution(output, &width, &height); pixman_region32_t render_damage; pixman_region32_init(&render_damage); From 2a855e62824653f7634617a2c19d88ba1c650911 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 30 Jan 2018 12:01:10 +0100 Subject: [PATCH 61/75] rootston: fix urxvt damage on HiDPI outputs util/region: add wlr_region_expand --- include/wlr/util/region.h | 7 +++++++ rootston/output.c | 6 ++++++ util/region.c | 27 +++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/include/wlr/util/region.h b/include/wlr/util/region.h index 5d2b37e1..7883af97 100644 --- a/include/wlr/util/region.h +++ b/include/wlr/util/region.h @@ -19,4 +19,11 @@ void wlr_region_scale(pixman_region32_t *dst, pixman_region32_t *src, void wlr_region_transform(pixman_region32_t *dst, pixman_region32_t *src, enum wl_output_transform transform, int width, int height); +/** + * Expands the region of `distance`. If `distance` is negative, it shrinks the + * region. + */ +void wlr_region_expand(pixman_region32_t *dst, pixman_region32_t *src, + int distance); + #endif diff --git a/rootston/output.c b/rootston/output.c index e90f0491..de4922ba 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -600,6 +600,12 @@ static void damage_from_surface(struct wlr_surface *surface, pixman_region32_init(&damage); pixman_region32_copy(&damage, &surface->current->surface_damage); wlr_region_scale(&damage, &damage, output->wlr_output->scale); + if (ceil(output->wlr_output->scale) > surface->current->scale) { + // When scaling up a surface, it'll become blurry so we need to expand + // the damage region + wlr_region_expand(&damage, &damage, + ceil(output->wlr_output->scale) - surface->current->scale); + } pixman_region32_translate(&damage, box.x, box.y); pixman_region32_union(&output->damage, &output->damage, &damage); pixman_region32_fini(&damage); diff --git a/util/region.c b/util/region.c index 9c4712f9..1bde0cb8 100644 --- a/util/region.c +++ b/util/region.c @@ -101,3 +101,30 @@ void wlr_region_transform(pixman_region32_t *dst, pixman_region32_t *src, pixman_region32_init_rects(dst, dst_rects, nrects); free(dst_rects); } + +void wlr_region_expand(pixman_region32_t *dst, pixman_region32_t *src, + int distance) { + if (distance == 0) { + pixman_region32_copy(dst, src); + return; + } + + int nrects; + pixman_box32_t *src_rects = pixman_region32_rectangles(src, &nrects); + + pixman_box32_t *dst_rects = malloc(nrects * sizeof(pixman_box32_t)); + if (dst_rects == NULL) { + return; + } + + for (int i = 0; i < nrects; ++i) { + dst_rects[i].x1 = src_rects[i].x1 - distance; + dst_rects[i].x2 = src_rects[i].x2 + distance; + dst_rects[i].y1 = src_rects[i].y1 - distance; + dst_rects[i].y2 = src_rects[i].y2 + distance; + } + + pixman_region32_fini(dst); + pixman_region32_init_rects(dst, dst_rects, nrects); + free(dst_rects); +} From a7cba7d83fc0c881af79792029f36cd46c6cab2c Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 30 Jan 2018 14:40:22 +0100 Subject: [PATCH 62/75] rootston: damage whole output when entering/leaving fullscreen --- include/rootston/output.h | 1 + rootston/desktop.c | 2 ++ rootston/output.c | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/rootston/output.h b/include/rootston/output.h index a9f9bc2b..3a6d3cc7 100644 --- a/include/rootston/output.h +++ b/include/rootston/output.h @@ -39,6 +39,7 @@ void output_remove_notify(struct wl_listener *listener, void *data); struct roots_view; struct roots_drag_icon; +void output_damage_whole(struct roots_output *output); void output_damage_whole_view(struct roots_output *output, struct roots_view *view); void output_damage_from_view(struct roots_output *output, diff --git a/rootston/desktop.c b/rootston/desktop.c index d3654661..91661c05 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -243,6 +243,7 @@ void view_set_fullscreen(struct roots_view *view, bool fullscreen, roots_output->fullscreen_view = view; view->fullscreen_output = roots_output; + output_damage_whole(roots_output); } if (was_fullscreen && !fullscreen) { @@ -250,6 +251,7 @@ void view_set_fullscreen(struct roots_view *view, bool fullscreen, view->saved.height); view_rotate(view, view->saved.rotation); + output_damage_whole(view->fullscreen_output); view->fullscreen_output->fullscreen_view = NULL; view->fullscreen_output = NULL; } diff --git a/rootston/output.c b/rootston/output.c index de4922ba..a7fca415 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -493,7 +493,7 @@ static void output_handle_frame(struct wl_listener *listener, void *data) { render_output(output); } -static void output_damage_whole(struct roots_output *output) { +void output_damage_whole(struct roots_output *output) { int width, height; wlr_output_transformed_resolution(output->wlr_output, &width, &height); From 704130cc1164604c5b805adf186999269e14c5a5 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 30 Jan 2018 14:45:02 +0100 Subject: [PATCH 63/75] output: fix performance issues with wlr_output_schedule_frame --- backend/wayland/output.c | 8 +++++++- include/wlr/types/wlr_output.h | 2 ++ types/wlr_output.c | 22 ++++++++++++++++++---- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/backend/wayland/output.c b/backend/wayland/output.c index 4fec1955..4a8fb0bf 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -21,9 +21,10 @@ static void surface_frame_callback(void *data, struct wl_callback *cb, uint32_t time) { struct wlr_wl_backend_output *output = data; assert(output); - wlr_output_send_frame(&output->wlr_output); wl_callback_destroy(cb); output->frame_callback = NULL; + + wlr_output_send_frame(&output->wlr_output); } static struct wl_callback_listener frame_listener = { @@ -50,6 +51,11 @@ static bool wlr_wl_output_swap_buffers(struct wlr_output *wlr_output) { struct wlr_wl_backend_output *output = (struct wlr_wl_backend_output *)wlr_output; + if (output->frame_callback != NULL) { + wlr_log(L_ERROR, "Skipping buffer swap"); + return false; + } + output->frame_callback = wl_surface_frame(output->surface); wl_callback_add_listener(output->frame_callback, &frame_listener, output); diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 5b6ba3e7..3eb1c6ff 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -77,6 +77,8 @@ struct wlr_output { struct wl_signal destroy; } events; + struct wl_event_source *idle_frame; + struct wlr_surface *fullscreen_surface; struct wl_listener fullscreen_surface_commit; struct wl_listener fullscreen_surface_destroy; diff --git a/types/wlr_output.c b/types/wlr_output.c index 8c9de541..54f4baf8 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -273,6 +273,8 @@ void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, output->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &output->display_destroy); + + output->frame_pending = true; } void wlr_output_destroy(struct wlr_output *output) { @@ -466,6 +468,15 @@ surface_damage_finish: bool wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when, pixman_region32_t *damage) { + if (output->frame_pending) { + wlr_log(L_ERROR, "Tried to swap buffers when a frame is pending"); + return false; + } + if (output->idle_frame != NULL) { + wl_event_source_remove(output->idle_frame); + output->idle_frame = NULL; + } + wl_signal_emit(&output->events.swap_buffers, damage); int width, height; @@ -522,18 +533,21 @@ void wlr_output_send_frame(struct wlr_output *output) { static void schedule_frame_handle_idle_timer(void *data) { struct wlr_output *output = data; - wlr_output_send_frame(output); + output->idle_frame = NULL; + if (!output->frame_pending) { + wlr_output_send_frame(output); + } } void wlr_output_schedule_frame(struct wlr_output *output) { - if (output->frame_pending) { + if (output->frame_pending || output->idle_frame != NULL) { return; } // TODO: ask the backend to send a frame event when appropriate instead struct wl_event_loop *ev = wl_display_get_event_loop(output->display); - wl_event_loop_add_idle(ev, schedule_frame_handle_idle_timer, output); - output->frame_pending = true; + output->idle_frame = + wl_event_loop_add_idle(ev, schedule_frame_handle_idle_timer, output); } void wlr_output_set_gamma(struct wlr_output *output, From babdd6ccf757f18ef15b50d9f16c55031a7c1944 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 30 Jan 2018 19:45:57 +0100 Subject: [PATCH 64/75] backend: fix use-after-free when destroying backends The backend destroy signal is emitted before the output_remove signal is. When the destroy signal is emitted listeners remove their output_remove listener, so the output_remove signal is never received and listeners have an invalid output pointer. The correct way to solve this would be to remove the output_remove signal completely and use the wlr_output.events.destroy signal instead. This isn't yet possible because wl_signal_emit is unsafe and listeners cannot be removed in listeners. --- backend/backend.c | 1 - backend/drm/backend.c | 2 ++ backend/headless/backend.c | 2 ++ backend/headless/output.c | 2 -- backend/libinput/backend.c | 8 +++++--- backend/multi/backend.c | 5 +++++ backend/wayland/backend.c | 8 +++++--- backend/wayland/output.c | 9 +++++---- backend/x11/backend.c | 2 ++ types/wlr_output.c | 1 + 10 files changed, 27 insertions(+), 13 deletions(-) diff --git a/backend/backend.c b/backend/backend.c index a71cf6b8..98b94c5c 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -37,7 +37,6 @@ void wlr_backend_destroy(struct wlr_backend *backend) { return; } - wl_signal_emit(&backend->events.destroy, backend); if (backend->impl && backend->impl->destroy) { backend->impl->destroy(backend); } else { diff --git a/backend/drm/backend.c b/backend/drm/backend.c index de69dad5..dc6757a5 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -34,6 +34,8 @@ static void wlr_drm_backend_destroy(struct wlr_backend *backend) { wlr_output_destroy(&conn->output); } + wl_signal_emit(&backend->events.destroy, backend); + wl_list_remove(&drm->display_destroy.link); wl_list_remove(&drm->session_signal.link); wl_list_remove(&drm->drm_invalidated.link); diff --git a/backend/headless/backend.c b/backend/headless/backend.c index 61409d41..0bf5ec28 100644 --- a/backend/headless/backend.c +++ b/backend/headless/backend.c @@ -51,6 +51,8 @@ static void backend_destroy(struct wlr_backend *wlr_backend) { wlr_input_device_destroy(&input_device->wlr_input_device); } + wl_signal_emit(&wlr_backend->events.destroy, backend); + wlr_egl_finish(&backend->egl); free(backend); } diff --git a/backend/headless/output.c b/backend/headless/output.c index 46f9d212..aac7cc20 100644 --- a/backend/headless/output.c +++ b/backend/headless/output.c @@ -62,8 +62,6 @@ static bool output_swap_buffers(struct wlr_output *wlr_output) { static void output_destroy(struct wlr_output *wlr_output) { struct wlr_headless_output *output = (struct wlr_headless_output *)wlr_output; - wl_signal_emit(&output->backend->backend.events.output_remove, - &output->wlr_output); wl_list_remove(&output->link); diff --git a/backend/libinput/backend.c b/backend/libinput/backend.c index c9352051..86477947 100644 --- a/backend/libinput/backend.c +++ b/backend/libinput/backend.c @@ -95,12 +95,12 @@ static bool wlr_libinput_backend_start(struct wlr_backend *_backend) { return true; } -static void wlr_libinput_backend_destroy(struct wlr_backend *_backend) { - if (!_backend) { +static void wlr_libinput_backend_destroy(struct wlr_backend *wlr_backend) { + if (!wlr_backend) { return; } struct wlr_libinput_backend *backend = - (struct wlr_libinput_backend *)_backend; + (struct wlr_libinput_backend *)wlr_backend; for (size_t i = 0; i < backend->wlr_device_lists.length; i++) { struct wl_list *wlr_devices = backend->wlr_device_lists.items[i]; @@ -112,6 +112,8 @@ static void wlr_libinput_backend_destroy(struct wlr_backend *_backend) { free(wlr_devices); } + wl_signal_emit(&wlr_backend->events.destroy, wlr_backend); + wl_list_remove(&backend->display_destroy.link); wl_list_remove(&backend->session_signal.link); diff --git a/backend/multi/backend.c b/backend/multi/backend.c index 1e574475..78f5c63b 100644 --- a/backend/multi/backend.c +++ b/backend/multi/backend.c @@ -42,11 +42,16 @@ static void subbackend_state_destroy(struct subbackend_state *sub) { static void multi_backend_destroy(struct wlr_backend *wlr_backend) { struct wlr_multi_backend *backend = (struct wlr_multi_backend *)wlr_backend; + wl_list_remove(&backend->display_destroy.link); + struct subbackend_state *sub, *next; wl_list_for_each_safe(sub, next, &backend->backends, link) { wlr_backend_destroy(sub->backend); } + + // Destroy this backend only after removing all sub-backends + wl_signal_emit(&wlr_backend->events.destroy, backend); free(backend); } diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index eca79350..458c9dd0 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -64,9 +64,9 @@ static bool wlr_wl_backend_start(struct wlr_backend *_backend) { return true; } -static void wlr_wl_backend_destroy(struct wlr_backend *_backend) { - struct wlr_wl_backend *backend = (struct wlr_wl_backend *)_backend; - if (!_backend) { +static void wlr_wl_backend_destroy(struct wlr_backend *wlr_backend) { + struct wlr_wl_backend *backend = (struct wlr_wl_backend *)wlr_backend; + if (backend == NULL) { return; } @@ -80,6 +80,8 @@ static void wlr_wl_backend_destroy(struct wlr_backend *_backend) { wlr_input_device_destroy(input_device); } + wl_signal_emit(&wlr_backend->events.destroy, wlr_backend); + wl_list_remove(&backend->local_display_destroy.link); free(backend->seat_name); diff --git a/backend/wayland/output.c b/backend/wayland/output.c index 4a8fb0bf..a9140ff7 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -161,11 +161,12 @@ static bool wlr_wl_output_set_cursor(struct wlr_output *_output, return true; } -static void wlr_wl_output_destroy(struct wlr_output *_output) { +static void wlr_wl_output_destroy(struct wlr_output *wlr_output) { struct wlr_wl_backend_output *output = - (struct wlr_wl_backend_output *)_output; - wl_signal_emit(&output->backend->backend.events.output_remove, - &output->wlr_output); + (struct wlr_wl_backend_output *)wlr_output; + if (output == NULL) { + return; + } wl_list_remove(&output->link); diff --git a/backend/x11/backend.c b/backend/x11/backend.c index 3bad8d61..44e29be1 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -259,6 +259,8 @@ static void wlr_x11_backend_destroy(struct wlr_backend *backend) { xkb_state_unref(x11->keyboard_dev.keyboard->xkb_state); } + wl_signal_emit(&backend->events.destroy, backend); + wl_list_remove(&x11->display_destroy.link); wl_event_source_remove(x11->frame_timer); diff --git a/types/wlr_output.c b/types/wlr_output.c index 54f4baf8..1878dbb3 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -286,6 +286,7 @@ void wlr_output_destroy(struct wlr_output *output) { wlr_output_destroy_global(output); wlr_output_set_fullscreen_surface(output, NULL); + wl_signal_emit(&output->backend->events.output_remove, output); wl_signal_emit(&output->events.destroy, output); struct wlr_output_mode *mode, *tmp_mode; From a295c805c45e940dab511f118a10101a3d3c1f18 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 30 Jan 2018 21:42:12 +0100 Subject: [PATCH 65/75] output: fix output_damage_whole for scaled outputs --- types/wlr_output.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/types/wlr_output.c b/types/wlr_output.c index 1878dbb3..497178c1 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -572,7 +572,7 @@ void wlr_output_update_needs_swap(struct wlr_output *output) { static void output_damage_whole(struct wlr_output *output) { int width, height; - wlr_output_effective_resolution(output, &width, &height); + wlr_output_transformed_resolution(output, &width, &height); pixman_region32_union_rect(&output->damage, &output->damage, 0, 0, width, height); @@ -714,10 +714,8 @@ bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor, static void output_cursor_update_visible(struct wlr_output_cursor *cursor) { struct wlr_box output_box; output_box.x = output_box.y = 0; - wlr_output_effective_resolution(cursor->output, &output_box.width, + wlr_output_transformed_resolution(cursor->output, &output_box.width, &output_box.height); - output_box.width *= cursor->output->scale; - output_box.height *= cursor->output->scale; struct wlr_box cursor_box; output_cursor_get_box(cursor, &cursor_box); From edb4c8d8588eea184cb688f04affa14fd3f0615c Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 30 Jan 2018 22:06:10 +0100 Subject: [PATCH 66/75] output: damage whole output when fullscreen surface size changes --- include/wlr/types/wlr_output.h | 1 + types/wlr_output.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 3eb1c6ff..f10d8286 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -82,6 +82,7 @@ struct wlr_output { struct wlr_surface *fullscreen_surface; struct wl_listener fullscreen_surface_commit; struct wl_listener fullscreen_surface_destroy; + int fullscreen_width, fullscreen_height; struct wl_list cursors; // wlr_output_cursor::link struct wlr_output_cursor *hardware_cursor; diff --git a/types/wlr_output.c b/types/wlr_output.c index 497178c1..4aed1ba6 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -594,6 +594,14 @@ static void output_fullscreen_surface_handle_commit( fullscreen_surface_commit); struct wlr_surface *surface = output->fullscreen_surface; + if (output->fullscreen_width != surface->current->width || + output->fullscreen_height != surface->current->height) { + output->fullscreen_width = surface->current->width; + output->fullscreen_height = surface->current->height; + output_damage_whole(output); + return; + } + struct wlr_box box; output_fullscreen_surface_get_box(output, surface, &box); From 4d6e7f510e80ecae25dff8f36cde77583f53ee8b Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 2 Feb 2018 20:34:46 +0100 Subject: [PATCH 67/75] rootston: fix artifacts when leaving fullscreen in a rotated view --- rootston/output.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/rootston/output.c b/rootston/output.c index a7fca415..294ad57a 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -542,10 +542,27 @@ static void damage_whole_surface(struct wlr_surface *surface, return; } - wlr_box_rotated_bounds(&box, -rotation, &box); + // Take the surface damage and damage the whole surface + // The surface damage is still useful in case the surface got resized + pixman_region32_t damage; + pixman_region32_init(&damage); + pixman_region32_copy(&damage, &surface->current->surface_damage); + wlr_region_scale(&damage, &damage, output->wlr_output->scale); + pixman_region32_union_rect(&damage, &damage, 0, 0, box.width, box.height); + pixman_region32_translate(&damage, box.x, box.y); + pixman_box32_t *extents = pixman_region32_extents(&damage); + struct wlr_box extents_box = { + .x = extents->x1, + .y = extents->y1, + .width = extents->x2 - extents->x1, + .height = extents->y2 - extents->y1, + }; + pixman_region32_fini(&damage); + + wlr_box_rotated_bounds(&extents_box, -rotation, &extents_box); pixman_region32_union_rect(&output->damage, &output->damage, - box.x, box.y, box.width, box.height); + extents_box.x, extents_box.y, extents_box.width, extents_box.height); wlr_output_schedule_frame(output->wlr_output); } From 5aa642485d8d2e1cc17a105dfcc69dd93b20c9a9 Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 2 Feb 2018 20:39:15 +0100 Subject: [PATCH 68/75] rootston: do not render views fullscreened on other outputs --- rootston/output.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rootston/output.c b/rootston/output.c index 294ad57a..b5b277cf 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -312,6 +312,12 @@ damage_finish: } static void render_view(struct roots_view *view, struct render_data *data) { + // Do not render views fullscreened on other outputs + if (view->fullscreen_output != NULL && + view->fullscreen_output != data->output) { + return; + } + render_decorations(view, data); view_for_each_surface(view, render_surface, data); } From bb4aeb3b2f8d739b042ab8c2f2b9b6d1caf6e26b Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 2 Feb 2018 21:01:59 +0100 Subject: [PATCH 69/75] backend/drm: support updating cursor when session is paused --- backend/drm/backend.c | 2 ++ backend/drm/drm.c | 21 ++++++++++++++------- include/backend/drm/drm.h | 4 ++-- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/backend/drm/backend.c b/backend/drm/backend.c index dc6757a5..2b54336f 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -91,6 +91,8 @@ static void session_signal(struct wl_listener *listener, void *data) { struct wlr_drm_plane *plane = conn->crtc->cursor; drm->iface->crtc_set_cursor(drm, conn->crtc, (plane && plane->cursor_enabled) ? plane->cursor_bo : NULL); + drm->iface->crtc_move_cursor(drm, conn->crtc, conn->cursor_x, + conn->cursor_y); } } else { wlr_log(L_INFO, "DRM fd paused"); diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 1b0b9b2b..8d102d8a 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -517,10 +517,6 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, struct wlr_drm_backend *drm = (struct wlr_drm_backend *)output->backend; struct wlr_drm_renderer *renderer = &drm->renderer; - if (!drm->session->active) { - return false; - } - struct wlr_drm_crtc *crtc = conn->crtc; if (!crtc) { return false; @@ -540,6 +536,9 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, if (!buf && update_pixels) { // Hide the cursor plane->cursor_enabled = false; + if (!drm->session->active) { + return true; + } return drm->iface->crtc_set_cursor(drm, crtc, NULL); } plane->cursor_enabled = true; @@ -637,6 +636,10 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, gbm_bo_unmap(bo, bo_data); + if (!drm->session->active) { + return true; + } + bool ok = drm->iface->crtc_set_cursor(drm, crtc, bo); if (ok) { wlr_output_update_needs_swap(output); @@ -648,9 +651,6 @@ static bool wlr_drm_connector_move_cursor(struct wlr_output *output, int x, int y) { struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; struct wlr_drm_backend *drm = (struct wlr_drm_backend *)output->backend; - if (!drm->session->active) { - return false; - } if (!conn->crtc) { return false; } @@ -670,6 +670,13 @@ static bool wlr_drm_connector_move_cursor(struct wlr_output *output, box.y -= plane->cursor_hotspot_y; } + conn->cursor_x = box.x; + conn->cursor_y = box.y; + + if (!drm->session->active) { + return true; + } + bool ok = drm->iface->crtc_move_cursor(drm, conn->crtc, box.x, box.y); if (ok) { wlr_output_update_needs_swap(output); diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index 72671f45..af472ede 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -123,8 +123,8 @@ struct wlr_drm_connector { union wlr_drm_connector_props props; - uint32_t width; - uint32_t height; + uint32_t width, height; + int32_t cursor_x, cursor_y; drmModeCrtc *old_crtc; From 402587ed65016fa89b9fcafc8d7af27b1958dd20 Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 3 Feb 2018 09:25:35 +0100 Subject: [PATCH 70/75] rootston: use output renderer --- rootston/output.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/rootston/output.c b/rootston/output.c index b5b277cf..96e466a7 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -177,6 +178,8 @@ static bool surface_intersect_output(struct wlr_surface *surface, static void scissor_output(struct roots_output *output, pixman_box32_t *rect) { struct wlr_output *wlr_output = output->wlr_output; + struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); + assert(renderer); struct wlr_box box = { .x = rect->x1, @@ -194,7 +197,7 @@ static void scissor_output(struct roots_output *output, pixman_box32_t *rect) { WL_OUTPUT_TRANSFORM_FLIPPED_180); wlr_box_transform(&box, transform, ow, oh, &box); - wlr_renderer_scissor(output->desktop->server->renderer, &box); + wlr_renderer_scissor(renderer, &box); } static void render_surface(struct wlr_surface *surface, double lx, double ly, @@ -202,6 +205,9 @@ static void render_surface(struct wlr_surface *surface, double lx, double ly, struct render_data *data = _data; struct roots_output *output = data->output; struct timespec *when = data->when; + struct wlr_renderer *renderer = + wlr_backend_get_renderer(output->wlr_output->backend); + assert(renderer); if (!wlr_surface_has_buffer(surface)) { return; @@ -237,8 +243,7 @@ static void render_surface(struct wlr_surface *surface, double lx, double ly, pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); for (int i = 0; i < nrects; ++i) { scissor_output(output, &rects[i]); - wlr_render_with_matrix(output->desktop->server->renderer, - surface->texture, &matrix); + wlr_render_with_matrix(renderer, surface->texture, &matrix); } wlr_surface_send_frame_done(surface, when); @@ -276,6 +281,9 @@ static void render_decorations(struct roots_view *view, } struct roots_output *output = data->output; + struct wlr_renderer *renderer = + wlr_backend_get_renderer(output->wlr_output->backend); + assert(renderer); struct wlr_box box; get_decoration_box(view, output, &box); @@ -303,8 +311,7 @@ static void render_decorations(struct roots_view *view, pixman_region32_rectangles(&damage, &nrects); for (int i = 0; i < nrects; ++i) { scissor_output(output, &rects[i]); - wlr_render_colored_quad(output->desktop->server->renderer, &color, - &matrix); + wlr_render_colored_quad(renderer, &color, &matrix); } damage_finish: @@ -344,6 +351,8 @@ static void render_output(struct roots_output *output) { struct wlr_output *wlr_output = output->wlr_output; struct roots_desktop *desktop = output->desktop; struct roots_server *server = desktop->server; + struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); + assert(renderer); if (!wlr_output->enabled) { return; @@ -418,7 +427,7 @@ static void render_output(struct roots_output *output) { .damage = &damage, }; - wlr_renderer_begin(server->renderer, wlr_output); + wlr_renderer_begin(renderer, wlr_output); if (!pixman_region32_not_empty(&damage)) { // Output isn't damaged but needs buffer swap @@ -429,8 +438,8 @@ static void render_output(struct roots_output *output) { pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); for (int i = 0; i < nrects; ++i) { scissor_output(output, &rects[i]); - wlr_renderer_clear(output->desktop->server->renderer, - clear_color[0], clear_color[1], clear_color[2], 1); + wlr_renderer_clear(renderer, clear_color[0], clear_color[1], + clear_color[2], 1); } // If a view is fullscreen on this output, render it @@ -477,8 +486,8 @@ static void render_output(struct roots_output *output) { } renderer_end: - wlr_renderer_scissor(output->desktop->server->renderer, NULL); - wlr_renderer_end(server->renderer); + wlr_renderer_scissor(renderer, NULL); + wlr_renderer_end(renderer); if (!wlr_output_swap_buffers(wlr_output, &now, &damage)) { goto damage_finish; } From ddb1779f9fee28b6393ba6607852a078ed65575f Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 3 Feb 2018 09:32:02 +0100 Subject: [PATCH 71/75] render: make wlr_renderer_clear take a float[4] for the color --- examples/output-layout.c | 2 +- examples/rotation.c | 2 +- examples/tablet.c | 2 +- examples/touch.c | 2 +- include/wlr/render.h | 3 +-- include/wlr/render/interface.h | 3 +-- render/gles2/renderer.c | 6 +++--- render/wlr_renderer.c | 5 ++--- rootston/output.c | 5 ++--- 9 files changed, 13 insertions(+), 17 deletions(-) diff --git a/examples/output-layout.c b/examples/output-layout.c index 0c85ba7f..91ab80f4 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -102,7 +102,7 @@ static void handle_output_frame(struct output_state *output, wlr_output_make_current(wlr_output, NULL); wlr_renderer_begin(sample->renderer, wlr_output); - wlr_renderer_clear(sample->renderer, 0.25f, 0.25f, 0.25f, 1); + wlr_renderer_clear(sample->renderer, &(float[]){0.25f, 0.25f, 0.25f, 1}); animate_cat(sample, output->output); diff --git a/examples/rotation.c b/examples/rotation.c index 4f7b1567..e390daaf 100644 --- a/examples/rotation.c +++ b/examples/rotation.c @@ -44,7 +44,7 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts wlr_output_make_current(wlr_output, NULL); wlr_renderer_begin(sample->renderer, wlr_output); - wlr_renderer_clear(sample->renderer, 0.25f, 0.25f, 0.25f, 1); + wlr_renderer_clear(sample->renderer, &(float[]){0.25f, 0.25f, 0.25f, 1}); float matrix[16]; for (int y = -128 + (int)odata->y_offs; y < height; y += 128) { diff --git a/examples/tablet.c b/examples/tablet.c index f12ecbc4..ca76ec5a 100644 --- a/examples/tablet.c +++ b/examples/tablet.c @@ -44,7 +44,7 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts wlr_output_make_current(wlr_output, NULL); wlr_renderer_begin(sample->renderer, wlr_output); - wlr_renderer_clear(sample->renderer, 0.25f, 0.25f, 0.25f, 1); + wlr_renderer_clear(sample->renderer, &(float[]){0.25f, 0.25f, 0.25f, 1}); float matrix[16], view[16]; float distance = 0.8f * (1 - sample->distance); diff --git a/examples/touch.c b/examples/touch.c index 2ef2712f..3cf00e9c 100644 --- a/examples/touch.c +++ b/examples/touch.c @@ -43,7 +43,7 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts wlr_output_make_current(wlr_output, NULL); wlr_renderer_begin(sample->renderer, wlr_output); - wlr_renderer_clear(sample->renderer, 0.25f, 0.25f, 0.25f, 1); + wlr_renderer_clear(sample->renderer, &(float[]){0.25f, 0.25f, 0.25f, 1}); float matrix[16]; struct touch_point *p; diff --git a/include/wlr/render.h b/include/wlr/render.h index c277ab17..ccc66d36 100644 --- a/include/wlr/render.h +++ b/include/wlr/render.h @@ -13,8 +13,7 @@ struct wlr_renderer; void wlr_renderer_begin(struct wlr_renderer *r, struct wlr_output *output); void wlr_renderer_end(struct wlr_renderer *r); -void wlr_renderer_clear(struct wlr_renderer *r, float red, float green, - float blue, float alpha); +void wlr_renderer_clear(struct wlr_renderer *r, const float (*color)[4]); /** * Defines a scissor box. Only pixels that lie within the scissor box can be * modified by drawing functions. Providing a NULL `box` disables the scissor diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index 2531f33c..b8e99898 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -18,8 +18,7 @@ struct wlr_renderer { struct wlr_renderer_impl { void (*begin)(struct wlr_renderer *renderer, struct wlr_output *output); void (*end)(struct wlr_renderer *renderer); - void (*clear)(struct wlr_renderer *renderer, float red, float green, - float blue, float alpha); + void (*clear)(struct wlr_renderer *renderer, const float (*color)[4]); void (*scissor)(struct wlr_renderer *renderer, struct wlr_box *box); struct wlr_texture *(*texture_create)(struct wlr_renderer *renderer); bool (*render_with_matrix)(struct wlr_renderer *renderer, diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index bdb62ff3..f57e9dae 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -121,9 +121,9 @@ static void wlr_gles2_end(struct wlr_renderer *wlr_renderer) { // no-op } -static void wlr_gles2_clear(struct wlr_renderer *wlr_renderer, float red, - float green, float blue, float alpha) { - glClearColor(red, green, blue, alpha); +static void wlr_gles2_clear(struct wlr_renderer *wlr_renderer, + const float (*color)[4]) { + glClearColor((*color)[0], (*color)[1], (*color)[2], (*color)[3]); glClear(GL_COLOR_BUFFER_BIT); } diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index b60a3f73..c8f06a64 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -23,9 +23,8 @@ void wlr_renderer_end(struct wlr_renderer *r) { r->impl->end(r); } -void wlr_renderer_clear(struct wlr_renderer *r, float red, float green, - float blue, float alpha) { - r->impl->clear(r, red, green, blue, alpha); +void wlr_renderer_clear(struct wlr_renderer *r, const float (*color)[4]) { + r->impl->clear(r, color); } void wlr_renderer_scissor(struct wlr_renderer *r, struct wlr_box *box) { diff --git a/rootston/output.c b/rootston/output.c index 96e466a7..7c520d86 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -361,7 +361,7 @@ static void render_output(struct roots_output *output) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - float clear_color[] = {0.25f, 0.25f, 0.25f}; + float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; // Check if we can delegate the fullscreen surface to the output if (output->fullscreen_view != NULL) { @@ -438,8 +438,7 @@ static void render_output(struct roots_output *output) { pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); for (int i = 0; i < nrects; ++i) { scissor_output(output, &rects[i]); - wlr_renderer_clear(renderer, clear_color[0], clear_color[1], - clear_color[2], 1); + wlr_renderer_clear(renderer, &clear_color); } // If a view is fullscreen on this output, render it From faa57341ca49b4cc0f2a51d420955339442a5fac Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 3 Feb 2018 10:01:42 +0100 Subject: [PATCH 72/75] output: replace raw GL calls by wlr_renderer_* calls --- include/wlr/types/wlr_output.h | 1 - types/wlr_output.c | 53 +++++++++++++--------------------- 2 files changed, 20 insertions(+), 34 deletions(-) diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index a1058a8c..a653d527 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -24,7 +24,6 @@ struct wlr_output_cursor { struct wl_list link; // only when using a software cursor without a surface - struct wlr_renderer *renderer; struct wlr_texture *texture; // only when using a cursor surface diff --git a/types/wlr_output.c b/types/wlr_output.c index aaee78a2..13561d43 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -10,9 +10,7 @@ #include #include #include -#include #include -#include #include #include @@ -332,6 +330,9 @@ bool wlr_output_make_current(struct wlr_output *output, int *buffer_age) { } static void output_scissor(struct wlr_output *output, pixman_box32_t *rect) { + struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + assert(renderer); + struct wlr_box box = { .x = rect->x1, .y = rect->y1, @@ -348,7 +349,7 @@ static void output_scissor(struct wlr_output *output, pixman_box32_t *rect) { WL_OUTPUT_TRANSFORM_FLIPPED_180); wlr_box_transform(&box, transform, ow, oh, &box); - glScissor(box.x, box.y, box.width, box.height); + wlr_renderer_scissor(renderer, &box); } static void output_fullscreen_surface_get_box(struct wlr_output *output, @@ -368,13 +369,11 @@ static void output_fullscreen_surface_get_box(struct wlr_output *output, static void output_fullscreen_surface_render(struct wlr_output *output, struct wlr_surface *surface, const struct timespec *when, pixman_region32_t *damage) { - glViewport(0, 0, output->width, output->height); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + assert(renderer); if (!wlr_surface_has_buffer(surface)) { - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); + wlr_renderer_clear(renderer, &(float[]){0, 0, 0, 0}); return; } @@ -389,14 +388,12 @@ static void output_fullscreen_surface_render(struct wlr_output *output, int nrects; pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); - glEnable(GL_SCISSOR_TEST); for (int i = 0; i < nrects; ++i) { output_scissor(output, &rects[i]); - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); + wlr_renderer_clear(renderer, &(float[]){0, 0, 0, 0}); wlr_render_with_matrix(surface->renderer, surface->texture, &matrix); } - glDisable(GL_SCISSOR_TEST); + wlr_renderer_scissor(renderer, NULL); wlr_surface_send_frame_done(surface, when); } @@ -419,14 +416,15 @@ static void output_cursor_get_box(struct wlr_output_cursor *cursor, static void output_cursor_render(struct wlr_output_cursor *cursor, const struct timespec *when, pixman_region32_t *damage) { + struct wlr_renderer *renderer = + wlr_backend_get_renderer(cursor->output->backend); + assert(renderer); + struct wlr_texture *texture = cursor->texture; - struct wlr_renderer *renderer = cursor->renderer; if (cursor->surface != NULL) { texture = cursor->surface->texture; - renderer = cursor->surface->renderer; } - - if (texture == NULL || renderer == NULL) { + if (texture == NULL) { return; } @@ -442,22 +440,17 @@ static void output_cursor_render(struct wlr_output_cursor *cursor, goto surface_damage_finish; } - glViewport(0, 0, cursor->output->width, cursor->output->height); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - float matrix[16]; wlr_matrix_project_box(&matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0, &cursor->output->transform_matrix); int nrects; pixman_box32_t *rects = pixman_region32_rectangles(&surface_damage, &nrects); - glEnable(GL_SCISSOR_TEST); for (int i = 0; i < nrects; ++i) { output_scissor(cursor->output, &rects[i]); wlr_render_with_matrix(renderer, texture, &matrix); } - glDisable(GL_SCISSOR_TEST); + wlr_renderer_scissor(renderer, NULL); if (cursor->surface != NULL) { wlr_surface_send_frame_done(cursor->surface, when); @@ -672,6 +665,10 @@ static void output_cursor_reset(struct wlr_output_cursor *cursor) { bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor, const uint8_t *pixels, int32_t stride, uint32_t width, uint32_t height, int32_t hotspot_x, int32_t hotspot_y) { + struct wlr_renderer *renderer = + wlr_backend_get_renderer(cursor->output->backend); + assert(renderer); + output_cursor_reset(cursor); cursor->width = width; @@ -701,15 +698,8 @@ bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor, return true; } - if (cursor->renderer == NULL) { - cursor->renderer = wlr_gles2_renderer_create(cursor->output->backend); - if (cursor->renderer == NULL) { - return false; - } - } - if (cursor->texture == NULL) { - cursor->texture = wlr_render_texture_create(cursor->renderer); + cursor->texture = wlr_render_texture_create(renderer); if (cursor->texture == NULL) { return false; } @@ -899,9 +889,6 @@ void wlr_output_cursor_destroy(struct wlr_output_cursor *cursor) { if (cursor->texture != NULL) { wlr_texture_destroy(cursor->texture); } - if (cursor->renderer != NULL) { - wlr_renderer_destroy(cursor->renderer); - } wl_list_remove(&cursor->link); free(cursor); } From 6ba36cc52f83db2d21ef3e2fcb5b3dbf37c4d78e Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 3 Feb 2018 16:33:58 +0100 Subject: [PATCH 73/75] rootston: do not rely on current view size when accumulating damage --- rootston/output.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/rootston/output.c b/rootston/output.c index 7c520d86..8e9e2b73 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -549,12 +549,12 @@ static void damage_whole_surface(struct wlr_surface *surface, return; } + int ow, oh; + wlr_output_transformed_resolution(output->wlr_output, &ow, &oh); + struct wlr_box box; - bool intersects = surface_intersect_output(surface, output->desktop->layout, + surface_intersect_output(surface, output->desktop->layout, output->wlr_output, lx, ly, rotation, &box); - if (!intersects) { - return; - } // Take the surface damage and damage the whole surface // The surface damage is still useful in case the surface got resized @@ -564,6 +564,7 @@ static void damage_whole_surface(struct wlr_surface *surface, wlr_region_scale(&damage, &damage, output->wlr_output->scale); pixman_region32_union_rect(&damage, &damage, 0, 0, box.width, box.height); pixman_region32_translate(&damage, box.x, box.y); + pixman_region32_intersect_rect(&damage, &damage, 0, 0, ow, oh); pixman_box32_t *extents = pixman_region32_extents(&damage); struct wlr_box extents_box = { .x = extents->x1, @@ -620,12 +621,12 @@ static void damage_from_surface(struct wlr_surface *surface, return; } + int ow, oh; + wlr_output_transformed_resolution(output->wlr_output, &ow, &oh); + struct wlr_box box; - bool intersects = surface_intersect_output(surface, output->desktop->layout, + surface_intersect_output(surface, output->desktop->layout, output->wlr_output, lx, ly, rotation, &box); - if (!intersects) { - return; - } pixman_region32_t damage; pixman_region32_init(&damage); @@ -638,6 +639,7 @@ static void damage_from_surface(struct wlr_surface *surface, ceil(output->wlr_output->scale) - surface->current->scale); } pixman_region32_translate(&damage, box.x, box.y); + pixman_region32_intersect_rect(&damage, &damage, 0, 0, ow, oh); pixman_region32_union(&output->damage, &output->damage, &damage); pixman_region32_fini(&damage); From 1842487d61ad6ee39369b5321b363941596a3bf6 Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 3 Feb 2018 16:43:31 +0100 Subject: [PATCH 74/75] rootston: fix crash when closing a fullscreened xwayland view --- rootston/xwayland.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rootston/xwayland.c b/rootston/xwayland.c index a3e12d00..36be9793 100644 --- a/rootston/xwayland.c +++ b/rootston/xwayland.c @@ -267,6 +267,12 @@ static void handle_unmap_notify(struct wl_listener *listener, void *data) { child->destroy(child); } + if (view->fullscreen_output != NULL) { + output_damage_whole(view->fullscreen_output); + view->fullscreen_output->fullscreen_view = NULL; + view->fullscreen_output = NULL; + } + view->wlr_surface = NULL; view->width = view->height = 0; wl_list_remove(&view->link); From 1cea73d2d816f50222c4e27a20b3a5c08ae104df Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 4 Feb 2018 11:59:04 +0100 Subject: [PATCH 75/75] rootston: fix rotated views damage tracking --- rootston/output.c | 81 +++++++++++++++++++++++------------------------ types/wlr_box.c | 8 ++--- 2 files changed, 43 insertions(+), 46 deletions(-) diff --git a/rootston/output.c b/rootston/output.c index 8e9e2b73..0e0c6114 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -553,31 +553,16 @@ static void damage_whole_surface(struct wlr_surface *surface, wlr_output_transformed_resolution(output->wlr_output, &ow, &oh); struct wlr_box box; - surface_intersect_output(surface, output->desktop->layout, + bool intersects = surface_intersect_output(surface, output->desktop->layout, output->wlr_output, lx, ly, rotation, &box); + if (!intersects) { + return; + } - // Take the surface damage and damage the whole surface - // The surface damage is still useful in case the surface got resized - pixman_region32_t damage; - pixman_region32_init(&damage); - pixman_region32_copy(&damage, &surface->current->surface_damage); - wlr_region_scale(&damage, &damage, output->wlr_output->scale); - pixman_region32_union_rect(&damage, &damage, 0, 0, box.width, box.height); - pixman_region32_translate(&damage, box.x, box.y); - pixman_region32_intersect_rect(&damage, &damage, 0, 0, ow, oh); - pixman_box32_t *extents = pixman_region32_extents(&damage); - struct wlr_box extents_box = { - .x = extents->x1, - .y = extents->y1, - .width = extents->x2 - extents->x1, - .height = extents->y2 - extents->y1, - }; - pixman_region32_fini(&damage); - - wlr_box_rotated_bounds(&extents_box, -rotation, &extents_box); + wlr_box_rotated_bounds(&box, -rotation, &box); pixman_region32_union_rect(&output->damage, &output->damage, - extents_box.x, extents_box.y, extents_box.width, extents_box.height); + box.x, box.y, box.width, box.height); wlr_output_schedule_frame(output->wlr_output); } @@ -616,34 +601,51 @@ void output_damage_whole_drag_icon(struct roots_output *output, static void damage_from_surface(struct wlr_surface *surface, double lx, double ly, float rotation, void *data) { struct roots_output *output = data; + struct wlr_output *wlr_output = output->wlr_output; if (!wlr_surface_has_buffer(surface)) { return; } int ow, oh; - wlr_output_transformed_resolution(output->wlr_output, &ow, &oh); + wlr_output_transformed_resolution(wlr_output, &ow, &oh); struct wlr_box box; surface_intersect_output(surface, output->desktop->layout, - output->wlr_output, lx, ly, rotation, &box); + wlr_output, lx, ly, rotation, &box); - pixman_region32_t damage; - pixman_region32_init(&damage); - pixman_region32_copy(&damage, &surface->current->surface_damage); - wlr_region_scale(&damage, &damage, output->wlr_output->scale); - if (ceil(output->wlr_output->scale) > surface->current->scale) { - // When scaling up a surface, it'll become blurry so we need to expand - // the damage region - wlr_region_expand(&damage, &damage, - ceil(output->wlr_output->scale) - surface->current->scale); + if (rotation == 0) { + pixman_region32_t damage; + pixman_region32_init(&damage); + pixman_region32_copy(&damage, &surface->current->surface_damage); + wlr_region_scale(&damage, &damage, wlr_output->scale); + if (ceil(wlr_output->scale) > surface->current->scale) { + // When scaling up a surface, it'll become blurry so we need to + // expand the damage region + wlr_region_expand(&damage, &damage, + ceil(wlr_output->scale) - surface->current->scale); + } + pixman_region32_translate(&damage, box.x, box.y); + pixman_region32_union(&output->damage, &output->damage, &damage); + pixman_region32_fini(&damage); + } else { + pixman_box32_t *extents = + pixman_region32_extents(&surface->current->surface_damage); + struct wlr_box damage_box = { + .x = box.x + extents->x1 * wlr_output->scale, + .y = box.y + extents->y1 * wlr_output->scale, + .width = (extents->x2 - extents->x1) * wlr_output->scale, + .height = (extents->y2 - extents->y1) * wlr_output->scale, + }; + wlr_box_rotated_bounds(&damage_box, -rotation, &damage_box); + pixman_region32_union_rect(&output->damage, &output->damage, + damage_box.x, damage_box.y, damage_box.width, damage_box.height); } - pixman_region32_translate(&damage, box.x, box.y); - pixman_region32_intersect_rect(&damage, &damage, 0, 0, ow, oh); - pixman_region32_union(&output->damage, &output->damage, &damage); - pixman_region32_fini(&damage); - wlr_output_schedule_frame(output->wlr_output); + pixman_region32_intersect_rect(&output->damage, &output->damage, 0, 0, + ow, oh); + + wlr_output_schedule_frame(wlr_output); } void output_damage_from_view(struct roots_output *output, @@ -652,11 +654,6 @@ void output_damage_from_view(struct roots_output *output, return; } - if (view->rotation != 0) { - output_damage_whole_view(output, view); - return; - } - view_for_each_surface(view, damage_from_surface, output); } diff --git a/types/wlr_box.c b/types/wlr_box.c index a7388209..33031858 100644 --- a/types/wlr_box.c +++ b/types/wlr_box.c @@ -138,8 +138,8 @@ void wlr_box_rotated_bounds(const struct wlr_box *box, float rotation, (box->x + box->width - ox) * s + (box->y + box->height - oy) * c; - dest->x = fmin(x1, x2); - dest->width = fmax(x1, x2) - fmin(x1, x2); - dest->y = fmin(y1, y2); - dest->height = fmax(y1, y2) - fmin(y1, y2); + dest->x = floor(fmin(x1, x2)); + dest->width = ceil(fmax(x1, x2) - fmin(x1, x2)); + dest->y = floor(fmin(y1, y2)); + dest->height = ceil(fmax(y1, y2) - fmin(y1, y2)); }