]> git.mdlowis.com Git - proto/labwc.git/commitdiff
scaled_scene_buffer: make dropping the buffer optional
authorConsolatis <35009135+Consolatis@users.noreply.github.com>
Sat, 14 Oct 2023 20:26:40 +0000 (22:26 +0200)
committerJohan Malm <johanmalm@users.noreply.github.com>
Thu, 19 Oct 2023 20:48:57 +0000 (21:48 +0100)
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
include/common/scaled_scene_buffer.h
src/common/scaled_font_buffer.c
src/common/scaled_scene_buffer.c

index cba277efa6b1e8ead6d592af859b744e0d106c24..42fd3ad51cbc59049dd6fa3ba631715daea2f82a 100644 (file)
@@ -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;
index 114737679d20875c685c14606f8c78acf30d7965..d0d96920c3599c47e9338f19b9118f54a96e7b41 100644 (file)
@@ -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);
index 3daae5934d6cb5c02eea0201dfa92eded4e4469b..a9b33a853749a66f55aae4409f6ce4054db9c00a 100644 (file)
@@ -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;
index 13737beacf604794baffc00cd83ebe801cd5bd52..abe99b2604e6c28957d9439d17f262feb03531d2 100644 (file)
 
 /* 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);