From 0aafd6e234ff921e2b41126e22c426f928877cc4 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 2 Oct 2018 11:19:20 +0200 Subject: rootston: add layer_for_each_surface --- rootston/output.c | 64 +++++++++++++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 33 deletions(-) (limited to 'rootston') diff --git a/rootston/output.c b/rootston/output.c index e85612fa..e8a1b60f 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -127,6 +127,23 @@ static void drag_icons_for_each_surface(struct roots_input *input, } } +static void layer_for_each_surface(struct wl_list *layer, + const struct wlr_box *output_layout_box, + wlr_surface_iterator_func_t iterator, struct layout_data *layout_data, + void *user_data) { + struct roots_layer_surface *roots_surface; + wl_list_for_each(roots_surface, layer, link) { + struct wlr_layer_surface_v1 *layer = roots_surface->layer_surface; + + layout_data->x = roots_surface->geo.x + output_layout_box->x; + layout_data->y = roots_surface->geo.y + output_layout_box->y; + layout_data->width = roots_surface->geo.width; + layout_data->height = roots_surface->geo.height; + layout_data->rotation = 0; + wlr_layer_surface_v1_for_each_surface(layer, iterator, user_data); + } +} + struct render_data { struct layout_data layout; @@ -320,6 +337,14 @@ static void render_view(struct roots_view *view, struct render_data *data) { view_for_each_surface(view, &data->layout, render_surface, data); } +static void render_layer(struct roots_output *output, + const struct wlr_box *output_layout_box, struct render_data *data, + struct wl_list *layer) { + data->alpha = 1; + layer_for_each_surface(layer, output_layout_box, render_surface, + &data->layout, data); +} + static bool has_standalone_surface(struct roots_view *view) { if (!wl_list_empty(&view->wlr_surface->subsurfaces)) { return false; @@ -358,38 +383,6 @@ static void surface_send_frame_done(struct wlr_surface *surface, int sx, int sy, wlr_surface_send_frame_done(surface, when); } -static void render_layer(struct roots_output *output, - const struct wlr_box *output_layout_box, struct render_data *data, - struct wl_list *layer) { - struct roots_layer_surface *roots_surface; - wl_list_for_each(roots_surface, layer, link) { - struct wlr_layer_surface_v1 *layer = roots_surface->layer_surface; - - surface_for_each_surface(layer->surface, - roots_surface->geo.x + output_layout_box->x, - roots_surface->geo.y + output_layout_box->y, - 0, &data->layout, render_surface, data); - - wlr_layer_surface_v1_for_each_surface(layer, render_surface, data); - } -} - -static void layers_send_done( - struct roots_output *output, struct timespec *when) { - size_t len = sizeof(output->layers) / sizeof(output->layers[0]); - for (size_t i = 0; i < len; ++i) { - struct roots_layer_surface *roots_surface; - wl_list_for_each(roots_surface, &output->layers[i], link) { - struct wlr_layer_surface_v1 *layer = roots_surface->layer_surface; - wlr_surface_send_frame_done(layer->surface, when); - struct wlr_xdg_popup *popup; - wl_list_for_each(popup, &roots_surface->layer_surface->popups, link) { - wlr_surface_send_frame_done(popup->base->surface, when); - } - } - } -} - static void render_output(struct roots_output *output) { struct wlr_output *wlr_output = output->wlr_output; struct roots_desktop *desktop = output->desktop; @@ -563,7 +556,12 @@ damage_finish: drag_icons_for_each_surface(server->input, surface_send_frame_done, &data.layout, &data); } - layers_send_done(output, data.when); + + size_t len = sizeof(output->layers) / sizeof(output->layers[0]); + for (size_t i = 0; i < len; ++i) { + layer_for_each_surface(&output->layers[i], output_box, + surface_send_frame_done, &data.layout, &data); + } } void output_damage_whole(struct roots_output *output) { -- cgit v1.2.3 From ba63d77ec19b84c9bf9be24cc4d91f3bfa856dba Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 2 Oct 2018 11:26:40 +0200 Subject: rootston: add output_for_each_surface --- rootston/output.c | 78 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 45 insertions(+), 33 deletions(-) (limited to 'rootston') diff --git a/rootston/output.c b/rootston/output.c index e8a1b60f..1707be3a 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -129,7 +129,7 @@ static void drag_icons_for_each_surface(struct roots_input *input, static void layer_for_each_surface(struct wl_list *layer, const struct wlr_box *output_layout_box, - wlr_surface_iterator_func_t iterator, struct layout_data *layout_data, + wlr_surface_iterator_func_t iterator, struct layout_data *layout_data, void *user_data) { struct roots_layer_surface *roots_surface; wl_list_for_each(roots_surface, layer, link) { @@ -144,6 +144,48 @@ static void layer_for_each_surface(struct wl_list *layer, } } +static void output_for_each_surface(struct roots_output *output, + wlr_surface_iterator_func_t iterator, struct layout_data *layout_data, + void *user_data) { + struct wlr_output *wlr_output = output->wlr_output; + struct roots_desktop *desktop = output->desktop; + struct roots_server *server = desktop->server; + + const struct wlr_box *output_box = + wlr_output_layout_get_box(desktop->layout, wlr_output); + + if (output->fullscreen_view != NULL) { + struct roots_view *view = output->fullscreen_view; + if (wlr_output->fullscreen_surface == view->wlr_surface) { + // The surface is managed by the wlr_output + return; + } + + view_for_each_surface(view, layout_data, iterator, user_data); + +#ifdef WLR_HAS_XWAYLAND + if (view->type == ROOTS_XWAYLAND_VIEW) { + xwayland_children_for_each_surface(view->xwayland_surface, + iterator, layout_data, user_data); + } +#endif + } else { + struct roots_view *view; + wl_list_for_each_reverse(view, &desktop->views, link) { + view_for_each_surface(view, layout_data, iterator, user_data); + } + + drag_icons_for_each_surface(server->input, iterator, + layout_data, user_data); + } + + size_t len = sizeof(output->layers) / sizeof(output->layers[0]); + for (size_t i = 0; i < len; ++i) { + layer_for_each_surface(&output->layers[i], output_box, + iterator, layout_data, user_data); + } +} + struct render_data { struct layout_data layout; @@ -530,38 +572,8 @@ damage_finish: pixman_region32_fini(&damage); // Send frame done events to all surfaces - if (output->fullscreen_view != NULL) { - struct roots_view *view = output->fullscreen_view; - if (wlr_output->fullscreen_surface == view->wlr_surface) { - // The surface is managed by the wlr_output - return; - } - - view_for_each_surface(view, &data.layout, surface_send_frame_done, - &data); - -#ifdef WLR_HAS_XWAYLAND - if (view->type == ROOTS_XWAYLAND_VIEW) { - xwayland_children_for_each_surface(view->xwayland_surface, - surface_send_frame_done, &data.layout, &data); - } -#endif - } else { - struct roots_view *view; - wl_list_for_each_reverse(view, &desktop->views, link) { - view_for_each_surface(view, &data.layout, surface_send_frame_done, - &data); - } - - drag_icons_for_each_surface(server->input, surface_send_frame_done, - &data.layout, &data); - } - - size_t len = sizeof(output->layers) / sizeof(output->layers[0]); - for (size_t i = 0; i < len; ++i) { - layer_for_each_surface(&output->layers[i], output_box, - surface_send_frame_done, &data.layout, &data); - } + output_for_each_surface(output, surface_send_frame_done, + &data.layout, &data); } void output_damage_whole(struct roots_output *output) { -- cgit v1.2.3 From abd3e995ab446b5487f4d2ff16d9e2c3f1baade1 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 2 Oct 2018 11:46:28 +0200 Subject: rootston: send presentation events --- include/rootston/desktop.h | 2 ++ include/rootston/output.h | 1 + rootston/desktop.c | 3 +++ rootston/output.c | 52 +++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 57 insertions(+), 1 deletion(-) (limited to 'rootston') diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h index 90851a17..8cee170f 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -57,6 +58,7 @@ struct roots_desktop { struct wlr_screencopy_manager_v1 *screencopy; struct wlr_tablet_manager_v2 *tablet_v2; struct wlr_pointer_constraints_v1 *pointer_constraints; + struct wlr_presentation *presentation; struct wl_listener new_output; struct wl_listener layout_change; diff --git a/include/rootston/output.h b/include/rootston/output.h index 69bc5126..3f07ab6f 100644 --- a/include/rootston/output.h +++ b/include/rootston/output.h @@ -24,6 +24,7 @@ struct roots_output { struct wl_listener destroy; struct wl_listener mode; struct wl_listener transform; + struct wl_listener present; struct wl_listener damage_frame; struct wl_listener damage_destroy; }; diff --git a/rootston/desktop.c b/rootston/desktop.c index c180c839..7f749050 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -969,6 +969,9 @@ struct roots_desktop *desktop_create(struct roots_server *server, wl_signal_add(&desktop->pointer_constraints->events.new_constraint, &desktop->pointer_constraint); + desktop->presentation = + wlr_presentation_create(server->wl_display, server->backend); + return desktop; } diff --git a/rootston/output.c b/rootston/output.c index 1707be3a..8168a0c3 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -5,9 +5,10 @@ #include #include #include -#include #include +#include #include +#include #include #include #include @@ -784,6 +785,7 @@ static void output_destroy(struct roots_output *output) { wl_list_remove(&output->destroy.link); wl_list_remove(&output->mode.link); wl_list_remove(&output->transform.link); + wl_list_remove(&output->present.link); wl_list_remove(&output->damage_frame.link); wl_list_remove(&output->damage_destroy.link); free(output); @@ -820,6 +822,52 @@ static void output_handle_transform(struct wl_listener *listener, void *data) { arrange_layers(output); } +struct presentation_data { + struct layout_data layout; + struct roots_output *output; + struct wlr_presentation_event *event; +}; + +static void surface_send_presented(struct wlr_surface *surface, int sx, int sy, + void *_data) { + struct presentation_data *data = _data; + struct roots_output *output = data->output; + float rotation = data->layout.rotation; + + double lx, ly; + get_layout_position(&data->layout, &lx, &ly, surface, sx, sy); + + if (!surface_intersect_output(surface, output->desktop->layout, + output->wlr_output, lx, ly, rotation, NULL)) { + return; + } + + wlr_presentation_send_surface_presented(output->desktop->presentation, + surface, data->event); +} + +static void output_handle_present(struct wl_listener *listener, void *data) { + struct roots_output *output = + wl_container_of(listener, output, present); + struct wlr_output_event_present *output_event = data; + + struct wlr_presentation_event event = { + .output = output->wlr_output, + .tv_sec = (uint64_t)output_event->when->tv_sec, + .tv_nsec = (uint32_t)output_event->when->tv_nsec, + .refresh = 0, // TODO: predict next output vsync delay + .seq = (uint64_t)output_event->seq, + .flags = output_event->flags, + }; + + struct presentation_data presentation_data = { + .output = output, + .event = &event, + }; + output_for_each_surface(output, surface_send_presented, + &presentation_data.layout, &presentation_data); +} + void handle_new_output(struct wl_listener *listener, void *data) { struct roots_desktop *desktop = wl_container_of(listener, desktop, new_output); @@ -847,6 +895,8 @@ void handle_new_output(struct wl_listener *listener, void *data) { wl_signal_add(&wlr_output->events.mode, &output->mode); output->transform.notify = output_handle_transform; wl_signal_add(&wlr_output->events.transform, &output->transform); + output->present.notify = output_handle_present; + wl_signal_add(&wlr_output->events.present, &output->present); output->damage_frame.notify = output_damage_handle_frame; wl_signal_add(&output->damage->events.frame, &output->damage_frame); -- cgit v1.2.3 From eac7c2ad2faf49084342d9f805cf06b773723fdd Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 2 Oct 2018 12:11:09 +0200 Subject: output: add presentation refresh prediction --- backend/drm/drm.c | 15 ++++++++++++--- backend/headless/output.c | 5 +++-- backend/wayland/output.c | 2 +- backend/x11/output.c | 2 +- include/wlr/interfaces/wlr_output.h | 4 ++-- include/wlr/types/wlr_output.h | 13 +++++++++++++ rootston/output.c | 2 +- types/wlr_output.c | 23 ++++++++++++----------- types/wlr_presentation_time.c | 4 ++-- 9 files changed, 47 insertions(+), 23 deletions(-) (limited to 'rootston') diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 753b6ab8..0187e5d0 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -1154,6 +1154,10 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { attempt_enable_needs_modeset(drm); } +static int mhz_to_nsec(int mhz) { + return 1000000000000LL / mhz; +} + static void page_flip_handler(int fd, unsigned seq, unsigned tv_sec, unsigned tv_usec, void *data) { struct wlr_drm_connector *conn = data; @@ -1180,9 +1184,14 @@ static void page_flip_handler(int fd, unsigned seq, .tv_sec = tv_sec, .tv_nsec = tv_usec * 1000, }; - uint32_t present_flags = WLR_OUTPUT_PRESENT_VSYNC | - WLR_OUTPUT_PRESENT_HW_CLOCK | WLR_OUTPUT_PRESENT_HW_COMPLETION; - wlr_output_send_present(&conn->output, &present_time, seq, present_flags); + struct wlr_output_event_present present_event = { + .when = &present_time, + .seq = seq, + .refresh = mhz_to_nsec(conn->output.refresh), + .flags = WLR_OUTPUT_PRESENT_VSYNC | WLR_OUTPUT_PRESENT_HW_CLOCK | + WLR_OUTPUT_PRESENT_HW_COMPLETION, + }; + wlr_output_send_present(&conn->output, &present_event); if (drm->session->active) { wlr_output_send_frame(&conn->output); diff --git a/backend/headless/output.c b/backend/headless/output.c index ad0050d8..3cb35dce 100644 --- a/backend/headless/output.c +++ b/backend/headless/output.c @@ -67,8 +67,9 @@ static bool output_make_current(struct wlr_output *wlr_output, int *buffer_age) static bool output_swap_buffers(struct wlr_output *wlr_output, pixman_region32_t *damage) { - wlr_output_send_present(wlr_output, NULL, 0, 0); - return true; // No-op + // Nothing needs to be done for pbuffers + wlr_output_send_present(wlr_output, NULL); + return true; } static void output_destroy(struct wlr_output *wlr_output) { diff --git a/backend/wayland/output.c b/backend/wayland/output.c index 4fbfe9d2..bc7a9f05 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -72,7 +72,7 @@ static bool output_swap_buffers(struct wlr_output *wlr_output, } // TODO: if available, use the presentation-time protocol - wlr_output_send_present(wlr_output, NULL, 0, 0); + wlr_output_send_present(wlr_output, NULL); return true; } diff --git a/backend/x11/output.c b/backend/x11/output.c index 8cd8ee33..1ac12a8d 100644 --- a/backend/x11/output.c +++ b/backend/x11/output.c @@ -106,7 +106,7 @@ static bool output_swap_buffers(struct wlr_output *wlr_output, return false; } - wlr_output_send_present(wlr_output, NULL, 0, 0); + wlr_output_send_present(wlr_output, NULL); return true; } diff --git a/include/wlr/interfaces/wlr_output.h b/include/wlr/interfaces/wlr_output.h index b06c5db0..52581768 100644 --- a/include/wlr/interfaces/wlr_output.h +++ b/include/wlr/interfaces/wlr_output.h @@ -45,7 +45,7 @@ void wlr_output_update_enabled(struct wlr_output *output, bool enabled); void wlr_output_update_needs_swap(struct wlr_output *output); void wlr_output_damage_whole(struct wlr_output *output); void wlr_output_send_frame(struct wlr_output *output); -void wlr_output_send_present(struct wlr_output *output, struct timespec *when, - unsigned seq, uint32_t flags); +void wlr_output_send_present(struct wlr_output *output, + struct wlr_output_event_present *event); #endif diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index fb3becd1..9ccfbbb5 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -130,15 +130,28 @@ struct wlr_output_event_swap_buffers { }; enum wlr_output_present_flag { + // The presentation was synchronized to the "vertical retrace" by the + // display hardware such that tearing does not happen. WLR_OUTPUT_PRESENT_VSYNC = 0x1, + // The display hardware provided measurements that the hardware driver + // converted into a presentation timestamp. WLR_OUTPUT_PRESENT_HW_CLOCK = 0x2, + // The display hardware signalled that it started using the new image + // content. WLR_OUTPUT_PRESENT_HW_COMPLETION = 0x4, + // The presentation of this update was done zero-copy. + WLR_OUTPUT_PRESENT_ZERO_COPY = 0x8, }; struct wlr_output_event_present { struct wlr_output *output; + // Time when the content update turned into light the first time. struct timespec *when; + // Vertical retrace counter. Zero if unavailable. unsigned seq; + // Prediction of how many nanoseconds after `when` the very next output + // refresh may occur. Zero if unknown. + int refresh; // nsec uint32_t flags; // enum wlr_output_present_flag }; diff --git a/rootston/output.c b/rootston/output.c index 8168a0c3..9d376f8e 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -855,7 +855,7 @@ static void output_handle_present(struct wl_listener *listener, void *data) { .output = output->wlr_output, .tv_sec = (uint64_t)output_event->when->tv_sec, .tv_nsec = (uint32_t)output_event->when->tv_nsec, - .refresh = 0, // TODO: predict next output vsync delay + .refresh = (uint32_t)output_event->refresh, .seq = (uint64_t)output_event->seq, .flags = output_event->flags, }; diff --git a/types/wlr_output.c b/types/wlr_output.c index 25cd0734..b3840415 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -561,10 +561,17 @@ void wlr_output_schedule_frame(struct wlr_output *output) { wl_event_loop_add_idle(ev, schedule_frame_handle_idle_timer, output); } -void wlr_output_send_present(struct wlr_output *output, struct timespec *when, - unsigned seq, uint32_t flags) { +void wlr_output_send_present(struct wlr_output *output, + struct wlr_output_event_present *event) { + struct wlr_output_event_present _event = {0}; + if (event == NULL) { + event = &_event; + } + + event->output = output; + struct timespec now; - if (when == NULL) { + if (event->when == NULL) { clockid_t clock = wlr_backend_get_presentation_clock(output->backend); errno = 0; if (clock_gettime(clock, &now) != 0) { @@ -572,16 +579,10 @@ void wlr_output_send_present(struct wlr_output *output, struct timespec *when, "failed to read clock"); return; } - when = &now; + event->when = &now; } - struct wlr_output_event_present event = { - .output = output, - .when = when, - .seq = seq, - .flags = flags, - }; - wlr_signal_emit_safe(&output->events.present, &event); + wlr_signal_emit_safe(&output->events.present, event); } bool wlr_output_set_gamma(struct wlr_output *output, size_t size, diff --git a/types/wlr_presentation_time.c b/types/wlr_presentation_time.c index c83b5e99..eeba47b6 100644 --- a/types/wlr_presentation_time.c +++ b/types/wlr_presentation_time.c @@ -42,8 +42,8 @@ static void feedback_send_presented(struct wlr_presentation_feedback *feedback, uint32_t seq_hi = event->seq >> 32; uint32_t seq_lo = event->seq & 0xFFFFFFFF; wp_presentation_feedback_send_presented(feedback->resource, - tv_sec_hi, tv_sec_lo, event->tv_nsec, event->refresh, seq_hi, seq_lo, - event->flags); + tv_sec_hi, tv_sec_lo, event->tv_nsec, event->refresh, + seq_hi, seq_lo, event->flags); wl_resource_destroy(feedback->resource); } -- cgit v1.2.3