From 3c96d0b68e3f3d270e885c4d7bb82ae8667ba385 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 21 May 2024 16:09:34 +0200 Subject: [PATCH] render: use single-pixel buffers for overlays, when possible The unicode-mode, and flash overlays are single color buffers. This means we can use the single-pixel buffer protocol. It's undefined whether the compositor will release the buffer or not; to make things easier, simply destroy the buffer as soon as we've committed it. Note that since compositors don't necessarily release single-pixel buffers, we can't plug them into our own buffer interface. This means we can't use buffer pointers to check if we can re-use the previous buffer (i.e. we can skip comitting a new buffer), or if we have to create a new one. It's _almost_ enough to just check if the last overlay style is the same as the current one. Except that that doesn't take window resizes into account... --- meson.build | 1 + render.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++------ terminal.c | 4 ++- wayland.c | 15 ++++++++++- wayland.h | 5 +++- 5 files changed, 92 insertions(+), 11 deletions(-) diff --git a/meson.build b/meson.build index dd698557..7c714ddf 100644 --- a/meson.build +++ b/meson.build @@ -159,6 +159,7 @@ wl_proto_xml = [ wayland_protocols_datadir / 'staging/fractional-scale/fractional-scale-v1.xml', wayland_protocols_datadir / 'unstable/tablet/tablet-unstable-v2.xml', # required by cursor-shape-v1 wayland_protocols_datadir / 'staging/cursor-shape/cursor-shape-v1.xml', + wayland_protocols_datadir / 'staging/single-pixel-buffer/single-pixel-buffer-v1.xml', ] foreach prot : wl_proto_xml diff --git a/render.c b/render.c index 3a577482..7d9baa1e 100644 --- a/render.c +++ b/render.c @@ -1559,6 +1559,58 @@ render_ime_preedit(struct terminal *term, struct buffer *buf) #endif } +static void +render_overlay_single_pixel(struct terminal *term, enum overlay_style style, + pixman_color_t color) +{ + struct wayland *wayl = term->wl; + struct wayl_sub_surface *overlay = &term->window->overlay; + + /* + * Note: we currently do *not* re-use the overlay buffer + * + * This means we'll re-create the buffer each time we render a new + * frame. This shouldn't be a problem in any of the cases where we + * use single-pixel buffers (unicode-input, and flash). + * + * Note: it's _almost_ enough to just check if + * style' == last_overlay_style + * except that doesn't take window resizes into account... + */ + + assert(style == OVERLAY_UNICODE_MODE || style == OVERLAY_FLASH); + assert(wayl->single_pixel_manager != NULL); + assert(overlay->surface.viewport != NULL); + + struct wl_buffer *buf = + wp_single_pixel_buffer_manager_v1_create_u32_rgba_buffer( + term->wl->single_pixel_manager, + (double)color.red / 0xffff * 0xffffffff, + (double)color.green / 0xffff * 0xffffffff, + (double)color.blue / 0xffff * 0xffffffff, + (double)color.alpha / 0xffff * 0xffffffff); + + wl_surface_set_buffer_scale(overlay->surface.surf, 1); + wp_viewport_set_destination( + overlay->surface.viewport, + roundf(term->width / term->scale), + roundf(term->height / term->scale)); + + quirk_weston_subsurface_desync_on(overlay->sub); + + wl_subsurface_set_position(overlay->sub, 0, 0); + wl_surface_attach(overlay->surface.surf, buf, 0, 0); + + wl_surface_damage_buffer( + overlay->surface.surf, 0, 0, term->width, term->height); + + wl_surface_commit(overlay->surface.surf); + quirk_weston_subsurface_desync_off(overlay->sub); + + term->render.last_overlay_style = style; + wl_buffer_destroy(buf); +} + static void render_overlay(struct terminal *term) { @@ -1586,17 +1638,9 @@ render_overlay(struct terminal *term) return; } - struct buffer *buf = shm_get_buffer( - term->render.chains.overlay, term->width, term->height, true); - - pixman_image_set_clip_region32(buf->pix[0], NULL); - pixman_color_t color; switch (style) { - case OVERLAY_NONE: - break; - case OVERLAY_SEARCH: case OVERLAY_UNICODE_MODE: color = (pixman_color_t){0, 0, 0, 0x7fff}; @@ -1607,8 +1651,26 @@ render_overlay(struct terminal *term) term->conf->colors.flash, term->conf->colors.flash_alpha); break; + + case OVERLAY_NONE: + xassert(false); + break; } + const bool single_pixel = + (style == OVERLAY_UNICODE_MODE || style == OVERLAY_FLASH) && + term->wl->single_pixel_manager != NULL && + overlay->surface.viewport != NULL; + + if (single_pixel) { + render_overlay_single_pixel(term, style, color); + return; + } + + struct buffer *buf = shm_get_buffer( + term->render.chains.overlay, term->width, term->height, true); + pixman_image_set_clip_region32(buf->pix[0], NULL); + /* Bounding rectangle of damaged areas - for wl_surface_damage_buffer() */ pixman_box32_t damage_bounds; diff --git a/terminal.c b/terminal.c index 9443467c..55c387c1 100644 --- a/terminal.c +++ b/terminal.c @@ -2195,7 +2195,9 @@ term_font_size_reset(struct terminal *term) bool term_fractional_scaling(const struct terminal *term) { - return term->wl->fractional_scale_manager != NULL && term->window->scale > 0.; + return term->wl->fractional_scale_manager != NULL && + term->wl->viewporter != NULL && + term->window->scale > 0.; } bool diff --git a/wayland.c b/wayland.c index 4add34e3..d65a404e 100644 --- a/wayland.c +++ b/wayland.c @@ -1320,6 +1320,16 @@ handle_global(void *data, struct wl_registry *registry, wayl->registry, name, &wp_cursor_shape_manager_v1_interface, required); } + else if (streq(interface, wp_single_pixel_buffer_manager_v1_interface.name)) { + const uint32_t required = 1; + if (!verify_iface_version(interface, version, required)) + return; + + wayl->single_pixel_manager = wl_registry_bind( + wayl->registry, name, + &wp_single_pixel_buffer_manager_v1_interface, required); + } + #if defined(FOOT_IME_ENABLED) && FOOT_IME_ENABLED else if (streq(interface, zwp_text_input_manager_v3_interface.name)) { const uint32_t required = 1; @@ -1636,6 +1646,8 @@ wayl_destroy(struct wayland *wayl) zwp_text_input_manager_v3_destroy(wayl->text_input_manager); #endif + if (wayl->single_pixel_manager != NULL) + wp_single_pixel_buffer_manager_v1_destroy(wayl->single_pixel_manager); if (wayl->fractional_scale_manager != NULL) wp_fractional_scale_manager_v1_destroy(wayl->fractional_scale_manager); if (wayl->viewporter != NULL) @@ -2058,6 +2070,7 @@ surface_scale_explicit_width_height( } } + xassert(surf->viewport != NULL); wl_surface_set_buffer_scale(surf->surf, 1); wp_viewport_set_destination( surf->viewport, roundf(width / scale), roundf(height / scale)); @@ -2204,7 +2217,7 @@ wayl_win_subsurface_new_with_custom_parent( } struct wp_viewport *viewport = NULL; - if (wayl->fractional_scale_manager != NULL && wayl->viewporter != NULL) { + if (wayl->viewporter != NULL) { viewport = wp_viewporter_get_viewport(wayl->viewporter, main_surface); if (viewport == NULL) { LOG_ERR("failed to instantiate viewport for sub-surface"); diff --git a/wayland.h b/wayland.h index 215640aa..7688fbdb 100644 --- a/wayland.h +++ b/wayland.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -439,10 +440,12 @@ struct wayland { struct wp_cursor_shape_manager_v1 *cursor_shape_manager; + struct wp_single_pixel_buffer_manager_v1 *single_pixel_manager; + bool presentation_timings; struct wp_presentation *presentation; uint32_t presentation_clock_id; - + #if defined(FOOT_IME_ENABLED) && FOOT_IME_ENABLED struct zwp_text_input_manager_v3 *text_input_manager; #endif