From f0f97280a0364f58c1b5fc3f95818c6969058010 Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 19 Jan 2018 23:35:23 +0100 Subject: backend/drm: fix retry pageflip --- backend/drm/drm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'backend/drm') 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); } } -- cgit v1.2.3 From 584f06ad2fb45cfc57fc1a0cdd59deec0c2d18c1 Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 19 Jan 2018 23:46:40 +0100 Subject: backend/drm: do not try a pageflip is another one is in pending --- backend/drm/drm.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'backend/drm') 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 { -- cgit v1.2.3 From 4ca38b84ede12aed3c3b807521992b3580384f76 Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 20 Jan 2018 16:43:14 +0100 Subject: 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(-) (limited to 'backend/drm') 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) { -- cgit v1.2.3 From 0365b587f03411d6a55017e111a991d466decc35 Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 21 Jan 2018 00:06:35 +0100 Subject: 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(-) (limited to 'backend/drm') 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); -- cgit v1.2.3 From ece2c1e4e200192bde19a2590b5a31f244e09524 Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 26 Jan 2018 22:11:09 +0100 Subject: 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(-) (limited to 'backend/drm') 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); } -- cgit v1.2.3 From 8d58ed502b6022e6a5e99bca98f6c45cc6deba0a Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 26 Jan 2018 22:39:23 +0100 Subject: 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(-) (limited to 'backend/drm') 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) { -- cgit v1.2.3 From 7adf13e2840bf57a2b96b73462fc7c6ca8e363da Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 27 Jan 2018 11:16:42 +0100 Subject: 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(-) (limited to 'backend/drm') 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); -- cgit v1.2.3 From 20e6861021ddce3c12f896aa2a961a4da23f98ad Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 28 Jan 2018 22:39:24 +0100 Subject: 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(-) (limited to 'backend/drm') 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; -- cgit v1.2.3 From b47e8c4a1d745c0eb7904079a9d45f201937247b Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 28 Jan 2018 23:33:38 +0100 Subject: backend/drm: do not retry pageflip when swapping buffers --- backend/drm/drm.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'backend/drm') 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; } -- cgit v1.2.3 From d498855b9d6f8d7f0ccde42a026fb0619d99b8a2 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 30 Jan 2018 10:23:35 +0100 Subject: 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 | 30 ++++++++++++------------------ 4 files changed, 31 insertions(+), 43 deletions(-) (limited to 'backend/drm') 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,15 +306,20 @@ void wlr_output_destroy(struct wlr_output *output) { } } -void wlr_output_effective_resolution(struct wlr_output *output, +void wlr_output_transformed_resolution(struct wlr_output *output, int *width, int *height) { - if (output->transform % 2 == 1) { - *width = output->height; - *height = output->width; - } else { + if (output->transform % 2 == 0) { *width = output->width; *height = output->height; + } else { + *width = output->height; + *height = output->width; } +} + +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; } @@ -323,17 +328,6 @@ 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, @@ -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); -- cgit v1.2.3 From babdd6ccf757f18ef15b50d9f16c55031a7c1944 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 30 Jan 2018 19:45:57 +0100 Subject: 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(-) (limited to 'backend/drm') 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; -- cgit v1.2.3 From bb4aeb3b2f8d739b042ab8c2f2b9b6d1caf6e26b Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 2 Feb 2018 21:01:59 +0100 Subject: 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(-) (limited to 'backend/drm') 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; -- cgit v1.2.3