[gtk/wip/chergert/glproto: 717/920] flesh out glyph uploads a bit




commit 5a6be53302e8ace7a0769c47faf017fbd4bd738b
Author: Christian Hergert <chergert redhat com>
Date:   Tue Jan 19 14:24:22 2021 -0800

    flesh out glyph uploads a bit
    
    still plenty to work on here, but some basics in place

 gsk/next/gskglglyphlibrary.c          | 171 +++++++++++++++++++++++-
 gsk/next/gskglglyphlibraryprivate.h   |  14 +-
 gsk/next/gskgliconlibrary.c           |   2 +
 gsk/next/gskglrenderjob.c             |   9 +-
 gsk/next/gskglshadowlibrary.c         |   2 +
 gsk/next/gskgltextureatlas.c          | 238 ----------------------------------
 gsk/next/gskgltextureatlasprivate.h   |  36 -----
 gsk/next/gskgltexturelibrary.c        |  23 +++-
 gsk/next/gskgltexturelibraryprivate.h |   6 +-
 9 files changed, 209 insertions(+), 292 deletions(-)
---
diff --git a/gsk/next/gskglglyphlibrary.c b/gsk/next/gskglglyphlibrary.c
index 3710697636..3b633bafdc 100644
--- a/gsk/next/gskglglyphlibrary.c
+++ b/gsk/next/gskglglyphlibrary.c
@@ -20,6 +20,9 @@
 
 #include "config.h"
 
+#include <gdk/gdkglcontextprivate.h>
+#include <gdk/gdkmemorytextureprivate.h>
+
 #include "gskgldriverprivate.h"
 #include "gskglglyphlibraryprivate.h"
 
@@ -66,7 +69,10 @@ gsk_gl_glyph_key_equal (gconstpointer v1,
 static void
 gsk_gl_glyph_key_free (gpointer data)
 {
-  g_slice_free (GskGLGlyphKey, data);
+  GskGLGlyphKey *key = data;
+
+  g_clear_object (&key->font);
+  g_slice_free (GskGLGlyphKey, key);
 }
 
 static void
@@ -81,6 +87,7 @@ gsk_gl_glyph_library_finalize (GObject *object)
   GskGLGlyphLibrary *self = (GskGLGlyphLibrary *)object;
 
   g_clear_pointer (&self->hash_table, g_hash_table_unref);
+  g_clear_pointer (&self->surface_data, g_free);
 
   G_OBJECT_CLASS (gsk_gl_glyph_library_parent_class)->finalize (object);
 }
@@ -104,9 +111,160 @@ gsk_gl_glyph_library_init (GskGLGlyphLibrary *self)
                                     gsk_gl_glyph_value_free);
 }
 
+static cairo_surface_t *
+gsk_gl_glyph_library_create_surface (GskGLGlyphLibrary *self,
+                                     int                stride,
+                                     int                width,
+                                     int                height,
+                                     double             device_scale)
+{
+  cairo_surface_t *surface;
+  gsize n_bytes;
+
+  g_assert (GSK_IS_GL_GLYPH_LIBRARY (self));
+  g_assert (width > 0);
+  g_assert (height > 0);
+
+  n_bytes = stride * height;
+
+  if G_LIKELY (n_bytes > self->surface_data_len)
+    {
+      self->surface_data = g_realloc (self->surface_data, n_bytes);
+      self->surface_data_len = n_bytes;
+    }
+
+  memset (self->surface_data, 0, n_bytes);
+  surface = cairo_image_surface_create_for_data (self->surface_data,
+                                                 CAIRO_FORMAT_ARGB32,
+                                                 width, height, stride);
+  cairo_surface_set_device_scale (surface, device_scale, device_scale);
+
+  return surface;
+}
+
+static void
+render_glyph (cairo_surface_t           *surface,
+              const cairo_scaled_font_t *scaled_font,
+              const GskGLGlyphKey       *key,
+              const GskGLGlyphValue     *value)
+{
+  cairo_t *cr;
+  PangoGlyphString glyph_string;
+  PangoGlyphInfo glyph_info;
+
+  g_assert (surface != NULL);
+  g_assert (scaled_font != NULL);
+
+  cr = cairo_create (surface);
+  cairo_set_scaled_font (cr, scaled_font);
+  cairo_set_source_rgba (cr, 1, 1, 1, 1);
+
+  glyph_info.glyph = key->glyph;
+  glyph_info.geometry.width = value->ink_rect.width * 1024;
+  if (glyph_info.glyph & PANGO_GLYPH_UNKNOWN_FLAG)
+    glyph_info.geometry.x_offset = 0;
+  else
+    glyph_info.geometry.x_offset = - value->ink_rect.x * 1024;
+  glyph_info.geometry.y_offset = - value->ink_rect.y * 1024;
+
+  glyph_string.num_glyphs = 1;
+  glyph_string.glyphs = &glyph_info;
+
+  pango_cairo_show_glyph_string (cr, key->font, &glyph_string);
+  cairo_destroy (cr);
+
+  cairo_surface_flush (surface);
+}
+
+static void
+gsk_gl_glyph_library_upload_glyph (GskGLGlyphLibrary     *self,
+                                   const GskGLGlyphKey   *key,
+                                   const GskGLGlyphValue *value,
+                                   int                    width,
+                                   int                    height,
+                                   double                 device_scale)
+{
+  cairo_scaled_font_t *scaled_font;
+  GskGLTextureAtlas *atlas;
+  cairo_surface_t *surface;
+  guchar *pixel_data;
+  guchar *free_data = NULL;
+  guint gl_format;
+  guint gl_type;
+  guint texture_id;
+  gsize stride;
+  int x, y;
+
+  g_assert (GSK_IS_GL_GLYPH_LIBRARY (self));
+  g_assert (key != NULL);
+  g_assert (value != NULL);
+
+  scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *)key->font);
+  if G_UNLIKELY (scaled_font == NULL ||
+                 cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS)
+    return;
+
+  stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, width);
+  atlas = value->entry.is_atlased ? value->entry.atlas : NULL;
+
+  gdk_gl_context_push_debug_group_printf (gdk_gl_context_get_current (),
+                                          "Uploading glyph %d",
+                                          key->glyph);
+
+  surface = gsk_gl_glyph_library_create_surface (self, stride, width, height, device_scale);
+  render_glyph (surface, scaled_font, key, value);
+
+  texture_id = GSK_GL_TEXTURE_ATLAS_ENTRY_TEXTURE (value);
+
+  g_assert (texture_id > 0);
+
+  glPixelStorei (GL_UNPACK_ROW_LENGTH, stride / 4);
+  glBindTexture (GL_TEXTURE_2D, texture_id);
+
+  if G_UNLIKELY (gdk_gl_context_get_use_es (gdk_gl_context_get_current ()))
+    {
+      pixel_data = free_data = g_malloc (width * height * 4);
+      gdk_memory_convert (pixel_data,
+                          width * 4,
+                          GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
+                          cairo_image_surface_get_data (surface),
+                          width * 4,
+                          GDK_MEMORY_DEFAULT,
+                          width, height);
+      gl_format = GL_RGBA;
+      gl_type = GL_UNSIGNED_BYTE;
+    }
+  else
+    {
+      pixel_data = cairo_image_surface_get_data (surface);
+      gl_format = GL_BGRA;
+      gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
+    }
+
+  if G_LIKELY (atlas != NULL)
+    {
+      x = atlas->width * value->entry.area.origin.x;
+      y = atlas->width * value->entry.area.origin.y;
+    }
+  else
+    {
+      x = 0;
+      y = 0;
+    }
+
+  glTexSubImage2D (GL_TEXTURE_2D, 0, x, y, width, height,
+                   gl_format, gl_type, pixel_data);
+  glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
+
+  cairo_surface_destroy (surface);
+  g_free (free_data);
+
+  gdk_gl_context_pop_debug_group (gdk_gl_context_get_current ());
+}
+
 gboolean
 gsk_gl_glyph_library_add (GskGLGlyphLibrary      *self,
-                          const GskGLGlyphKey    *key,
+                          GskGLGlyphKey          *key,
                           const GskGLGlyphValue **out_value)
 {
   PangoRectangle ink_rect;
@@ -131,14 +289,21 @@ gsk_gl_glyph_library_add (GskGLGlyphLibrary      *self,
 
   value = gsk_gl_texture_library_pack (GSK_GL_TEXTURE_LIBRARY (self),
                                        key,
-                                       sizeof *key,
                                        sizeof *value,
                                        width,
                                        height);
 
   memcpy (&value->ink_rect, &ink_rect, sizeof ink_rect);
 
+  if (key->scale > 0 && width > 0 && height > 0)
+    gsk_gl_glyph_library_upload_glyph (self,
+                                       key,
+                                       value,
+                                       width,
+                                       height,
+                                       key->scale / 1024.0);
 
+  *out_value = value;
 
   return TRUE;
 }
diff --git a/gsk/next/gskglglyphlibraryprivate.h b/gsk/next/gskglglyphlibraryprivate.h
index b373339ce1..3e7a286148 100644
--- a/gsk/next/gskglglyphlibraryprivate.h
+++ b/gsk/next/gskglglyphlibraryprivate.h
@@ -54,13 +54,15 @@ G_DECLARE_FINAL_TYPE (GskGLGlyphLibrary, gsk_gl_glyph_library, GSK, GL_GLYPH_LIB
 
 struct _GskGLGlyphLibrary
 {
-  GskGLTextureLibrary parent_instance;
-  GHashTable *hash_table;
+  GskGLTextureLibrary  parent_instance;
+  GHashTable          *hash_table;
+  guint8              *surface_data;
+  gsize                surface_data_len;
 };
 
 GskGLGlyphLibrary *gsk_gl_glyph_library_new (GskNextDriver          *driver);
 gboolean           gsk_gl_glyph_library_add (GskGLGlyphLibrary      *self,
-                                             const GskGLGlyphKey    *key,
+                                             GskGLGlyphKey          *key,
                                              const GskGLGlyphValue **out_value);
 
 static inline int
@@ -86,6 +88,7 @@ gsk_gl_glyph_library_lookup_or_add (GskGLGlyphLibrary      *self,
                                     const GskGLGlyphValue **out_value)
 {
   GskGLTextureAtlasEntry *entry;
+  GskGLGlyphKey *k;
 
   if G_LIKELY (gsk_gl_texture_library_lookup ((GskGLTextureLibrary *)self, key, &entry))
     {
@@ -93,7 +96,10 @@ gsk_gl_glyph_library_lookup_or_add (GskGLGlyphLibrary      *self,
       return TRUE;
     }
 
-  return gsk_gl_glyph_library_add (self, key, out_value);
+  k = g_slice_copy (sizeof *key, key);
+  g_object_ref (k->font);
+
+  return gsk_gl_glyph_library_add (self, k, out_value);
 }
 
 G_END_DECLS
diff --git a/gsk/next/gskgliconlibrary.c b/gsk/next/gskgliconlibrary.c
index 5cbdccb04a..207ff04ea5 100644
--- a/gsk/next/gskgliconlibrary.c
+++ b/gsk/next/gskgliconlibrary.c
@@ -48,4 +48,6 @@ gsk_gl_icon_library_class_init (GskGLIconLibraryClass *klass)
 static void
 gsk_gl_icon_library_init (GskGLIconLibrary *self)
 {
+  gsk_gl_texture_library_set_funcs (GSK_GL_TEXTURE_LIBRARY (self),
+                                    NULL, NULL, NULL, NULL);
 }
diff --git a/gsk/next/gskglrenderjob.c b/gsk/next/gskglrenderjob.c
index c1ac95ec88..3e467c10ea 100644
--- a/gsk/next/gskglrenderjob.c
+++ b/gsk/next/gskglrenderjob.c
@@ -2538,13 +2538,20 @@ gsk_gl_render_job_visit_text_node (GskGLRenderJob *job,
 
       texture_id = GSK_GL_TEXTURE_ATLAS_ENTRY_TEXTURE (glyph);
 
-      if (last_texture != texture_id)
+      if G_UNLIKELY (last_texture != texture_id)
         {
+          gsk_gl_program_end_draw (program);
           gsk_gl_program_set_uniform_texture (program,
                                               UNIFORM_SHARED_SOURCE,
                                               GL_TEXTURE_2D,
                                               GL_TEXTURE0,
                                               texture_id);
+          gsk_gl_program_begin_draw (program,
+                                     &job->viewport,
+                                     &job->projection,
+                                     gsk_gl_render_job_get_modelview_matrix (job),
+                                     gsk_gl_render_job_get_clip (job),
+                                     job->alpha);
           last_texture = texture_id;
         }
 
diff --git a/gsk/next/gskglshadowlibrary.c b/gsk/next/gskglshadowlibrary.c
index dbcba6f6ed..f33c608b10 100644
--- a/gsk/next/gskglshadowlibrary.c
+++ b/gsk/next/gskglshadowlibrary.c
@@ -48,4 +48,6 @@ gsk_gl_shadow_library_class_init (GskGLShadowLibraryClass *klass)
 static void
 gsk_gl_shadow_library_init (GskGLShadowLibrary *self)
 {
+  gsk_gl_texture_library_set_funcs (GSK_GL_TEXTURE_LIBRARY (self),
+                                    NULL, NULL, NULL, NULL);
 }
diff --git a/gsk/next/gskgltexturelibrary.c b/gsk/next/gskgltexturelibrary.c
index c4ef5e849d..347fcf8490 100644
--- a/gsk/next/gskgltexturelibrary.c
+++ b/gsk/next/gskgltexturelibrary.c
@@ -232,8 +232,7 @@ gsk_gl_texture_atlases_pack (GskNextDriver      *driver,
 
 gpointer
 gsk_gl_texture_library_pack (GskGLTextureLibrary *self,
-                             gconstpointer        key,
-                             gsize                keylen,
+                             gpointer             key,
                              gsize                valuelen,
                              guint                width,
                              guint                height)
@@ -243,14 +242,26 @@ gsk_gl_texture_library_pack (GskGLTextureLibrary *self,
 
   g_assert (GSK_IS_GL_TEXTURE_LIBRARY (self));
   g_assert (key != NULL);
-  g_assert (keylen > 0);
   g_assert (valuelen > sizeof (GskGLTextureAtlasEntry));
 
   entry = g_slice_alloc0 (valuelen);
   entry->n_pixels = width * height;
   entry->accessed = TRUE;
 
-  if (width <= self->max_entry_size && height <= self->max_entry_size)
+  /* If our size is invisible then we just want an entry in the
+   * cache for faster lookups, but do not actually spend any texture
+   * allocations on this entry.
+   */
+  if (width <= 0 && height <= 0)
+    {
+      entry->is_atlased = FALSE;
+      entry->texture = NULL;
+      entry->area.origin.x = 0.0f;
+      entry->area.origin.y = 0.0f;
+      entry->area.size.width = 0.0f;
+      entry->area.size.height = 0.0f;
+    }
+  else if (width <= self->max_entry_size && height <= self->max_entry_size)
     {
       int packed_x;
       int packed_y;
@@ -281,9 +292,7 @@ gsk_gl_texture_library_pack (GskGLTextureLibrary *self,
       entry->area.size.height = 1.0f;
     }
 
-  g_hash_table_insert (self->hash_table,
-                       g_slice_copy (keylen, key),
-                       entry);
+  g_hash_table_insert (self->hash_table, key, entry);
 
   return entry;
 }
diff --git a/gsk/next/gskgltexturelibraryprivate.h b/gsk/next/gskgltexturelibraryprivate.h
index 491f87b6b8..0f9b554954 100644
--- a/gsk/next/gskgltexturelibraryprivate.h
+++ b/gsk/next/gskgltexturelibraryprivate.h
@@ -113,8 +113,7 @@ void     gsk_gl_texture_library_set_funcs   (GskGLTextureLibrary    *self,
 void     gsk_gl_texture_library_begin_frame (GskGLTextureLibrary    *self);
 void     gsk_gl_texture_library_end_frame   (GskGLTextureLibrary    *self);
 gpointer gsk_gl_texture_library_pack        (GskGLTextureLibrary    *self,
-                                             gconstpointer           key,
-                                             gsize                   keylen,
+                                             gpointer                key,
                                              gsize                   valuelen,
                                              guint                   width,
                                              guint                   height);
@@ -172,7 +171,8 @@ GSK_GL_TEXTURE_ATLAS_ENTRY_TEXTURE (gconstpointer d)
 {
   const GskGLTextureAtlasEntry *e = d;
 
-  return e->is_atlased ? e->atlas->texture_id : e->texture->texture_id;
+  return e->is_atlased ? e->atlas->texture_id
+                       : e->texture ? e->texture->texture_id : 0;
 }
 
 static inline double


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