From 8d17ab2d60dd862b9e6ec3e1336065c91cf09bf5 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Sat, 14 Oct 2023 22:26:40 +0200 Subject: [PATCH] scaled_scene_buffer: make dropping the buffer optional In preparation to also use the scaled_scene_buffer for theme components like rounded corner images and button icons. No functional change intended. --- include/common/scaled_font_buffer.h | 2 +- include/common/scaled_scene_buffer.h | 27 ++++++++++++++++++++++++++- src/common/scaled_font_buffer.c | 6 ++++-- src/common/scaled_scene_buffer.c | 26 ++++++++++++++++++++------ 4 files changed, 51 insertions(+), 10 deletions(-) diff --git a/include/common/scaled_font_buffer.h b/include/common/scaled_font_buffer.h index cba277ef..42fd3ad5 100644 --- a/include/common/scaled_font_buffer.h +++ b/include/common/scaled_font_buffer.h @@ -6,7 +6,7 @@ struct wlr_scene_tree; struct wlr_scene_buffer; -struct scaled_scene_buffere; +struct scaled_scene_buffer; struct scaled_font_buffer { struct wlr_scene_buffer *scene_buffer; diff --git a/include/common/scaled_scene_buffer.h b/include/common/scaled_scene_buffer.h index 11473767..d0d96920 100644 --- a/include/common/scaled_scene_buffer.h +++ b/include/common/scaled_scene_buffer.h @@ -26,6 +26,7 @@ struct scaled_scene_buffer { void *data; /* opaque user data */ /* Private */ + bool drop_buffer; double active_scale; struct wl_list cache; /* struct scaled_buffer_cache_entry.link */ struct wl_listener destroy; @@ -51,10 +52,34 @@ struct scaled_scene_buffer { * wlr_scene_buffer is being destroyed. If implementation->destroy is set * it will also get called so a consumer of this API may clean up its own * allocations. + * + * All requested lab_data_buffers via impl->create_buffer() will be locked + * during the lifetime of the buffer in the internal cache and unlocked + * when being evacuated from the cache (due to LAB_SCALED_BUFFER_MAX_CACHE + * or the internal wlr_scene_buffer being destroyed). + * + * If drop_buffer was set during creation of the scaled_scene_buffer, the + * backing wlr_buffer behind a lab_data_buffer will also get dropped + * (via wlr_buffer_drop). If there are no more locks (consumers) of the + * respective buffer this will then cause the lab_data_buffer to be free'd. + * + * In the case of the buffer provider dropping the buffer itself (due to + * for example a Reconfigure event) the lock prevents the buffer from being + * destroyed until the buffer is evacuated from the internal cache and thus + * unlocked. + * + * This allows using scaled_scene_buffer for an autoscaling font_buffer + * (which gets free'd automatically) and also for theme components like + * rounded corner images or button icons whose buffers only exist once but + * are references by multiple windows with their own scaled_scene_buffers. + * + * The rough idea is: use drop_buffer = true for one-shot buffers and false + * for buffers that should outlive the scaled_scene_buffer instance itself. */ struct scaled_scene_buffer *scaled_scene_buffer_create( struct wlr_scene_tree *parent, - const struct scaled_scene_buffer_impl *implementation); + const struct scaled_scene_buffer_impl *implementation, + 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); diff --git a/src/common/scaled_font_buffer.c b/src/common/scaled_font_buffer.c index 3daae593..a9b33a85 100644 --- a/src/common/scaled_font_buffer.c +++ b/src/common/scaled_font_buffer.c @@ -30,10 +30,12 @@ static void _destroy(struct scaled_scene_buffer *scaled_buffer) { struct scaled_font_buffer *self = scaled_buffer->data; + scaled_buffer->data = NULL; + zfree(self->text); zfree(self->font.name); zfree(self->arrow); - zfree(scaled_buffer->data); + free(self); } static const struct scaled_scene_buffer_impl impl = { @@ -48,7 +50,7 @@ scaled_font_buffer_create(struct wlr_scene_tree *parent) assert(parent); struct scaled_font_buffer *self = znew(*self); struct scaled_scene_buffer *scaled_buffer = - scaled_scene_buffer_create(parent, &impl); + scaled_scene_buffer_create(parent, &impl, /* drop_buffer */ true); if (!scaled_buffer) { free(self); return NULL; diff --git a/src/common/scaled_scene_buffer.c b/src/common/scaled_scene_buffer.c index 13737bea..abe99b26 100644 --- a/src/common/scaled_scene_buffer.c +++ b/src/common/scaled_scene_buffer.c @@ -36,11 +36,15 @@ /* Internal API */ static void -_cache_entry_destroy(struct scaled_scene_buffer_cache_entry *cache_entry) +_cache_entry_destroy(struct scaled_scene_buffer_cache_entry *cache_entry, bool drop_buffer) { wl_list_remove(&cache_entry->link); if (cache_entry->buffer) { - wlr_buffer_drop(cache_entry->buffer); + /* Allow the buffer to get dropped if there are no further consumers */ + wlr_buffer_unlock(cache_entry->buffer); + if (drop_buffer) { + wlr_buffer_drop(cache_entry->buffer); + } } free(cache_entry); } @@ -64,6 +68,10 @@ _update_buffer(struct scaled_scene_buffer *self, double scale) /* Create new buffer, will get destroyed along the backing wlr_buffer */ struct lab_data_buffer *buffer = self->impl->create_buffer(self, scale); + if (buffer) { + /* Ensure the buffer doesn't get deleted behind our back */ + wlr_buffer_lock(&buffer->base); + } self->width = buffer ? buffer->unscaled_width : 0; self->height = buffer ? buffer->unscaled_height : 0; @@ -73,7 +81,11 @@ _update_buffer(struct scaled_scene_buffer *self, double scale) } else { cache_entry = wl_container_of(self->cache.prev, cache_entry, link); if (cache_entry->buffer) { - wlr_buffer_drop(cache_entry->buffer); + /* Allow the old buffer to get dropped if there are no further consumers */ + wlr_buffer_unlock(cache_entry->buffer); + if (self->drop_buffer) { + wlr_buffer_drop(cache_entry->buffer); + } } wl_list_remove(&cache_entry->link); } @@ -100,7 +112,7 @@ _handle_node_destroy(struct wl_listener *listener, void *data) wl_list_remove(&self->output_leave.link); wl_list_for_each_safe(cache_entry, cache_entry_tmp, &self->cache, link) { - _cache_entry_destroy(cache_entry); + _cache_entry_destroy(cache_entry, self->drop_buffer); } assert(wl_list_empty(&self->cache)); @@ -146,7 +158,8 @@ _handle_output_leave(struct wl_listener *listener, void *data) /* Public API */ struct scaled_scene_buffer * scaled_scene_buffer_create(struct wlr_scene_tree *parent, - const struct scaled_scene_buffer_impl *impl) + const struct scaled_scene_buffer_impl *impl, + bool drop_buffer) { assert(parent); assert(impl); @@ -162,6 +175,7 @@ scaled_scene_buffer_create(struct wlr_scene_tree *parent, self->impl = impl; self->active_scale = 1; + self->drop_buffer = drop_buffer; wl_list_init(&self->cache); /* Listen to output enter/leave so we get notified about scale changes */ @@ -183,7 +197,7 @@ scaled_scene_buffer_invalidate_cache(struct scaled_scene_buffer *self) assert(self); struct scaled_scene_buffer_cache_entry *cache_entry, *cache_entry_tmp; wl_list_for_each_safe(cache_entry, cache_entry_tmp, &self->cache, link) { - _cache_entry_destroy(cache_entry); + _cache_entry_destroy(cache_entry, self->drop_buffer); } assert(wl_list_empty(&self->cache)); _update_buffer(self, self->active_scale);