From 5db953aa899609af7d634491bade5418aa351262 Mon Sep 17 00:00:00 2001 From: tokyo4j Date: Tue, 3 Dec 2024 16:18:52 +0900 Subject: [PATCH] scaled-scene-buffer: reduce unnecessary renderings Prior to this commit, a backing buffer with scale 1 was always created for a scaled_scene_buffer before showing it, and backing buffers for specific scales were created on output_enter events. This commit removes this redundant re-renderings by calling wlr_scene_buffer_set_dest_size() upon scaled_scene_buffer creation just to receive output_enter events and delaying the first rendering to the first output_enter event. I needed to add font_get_buffer_size() to obtain the size of a font buffer without actually creating it. --- include/common/font.h | 6 ++++++ include/common/scaled-scene-buffer.h | 13 +++++++++++-- src/common/font.c | 23 ++++++++++++++++------- src/common/scaled-font-buffer.c | 19 +++++++++---------- src/common/scaled-rect-buffer.c | 3 ++- src/common/scaled-scene-buffer.c | 28 +++++++++++++++++++++++++--- 6 files changed, 69 insertions(+), 23 deletions(-) diff --git a/include/common/font.h b/include/common/font.h index ea734229..c9e9c179 100644 --- a/include/common/font.h +++ b/include/common/font.h @@ -36,6 +36,12 @@ int font_height(struct font *font); */ int font_width(struct font *font, const char *string); +/** + * font_get_buffer_size - dry-run font_buffer_create() to get buffer size + */ +void font_get_buffer_size(int max_width, const char *text, struct font *font, + int *width, int *height); + /** * font_buffer_create - Create ARGB8888 lab_data_buffer using pango * @buffer: buffer pointer diff --git a/include/common/scaled-scene-buffer.h b/include/common/scaled-scene-buffer.h index 5c365595..f1c1d124 100644 --- a/include/common/scaled-scene-buffer.h +++ b/include/common/scaled-scene-buffer.h @@ -96,8 +96,17 @@ struct scaled_scene_buffer *scaled_scene_buffer_create( const struct scaled_scene_buffer_impl *implementation, struct wl_list *cached_buffers, bool drop_buffer); -/* Clear the cache of existing buffers, useful in case the content changes */ -void scaled_scene_buffer_invalidate_cache(struct scaled_scene_buffer *self); +/** + * scaled_scene_buffer_request_update - mark the buffer that needs to be + * updated + * @width: the width of the buffer to be rendered, in scene coordinates + * @height: the height of the buffer to be rendered, in scene coordinates + * + * This function should be called when the states bound to the buffer are + * updated and ready for rendering. + */ +void scaled_scene_buffer_request_update(struct scaled_scene_buffer *self, + int width, int height); /* Private */ struct scaled_scene_buffer_cache_entry { diff --git a/src/common/font.c b/src/common/font.c index 4c406c42..0014eaf1 100644 --- a/src/common/font.c +++ b/src/common/font.c @@ -79,6 +79,18 @@ font_width(struct font *font, const char *string) return rectangle.width; } +void +font_get_buffer_size(int max_width, const char *text, struct font *font, + int *width, int *height) +{ + PangoRectangle text_extents = font_extents(font, text); + if (max_width > 0 && text_extents.width > max_width) { + text_extents.width = max_width; + } + *width = text_extents.width; + *height = text_extents.height; +} + void font_buffer_create(struct lab_data_buffer **buffer, int max_width, const char *text, struct font *font, const float *color, @@ -88,13 +100,10 @@ font_buffer_create(struct lab_data_buffer **buffer, int max_width, return; } - PangoRectangle text_extents = font_extents(font, text); - - if (max_width > 0 && text_extents.width > max_width) { - text_extents.width = max_width; - } + int width, height; + font_get_buffer_size(max_width, text, font, &width, &height); - *buffer = buffer_create_cairo(text_extents.width, text_extents.height, scale); + *buffer = buffer_create_cairo(width, height, scale); if (!*buffer) { wlr_log(WLR_ERROR, "Failed to create font buffer"); return; @@ -127,7 +136,7 @@ font_buffer_create(struct lab_data_buffer **buffer, int max_width, PangoLayout *layout = pango_cairo_create_layout(cairo); pango_context_set_round_glyph_positions(pango_layout_get_context(layout), false); - pango_layout_set_width(layout, text_extents.width * PANGO_SCALE); + pango_layout_set_width(layout, width * PANGO_SCALE); pango_layout_set_text(layout, text, -1); pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END); diff --git a/src/common/scaled-font-buffer.c b/src/common/scaled-font-buffer.c index 78849b72..e8a9b0a5 100644 --- a/src/common/scaled-font-buffer.c +++ b/src/common/scaled-font-buffer.c @@ -116,21 +116,20 @@ scaled_font_buffer_update(struct scaled_font_buffer *self, const char *text, memcpy(self->color, color, sizeof(self->color)); memcpy(self->bg_color, bg_color, sizeof(self->bg_color)); - /* Invalidate cache and force a new render */ - scaled_scene_buffer_invalidate_cache(self->scaled_buffer); - - /* Ensure the height / width is up-to-date */ - self->width = self->scaled_buffer->width; - self->height = self->scaled_buffer->height; + /* Calculate the size of font buffer and request re-rendering */ + font_get_buffer_size(self->max_width, self->text, &self->font, + &self->width, &self->height); + scaled_scene_buffer_request_update(self->scaled_buffer, + self->width, self->height); } void scaled_font_buffer_set_max_width(struct scaled_font_buffer *self, int max_width) { self->max_width = max_width; - scaled_scene_buffer_invalidate_cache(self->scaled_buffer); - /* Ensure the height / width is up-to-date */ - self->width = self->scaled_buffer->width; - self->height = self->scaled_buffer->height; + font_get_buffer_size(self->max_width, self->text, &self->font, + &self->width, &self->height); + scaled_scene_buffer_request_update(self->scaled_buffer, + self->width, self->height); } diff --git a/src/common/scaled-rect-buffer.c b/src/common/scaled-rect-buffer.c index 10457cd9..04b5e6d7 100644 --- a/src/common/scaled-rect-buffer.c +++ b/src/common/scaled-rect-buffer.c @@ -110,7 +110,8 @@ struct scaled_rect_buffer *scaled_rect_buffer_create( memcpy(self->fill_color, fill_color, sizeof(self->fill_color)); memcpy(self->border_color, border_color, sizeof(self->border_color)); - scaled_scene_buffer_invalidate_cache(scaled_buffer); + scaled_scene_buffer_request_update(scaled_buffer, + self->width, self->height); return self; } diff --git a/src/common/scaled-scene-buffer.c b/src/common/scaled-scene-buffer.c index cb6bf14a..6a19891a 100644 --- a/src/common/scaled-scene-buffer.c +++ b/src/common/scaled-scene-buffer.c @@ -228,7 +228,11 @@ scaled_scene_buffer_create(struct wlr_scene_tree *parent, } self->impl = impl; - self->active_scale = 1; + /* + * Set active scale to zero so that we always render a new buffer when + * entering the first output + */ + self->active_scale = 0; self->drop_buffer = drop_buffer; wl_list_init(&self->cache); @@ -254,7 +258,8 @@ scaled_scene_buffer_create(struct wlr_scene_tree *parent, } void -scaled_scene_buffer_invalidate_cache(struct scaled_scene_buffer *self) +scaled_scene_buffer_request_update(struct scaled_scene_buffer *self, + int width, int height) { assert(self); struct scaled_scene_buffer_cache_entry *cache_entry, *cache_entry_tmp; @@ -262,5 +267,22 @@ scaled_scene_buffer_invalidate_cache(struct scaled_scene_buffer *self) _cache_entry_destroy(cache_entry, self->drop_buffer); } assert(wl_list_empty(&self->cache)); - _update_buffer(self, self->active_scale); + + /* + * Tell wlroots about the buffer size so we can receive output_enter + * events even when the actual backing buffer is not set yet. + * The buffer size set here is updated when the backing buffer is + * created in _update_buffer(). + */ + wlr_scene_buffer_set_dest_size(self->scene_buffer, width, height); + self->width = width; + self->height = height; + + /* + * Skip re-rendering if the buffer is not shown yet + * TODO: don't re-render also when the buffer is temporarily invisible + */ + if (self->active_scale > 0) { + _update_buffer(self, self->active_scale); + } } -- 2.52.0