[gtk/wip/chergert/glyphy: 3/7] gsk/gl: allow texture libraries more allocation control




commit edf9695ff8b7e4124cb79af207fb450de2a694f6
Author: Christian Hergert <chergert redhat com>
Date:   Thu Mar 17 16:45:42 2022 -0700

    gsk/gl: allow texture libraries more allocation control
    
    Some texture libraries may want to be in control of where things are
    allocated and not even use the stbrp_pack_rects() implementation. This is
    a first step at abstracting those so that we can potentially even abstract
    those into an allocator structure.
    
    With this in place, the glyph library can control it's use of a 1x1 pixel
    for line drawing from within the subclass without causing extraneous
    allocations in unrelated atlases.

 gsk/gl/gskglglyphlibrary.c          |  49 ++++++++++++
 gsk/gl/gskgltexturelibrary.c        | 148 +++++++++++++++++-------------------
 gsk/gl/gskgltexturelibraryprivate.h |  19 ++++-
 3 files changed, 135 insertions(+), 81 deletions(-)
---
diff --git a/gsk/gl/gskglglyphlibrary.c b/gsk/gl/gskglglyphlibrary.c
index ee13198921..5afebb0577 100644
--- a/gsk/gl/gskglglyphlibrary.c
+++ b/gsk/gl/gskglglyphlibrary.c
@@ -93,6 +93,54 @@ gsk_gl_glyph_library_clear_cache (GskGLTextureLibrary *library)
   memset (self->front, 0, sizeof self->front);
 }
 
+static void
+gsk_gl_glyph_library_init_atlas (GskGLTextureLibrary *library,
+                                 GskGLTextureAtlas   *atlas)
+{
+  gboolean packed G_GNUC_UNUSED;
+  int x, y;
+  guint gl_format;
+  guint gl_type;
+  guint8 pixel_data[4 * 3 * 3];
+
+  g_assert (GSK_IS_GL_GLYPH_LIBRARY (library));
+  g_assert (atlas != NULL);
+
+  /* Insert a single pixel at 0,0 for use in coloring */
+
+  gdk_gl_context_push_debug_group_printf (gdk_gl_context_get_current (),
+                                          "Initializing Glyph Atlas");
+
+  packed = GSK_GL_TEXTURE_LIBRARY_GET_CLASS (library)->allocate (library, atlas, 3, 3, &x, &y);
+  g_assert (packed);
+  g_assert (x == 0 && y == 0);
+
+  memset (pixel_data, 255, sizeof pixel_data);
+
+  if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ()))
+    {
+      gl_format = GL_RGBA;
+      gl_type = GL_UNSIGNED_BYTE;
+    }
+  else
+    {
+      gl_format = GL_BGRA;
+      gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
+    }
+
+  glBindTexture (GL_TEXTURE_2D, atlas->texture_id);
+
+  glTexSubImage2D (GL_TEXTURE_2D, 0,
+                   0, 0,
+                   3, 3,
+                   gl_format, gl_type,
+                   pixel_data);
+
+  gdk_gl_context_pop_debug_group (gdk_gl_context_get_current ());
+
+  library->driver->command_queue->n_uploads++;
+}
+
 static void
 gsk_gl_glyph_library_finalize (GObject *object)
 {
@@ -112,6 +160,7 @@ gsk_gl_glyph_library_class_init (GskGLGlyphLibraryClass *klass)
   object_class->finalize = gsk_gl_glyph_library_finalize;
 
   library_class->clear_cache = gsk_gl_glyph_library_clear_cache;
+  library_class->init_atlas = gsk_gl_glyph_library_init_atlas;
 }
 
 static void
diff --git a/gsk/gl/gskgltexturelibrary.c b/gsk/gl/gskgltexturelibrary.c
index da99ea9500..fd5f172923 100644
--- a/gsk/gl/gskgltexturelibrary.c
+++ b/gsk/gl/gskgltexturelibrary.c
@@ -41,6 +41,53 @@ enum {
 
 static GParamSpec *properties [N_PROPS];
 
+static inline gboolean
+gsk_gl_texture_atlas_pack (GskGLTextureAtlas *self,
+                           int                width,
+                           int                height,
+                           int               *out_x,
+                           int               *out_y)
+{
+  stbrp_rect rect;
+
+  rect.w = width;
+  rect.h = height;
+
+  stbrp_pack_rects (&self->context, &rect, 1);
+
+  if (rect.was_packed)
+    {
+      *out_x = rect.x;
+      *out_y = rect.y;
+    }
+
+  return rect.was_packed;
+}
+
+static void
+gsk_gl_texture_library_real_init_atlas (GskGLTextureLibrary *self,
+                                        GskGLTextureAtlas   *atlas)
+{
+}
+
+static gboolean
+gsk_gl_texture_library_real_allocate (GskGLTextureLibrary *self,
+                                      GskGLTextureAtlas   *atlas,
+                                      int                  width,
+                                      int                  height,
+                                      int                 *out_x,
+                                      int                 *out_y)
+{
+  g_assert (GSK_IS_GL_TEXTURE_LIBRARY (self));
+  g_assert (atlas != NULL);
+  g_assert (width > 0);
+  g_assert (height > 0);
+  g_assert (out_x != NULL);
+  g_assert (out_y != NULL);
+
+  return gsk_gl_texture_atlas_pack (atlas, width, height, out_x, out_y);
+}
+
 static void
 gsk_gl_texture_library_constructed (GObject *object)
 {
@@ -107,6 +154,9 @@ gsk_gl_texture_library_class_init (GskGLTextureLibraryClass *klass)
   object_class->get_property = gsk_gl_texture_library_get_property;
   object_class->set_property = gsk_gl_texture_library_set_property;
 
+  klass->init_atlas = gsk_gl_texture_library_real_init_atlas;
+  klass->allocate = gsk_gl_texture_library_real_allocate;
+
   properties [PROP_DRIVER] =
     g_param_spec_object ("driver",
                          "Driver",
@@ -247,90 +297,33 @@ gsk_gl_texture_library_pack_one (GskGLTextureLibrary *self,
   return texture;
 }
 
-static inline gboolean
-gsk_gl_texture_atlas_pack (GskGLTextureAtlas *self,
-                           int                width,
-                           int                height,
-                           int               *out_x,
-                           int               *out_y)
-{
-  stbrp_rect rect;
-
-  rect.w = width;
-  rect.h = height;
-
-  stbrp_pack_rects (&self->context, &rect, 1);
-
-  if (rect.was_packed)
-    {
-      *out_x = rect.x;
-      *out_y = rect.y;
-    }
-
-  return rect.was_packed;
-}
-
 static void
-gsk_gl_texture_atlas_initialize (GskGLDriver       *driver,
-                                 GskGLTextureAtlas *atlas)
+gsk_gl_texture_atlases_pack (GskGLTextureLibrary  *self,
+                             int                   width,
+                             int                   height,
+                             GskGLTextureAtlas   **out_atlas,
+                             int                  *out_x,
+                             int                  *out_y)
 {
-  /* Insert a single pixel at 0,0 for use in coloring */
-
-  gboolean packed G_GNUC_UNUSED;
+  GskGLTextureAtlas *atlas = NULL;
+  GskGLTextureLibraryClass *klass;
+  GskGLDriver *driver;
   int x, y;
-  guint gl_format;
-  guint gl_type;
-  guint8 pixel_data[4 * 3 * 3];
-
-  gdk_gl_context_push_debug_group_printf (gdk_gl_context_get_current (),
-                                          "Initializing Atlas");
-
-  packed = gsk_gl_texture_atlas_pack (atlas, 3, 3, &x, &y);
-  g_assert (packed);
-  g_assert (x == 0 && y == 0);
-
-  memset (pixel_data, 255, sizeof pixel_data);
-
-  if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ()))
-    {
-      gl_format = GL_RGBA;
-      gl_type = GL_UNSIGNED_BYTE;
-    }
-  else
-    {
-      gl_format = GL_BGRA;
-      gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
-    }
 
-  glBindTexture (GL_TEXTURE_2D, atlas->texture_id);
-
-  glTexSubImage2D (GL_TEXTURE_2D, 0,
-                   0, 0,
-                   3, 3,
-                   gl_format, gl_type,
-                   pixel_data);
-
-  gdk_gl_context_pop_debug_group (gdk_gl_context_get_current ());
-
-  driver->command_queue->n_uploads++;
-}
+  g_assert (GSK_IS_GL_TEXTURE_LIBRARY (self));
+  g_assert (GSK_IS_GL_DRIVER (self->driver));
+  g_assert (out_atlas != NULL);
+  g_assert (out_x != NULL);
+  g_assert (out_y != NULL);
 
-static void
-gsk_gl_texture_atlases_pack (GskGLDriver        *driver,
-                             int                 width,
-                             int                 height,
-                             GskGLTextureAtlas **out_atlas,
-                             int                *out_x,
-                             int                *out_y)
-{
-  GskGLTextureAtlas *atlas = NULL;
-  int x, y;
+  driver = self->driver;
+  klass = GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self);
 
   for (guint i = 0; i < driver->atlases->len; i++)
     {
       atlas = g_ptr_array_index (driver->atlases, i);
 
-      if (gsk_gl_texture_atlas_pack (atlas, width, height, &x, &y))
+      if (klass->allocate (self, atlas, width, height, &x, &y))
         break;
 
       atlas = NULL;
@@ -341,10 +334,11 @@ gsk_gl_texture_atlases_pack (GskGLDriver        *driver,
       /* No atlas has enough space, so create a new one... */
       atlas = gsk_gl_driver_create_atlas (driver, self->atlas_width, self->atlas_height);
 
-      gsk_gl_texture_atlas_initialize (driver, atlas);
+      /* Allow subclass to initialize the atlas */
+      GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->init_atlas (self, atlas);
 
       /* Pack it onto that one, which surely has enough space... */
-      if (!gsk_gl_texture_atlas_pack (atlas, width, height, &x, &y))
+      if (!klass->allocate (self, atlas, width, height, &x, &y))
         g_assert_not_reached ();
     }
 
@@ -400,7 +394,7 @@ gsk_gl_texture_library_pack (GskGLTextureLibrary *self,
       int packed_x;
       int packed_y;
 
-      gsk_gl_texture_atlases_pack (self->driver,
+      gsk_gl_texture_atlases_pack (self,
                                    padding + width + padding,
                                    padding + height + padding,
                                    &atlas,
diff --git a/gsk/gl/gskgltexturelibraryprivate.h b/gsk/gl/gskgltexturelibraryprivate.h
index 26a35bd4af..8fd1d6d11a 100644
--- a/gsk/gl/gskgltexturelibraryprivate.h
+++ b/gsk/gl/gskgltexturelibraryprivate.h
@@ -50,6 +50,9 @@ typedef struct _GskGLTextureAtlas
    */
   int unused_pixels;
 
+  /* Used by library subclasses */
+  int cursor_x;
+  int cursor_y;
 } GskGLTextureAtlas;
 
 typedef struct _GskGLTextureAtlasEntry
@@ -101,10 +104,18 @@ typedef struct _GskGLTextureLibraryClass
 {
   GObjectClass parent_class;
 
-  void (*begin_frame) (GskGLTextureLibrary *library,
-                       gint64               frame_id,
-                       GPtrArray           *removed_atlases);
-  void (*clear_cache) (GskGLTextureLibrary *library);
+  void     (*begin_frame)  (GskGLTextureLibrary *library,
+                            gint64               frame_id,
+                            GPtrArray           *removed_atlases);
+  void     (*clear_cache)  (GskGLTextureLibrary *library);
+  void     (*init_atlas)   (GskGLTextureLibrary *library,
+                            GskGLTextureAtlas   *atlas);
+  gboolean (*allocate)     (GskGLTextureLibrary *library,
+                            GskGLTextureAtlas   *atlas,
+                            int                  width,
+                            int                  height,
+                            int                 *packed_x,
+                            int                 *packed_y);
 } GskGLTextureLibraryClass;
 
 G_DEFINE_AUTOPTR_CLEANUP_FUNC (GskGLTextureLibrary, g_object_unref)


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