[gtk/wip/chergert/glproto] add shadow library



commit 0faead81b7cd089f35d41d03bfb84d196e157a8a
Author: Christian Hergert <chergert redhat com>
Date:   Thu Jan 28 12:11:26 2021 -0800

    add shadow library

 gsk/next/TODO.md                     |   1 +
 gsk/next/gskgldriver.c               |  31 +++++-
 gsk/next/gskgldriverprivate.h        |   4 +
 gsk/next/gskglshadowlibrary.c        | 183 ++++++++++++++++++++++++++++++++++-
 gsk/next/gskglshadowlibraryprivate.h |  20 ++--
 5 files changed, 224 insertions(+), 15 deletions(-)
---
diff --git a/gsk/next/TODO.md b/gsk/next/TODO.md
index 6523abd32f..028ed5d661 100644
--- a/gsk/next/TODO.md
+++ b/gsk/next/TODO.md
@@ -8,4 +8,5 @@
  * Try to hold on to cached textures for more frames
  * Add debug tooling for sysprof so we can capture frame information
  * OpenGL Shader transitions missing main()
+ * Ensure drivers are disposed when surface is released
 
diff --git a/gsk/next/gskgldriver.c b/gsk/next/gskgldriver.c
index 6f1bada783..231ca3c4f3 100644
--- a/gsk/next/gskgldriver.c
+++ b/gsk/next/gskgldriver.c
@@ -505,7 +505,7 @@ gsk_next_driver_begin_frame (GskNextDriver     *self,
 
   gsk_gl_texture_library_begin_frame (GSK_GL_TEXTURE_LIBRARY (self->icons));
   gsk_gl_texture_library_begin_frame (GSK_GL_TEXTURE_LIBRARY (self->glyphs));
-  gsk_gl_texture_library_begin_frame (GSK_GL_TEXTURE_LIBRARY (self->shadows));
+  gsk_gl_shadow_library_begin_frame (self->shadows);
 
   /* Remove all textures that are from a previous frame or are no
    * longer used by linked GdkTexture. We do this at the beginning
@@ -535,7 +535,6 @@ gsk_next_driver_end_frame (GskNextDriver *self)
 
   gsk_gl_texture_library_end_frame (GSK_GL_TEXTURE_LIBRARY (self->icons));
   gsk_gl_texture_library_end_frame (GSK_GL_TEXTURE_LIBRARY (self->glyphs));
-  gsk_gl_texture_library_end_frame (GSK_GL_TEXTURE_LIBRARY (self->shadows));
 
   while (self->render_targets->len > 0)
     {
@@ -1246,3 +1245,31 @@ gsk_next_driver_slice_texture (GskNextDriver      *self,
   t->slices = *out_slices = slices;
   t->n_slices = *out_n_slices = n_slices;
 }
+
+void
+gsk_next_driver_mark_texture_permanent (GskNextDriver *self,
+                                        guint          texture_id)
+{
+  GskGLTexture *t;
+
+  g_return_if_fail (GSK_IS_NEXT_DRIVER (self));
+  g_return_if_fail (texture_id > 0);
+
+  if ((t = g_hash_table_lookup (self->textures, GUINT_TO_POINTER (texture_id))))
+    t->permanent = TRUE;
+}
+
+void
+gsk_next_driver_release_texture_by_id (GskNextDriver *self,
+                                       guint          texture_id)
+{
+  GskGLTexture *texture;
+
+  g_return_if_fail (GSK_IS_NEXT_DRIVER (self));
+  g_return_if_fail (texture_id > 0);
+
+  if ((texture = g_hash_table_lookup (self->textures, GUINT_TO_POINTER (texture_id))))
+    gsk_next_driver_release_texture (self, texture);
+  else
+    remove_texture_key_for_id (self, texture_id);
+}
diff --git a/gsk/next/gskgldriverprivate.h b/gsk/next/gskgldriverprivate.h
index b56310ba8b..12bc7a4fed 100644
--- a/gsk/next/gskgldriverprivate.h
+++ b/gsk/next/gskgldriverprivate.h
@@ -156,6 +156,10 @@ GskGLTexture      *gsk_next_driver_acquire_texture       (GskNextDriver        *
                                                           int                   mag_filter);
 void               gsk_next_driver_release_texture       (GskNextDriver        *self,
                                                           GskGLTexture         *texture);
+void               gsk_next_driver_release_texture_by_id (GskNextDriver        *self,
+                                                          guint                 texture_id);
+void               gsk_next_driver_mark_texture_permanent(GskNextDriver        *self,
+                                                          guint                 texture_id);
 void               gsk_next_driver_slice_texture         (GskNextDriver        *self,
                                                           GdkTexture           *texture,
                                                           GskGLTextureSlice   **out_slices,
diff --git a/gsk/next/gskglshadowlibrary.c b/gsk/next/gskglshadowlibrary.c
index f33c608b10..79ede9c95d 100644
--- a/gsk/next/gskglshadowlibrary.c
+++ b/gsk/next/gskglshadowlibrary.c
@@ -20,15 +20,37 @@
 
 #include "config.h"
 
+#include <string.h>
+
 #include "gskgldriverprivate.h"
 #include "gskglshadowlibraryprivate.h"
 
+#define MAX_UNUSED_FRAMES (16 * 5)
+
 struct _GskGLShadowLibrary
 {
-  GskGLTextureLibrary parent_instance;
+  GObject        parent_instance;
+  GskNextDriver *driver;
+  GArray        *shadows;
+};
+
+typedef struct _Shadow
+{
+  GskRoundedRect outline;
+  float          blur_radius;
+  guint          texture_id;
+  gint64         last_used_in_frame;
+} Shadow;
+
+G_DEFINE_TYPE (GskGLShadowLibrary, gsk_gl_shadow_library, G_TYPE_OBJECT)
+
+enum {
+  PROP_0,
+  PROP_DRIVER,
+  N_PROPS
 };
 
-G_DEFINE_TYPE (GskGLShadowLibrary, gsk_gl_shadow_library, GSK_TYPE_GL_TEXTURE_LIBRARY)
+static GParamSpec *properties [N_PROPS];
 
 GskGLShadowLibrary *
 gsk_gl_shadow_library_new (GskNextDriver *driver)
@@ -40,14 +62,167 @@ gsk_gl_shadow_library_new (GskNextDriver *driver)
                        NULL);
 }
 
+static void
+gsk_gl_shadow_library_dispose (GObject *object)
+{
+  GskGLShadowLibrary *self = (GskGLShadowLibrary *)object;
+
+  for (guint i = 0; i < self->shadows->len; i++)
+    {
+      const Shadow *shadow = &g_array_index (self->shadows, Shadow, i);
+      gsk_next_driver_release_texture_by_id (self->driver, shadow->texture_id);
+    }
+
+  g_clear_pointer (&self->shadows, g_array_unref);
+  g_clear_object (&self->driver);
+
+  G_OBJECT_CLASS (gsk_gl_shadow_library_parent_class)->dispose (object);
+}
+
+static void
+gsk_gl_shadow_library_get_property (GObject    *object,
+                                    guint       prop_id,
+                                    GValue     *value,
+                                    GParamSpec *pspec)
+{
+  GskGLShadowLibrary *self = GSK_GL_SHADOW_LIBRARY (object);
+
+  switch (prop_id)
+    {
+    case PROP_DRIVER:
+      g_value_set_object (value, self->driver);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gsk_gl_shadow_library_set_property (GObject      *object,
+                                    guint         prop_id,
+                                    const GValue *value,
+                                    GParamSpec   *pspec)
+{
+  GskGLShadowLibrary *self = GSK_GL_SHADOW_LIBRARY (object);
+
+  switch (prop_id)
+    {
+    case PROP_DRIVER:
+      self->driver = g_value_dup_object (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
 static void
 gsk_gl_shadow_library_class_init (GskGLShadowLibraryClass *klass)
 {
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = gsk_gl_shadow_library_dispose;
+  object_class->get_property = gsk_gl_shadow_library_get_property;
+  object_class->set_property = gsk_gl_shadow_library_set_property;
+
+  properties [PROP_DRIVER] =
+    g_param_spec_object ("driver",
+                         "Driver",
+                         "Driver",
+                         GSK_TYPE_NEXT_DRIVER,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
 }
 
 static void
 gsk_gl_shadow_library_init (GskGLShadowLibrary *self)
 {
-  gsk_gl_texture_library_set_funcs (GSK_GL_TEXTURE_LIBRARY (self),
-                                    NULL, NULL, NULL, NULL);
+  self->shadows = g_array_new (FALSE, FALSE, sizeof (Shadow));
+}
+
+void
+gsk_gl_shadow_library_insert (GskGLShadowLibrary   *self,
+                              const GskRoundedRect *outline,
+                              float                 blur_radius,
+                              guint                 texture_id)
+{
+  Shadow *shadow;
+
+  g_return_if_fail (GSK_IS_GL_SHADOW_LIBRARY (self));
+  g_return_if_fail (outline != NULL);
+  g_return_if_fail (texture_id != 0);
+
+  gsk_next_driver_mark_texture_permanent (self->driver, texture_id);
+
+  g_array_set_size (self->shadows, self->shadows->len + 1);
+
+  shadow = &g_array_index (self->shadows, Shadow, self->shadows->len - 1);
+  shadow->outline = *outline;
+  shadow->blur_radius = blur_radius;
+  shadow->texture_id = texture_id;
+  shadow->last_used_in_frame = self->driver->current_frame_id;
+}
+
+guint
+gsk_gl_shadow_library_lookup (GskGLShadowLibrary   *self,
+                              const GskRoundedRect *outline,
+                              float                 blur_radius)
+{
+  Shadow *ret = NULL;
+
+  g_return_val_if_fail (GSK_IS_GL_SHADOW_LIBRARY (self), 0);
+  g_return_val_if_fail (outline != NULL, 0);
+
+  /* Ensure GskRoundedRect  is 12 packed floats without padding
+   * so that we can use memcmp instead of float comparisons.
+   */
+  G_STATIC_ASSERT (sizeof *outline == (sizeof (float) * 12));
+
+  for (guint i = 0; i < self->shadows->len; i++)
+    {
+      Shadow *shadow = &g_array_index (self->shadows, Shadow, i);
+
+      if (blur_radius == shadow->blur_radius &&
+          memcmp (outline, &shadow->outline, sizeof *outline) == 0)
+        {
+          ret = shadow;
+          break;
+        }
+    }
+
+  if (ret == NULL)
+    return 0;
+
+  g_assert (ret->texture_id != 0);
+
+  ret->last_used_in_frame = self->driver->current_frame_id;
+
+  return ret->texture_id;
+}
+
+void
+gsk_gl_shadow_library_begin_frame (GskGLShadowLibrary *self)
+{
+  gint64 watermark;
+  int i;
+  int p;
+
+  g_return_if_fail (GSK_IS_GL_SHADOW_LIBRARY (self));
+
+  watermark = self->driver->current_frame_id - MAX_UNUSED_FRAMES;
+
+  for (i = 0, p = self->shadows->len; i < p; i++)
+    {
+      const Shadow *shadow = &g_array_index (self->shadows, Shadow, i);
+
+      if (shadow->last_used_in_frame < watermark)
+        {
+          gsk_next_driver_release_texture_by_id (self->driver, shadow->texture_id);
+          g_array_remove_index_fast (self->shadows, i);
+          p--;
+          i--;
+        }
+    }
 }
diff --git a/gsk/next/gskglshadowlibraryprivate.h b/gsk/next/gskglshadowlibraryprivate.h
index 57f952395c..437ad6d39d 100644
--- a/gsk/next/gskglshadowlibraryprivate.h
+++ b/gsk/next/gskglshadowlibraryprivate.h
@@ -25,17 +25,19 @@
 
 G_BEGIN_DECLS
 
-typedef struct _GskGLShadowKey
-{
-  GskRoundedRect rounded_rect;
-  float blur_radius;
-} GskGLShadowKey;
-
 #define GSK_TYPE_GL_SHADOW_LIBRARY (gsk_gl_shadow_library_get_type())
 
-G_DECLARE_FINAL_TYPE (GskGLShadowLibrary, gsk_gl_shadow_library, GSK, GL_SHADOW_LIBRARY, GskGLTextureLibrary)
-
-GskGLShadowLibrary *gsk_gl_shadow_library_new (GskNextDriver *driver);
+G_DECLARE_FINAL_TYPE (GskGLShadowLibrary, gsk_gl_shadow_library, GSK, GL_SHADOW_LIBRARY, GObject)
+
+GskGLShadowLibrary *gsk_gl_shadow_library_new         (GskNextDriver        *driver);
+void                gsk_gl_shadow_library_begin_frame (GskGLShadowLibrary   *self);
+guint               gsk_gl_shadow_library_lookup      (GskGLShadowLibrary   *self,
+                                                       const GskRoundedRect *outline,
+                                                       float                 blur_radius);
+void                gsk_gl_shadow_library_insert      (GskGLShadowLibrary   *self,
+                                                       const GskRoundedRect *outline,
+                                                       float                 blur_radius,
+                                                       guint                 texture_id);
 
 G_END_DECLS
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]