[gtk+/wip/matthiasc/text-node] wip: work towards per-glyph instances



commit aec50193b0bea3fdf979b9e16f359d46d87e6372
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Sep 10 13:27:58 2017 -0400

    wip: work towards per-glyph instances
    
    Doesn't quite work yet

 gsk/gskprivate.c                   |   20 ++++
 gsk/gskprivate.h                   |    3 +
 gsk/gskrendernodeimpl.c            |   20 ++++
 gsk/gskrendernodeprivate.h         |    2 +
 gsk/gskvulkanrender.c              |    2 +-
 gsk/gskvulkanrenderer.c            |  186 +++++++++++++++++++++++++++++++++---
 gsk/gskvulkanrendererprivate.h     |    8 ++
 gsk/gskvulkanrenderpass.c          |   14 ++-
 gsk/gskvulkanrenderpassprivate.h   |    1 +
 gsk/gskvulkantextpipeline.c        |   82 +++++++++++-----
 gsk/gskvulkantextpipelineprivate.h |   11 ++-
 11 files changed, 308 insertions(+), 41 deletions(-)
---
diff --git a/gsk/gskprivate.c b/gsk/gskprivate.c
index 8404b9d..d9e1c3e 100644
--- a/gsk/gskprivate.c
+++ b/gsk/gskprivate.c
@@ -15,3 +15,23 @@ gsk_ensure_resources (void)
 
   g_once (&register_resources_once, register_resources, NULL);
 }
+
+int
+pango_glyph_string_num_glyphs (PangoGlyphString *glyphs)
+{
+  int i, count;
+
+  count = 0;
+  for (i = 0; i < glyphs->num_glyphs; i++)
+    {
+      PangoGlyphInfo *gi = &glyphs->glyphs[i];
+      if (gi->glyph != PANGO_GLYPH_EMPTY)
+        {
+          if (!(gi->glyph & PANGO_GLYPH_UNKNOWN_FLAG))
+            count++;
+        }
+    }
+
+  return count;
+}
+
diff --git a/gsk/gskprivate.h b/gsk/gskprivate.h
index 84539c1..8584be6 100644
--- a/gsk/gskprivate.h
+++ b/gsk/gskprivate.h
@@ -2,11 +2,14 @@
 #define __GSK_PRIVATE_H__
 
 #include <glib.h>
+#include <pango/pango.h>
 
 G_BEGIN_DECLS
 
 void gsk_ensure_resources (void);
 
+int pango_glyph_string_num_glyphs (PangoGlyphString *glyphs);
+
 G_END_DECLS
 
 #endif /* __GSK_PRIVATE_H__ */
diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c
index 9e5c7da..a46bb01 100644
--- a/gsk/gskrendernodeimpl.c
+++ b/gsk/gskrendernodeimpl.c
@@ -3980,6 +3980,26 @@ gsk_text_node_get_glyphs (GskRenderNode *node)
   return self->glyphs;
 }
 
+float
+gsk_text_node_get_x (GskRenderNode *node)
+{
+  GskTextNode *self = (GskTextNode *) node;
+
+  g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_TEXT_NODE), 0.0);
+
+  return (float)self->x;
+}
+
+float
+gsk_text_node_get_y (GskRenderNode *node)
+{
+  GskTextNode *self = (GskTextNode *) node;
+
+  g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_TEXT_NODE), 0.0);
+
+  return (float)self->y;
+}
+
 /*** GSK_BLUR_NODE ***/
 
 typedef struct _GskBlurNode GskBlurNode;
diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h
index 7639e7e..4934ea3 100644
--- a/gsk/gskrendernodeprivate.h
+++ b/gsk/gskrendernodeprivate.h
@@ -84,6 +84,8 @@ GskTexture *gsk_texture_node_get_texture (GskRenderNode *node);
 PangoFont *gsk_text_node_get_font (GskRenderNode *node);
 PangoGlyphString *gsk_text_node_get_glyphs (GskRenderNode *node);
 const GdkRGBA *gsk_text_node_get_color (GskRenderNode *node);
+float gsk_text_node_get_x (GskRenderNode *node);
+float gsk_text_node_get_y (GskRenderNode *node);
 
 const GdkRGBA *gsk_color_node_peek_color (GskRenderNode *node);
 
diff --git a/gsk/gskvulkanrender.c b/gsk/gskvulkanrender.c
index a695381..6398829 100644
--- a/gsk/gskvulkanrender.c
+++ b/gsk/gskvulkanrender.c
@@ -305,7 +305,7 @@ gsk_vulkan_render_collect_vertex_data (GskVulkanRender *self)
 
   for (l = self->render_passes; l; l = l->next)
     {
-      offset += gsk_vulkan_render_pass_collect_vertex_data (l->data, data, offset, n_bytes - offset);
+      offset += gsk_vulkan_render_pass_collect_vertex_data (l->data, self, data, offset, n_bytes - offset);
       g_assert (offset <= n_bytes);
     }
 
diff --git a/gsk/gskvulkanrenderer.c b/gsk/gskvulkanrenderer.c
index 57262e6..9d50253 100644
--- a/gsk/gskvulkanrenderer.c
+++ b/gsk/gskvulkanrenderer.c
@@ -44,6 +44,8 @@ struct _GskVulkanRenderer
 
   GSList *textures;
 
+  GHashTable *glyph_cache;
+
 #ifdef G_ENABLE_DEBUG
   ProfileTimers profile_timers;
 #endif
@@ -350,12 +352,17 @@ gsk_vulkan_renderer_ref_texture_image (GskVulkanRenderer *self,
 
 #define STACK_ARRAY_LENGTH(T) (STACK_BUFFER_SIZE / sizeof(T))
 
+typedef struct {
+  PangoGlyph glyph;
+  float x, y, width, height;
+} GlyphCoords;
+
 static void
 render_text (cairo_t          *cr,
              PangoFont        *font,
              PangoGlyphString *glyphs,
-             GskRectangle     *glyph_rects,
-             int              *num_glyphs,
+             GlyphCoords      *coords,
+             int              *num_coords,
              float             x,
              float             y,
              float             width,
@@ -395,10 +402,11 @@ render_text (cairo_t          *cr,
               cairo_glyphs[count].x = cx;
               cairo_glyphs[count].y = cy;
 
-              glyph_rects[count].x = cx / width;
-              glyph_rects[count].y = 0.0;
-              glyph_rects[count].width = (float)gi->geometry.width / width;
-              glyph_rects[count].height = 1.0; // FIXME get actual glyph height
+              coords[count].glyph = gi->glyph;
+              coords[count].x = cx / width;
+              coords[count].y = 0.0;
+              coords[count].width = (float)gi->geometry.width / (PANGO_SCALE * width);
+              coords[count].height = 1.0; // FIXME get actual glyph height
 
               count++;
             }
@@ -406,7 +414,7 @@ render_text (cairo_t          *cr,
       x_position += gi->geometry.width;
     }
 
-  *num_glyphs = count;
+  *num_coords = count;
 
   cairo_show_glyphs (cr, cairo_glyphs, count);
 
@@ -414,6 +422,126 @@ render_text (cairo_t          *cr,
     g_free (cairo_glyphs);
 }
 
+typedef struct {
+  PangoFont *font;
+  PangoGlyphString *glyphs;
+  guint hash;
+  GlyphCoords *coords;
+  int num_coords;
+} CacheItem;
+
+static guint
+item_hash (gconstpointer key)
+{
+  const CacheItem *item = key;
+  PangoFontDescription *desc;
+  guint32 h = 5381;
+  char *p, *end;
+
+  if (item->hash != 0)
+    return item->hash;
+
+  end = ((char *)&item->glyphs->glyphs[item->glyphs->num_glyphs]);
+  for (p = (char *)item->glyphs->glyphs; p < end; p++)
+    h = (h << 5) + h + *p;
+
+  desc = pango_font_describe (item->font);
+  h ^= pango_font_description_hash (desc);
+  pango_font_description_free (desc);
+
+  if (h == 0)
+    h = 1;
+
+  return h;
+}
+
+static gboolean
+item_equal (gconstpointer v1, gconstpointer v2)
+{
+  const CacheItem *i1 = v1;
+  const CacheItem *i2 = v2;
+  int i;
+  PangoFontDescription *desc1, *desc2;
+  gboolean ret;
+
+  if (i1->glyphs->num_glyphs != i2->glyphs->num_glyphs)
+    return FALSE;
+
+  for (i = 0; i < i1->glyphs->num_glyphs; i++)
+    {
+      if (i1->glyphs->glyphs[i].glyph != i2->glyphs->glyphs[i].glyph)
+        return FALSE;
+    }
+
+  desc1 = pango_font_describe (i1->font);
+  desc2 = pango_font_describe (i2->font);
+  ret = pango_font_description_equal (desc1, desc2);
+  pango_font_description_free (desc1);
+  pango_font_description_free (desc2);
+
+  return ret;
+}
+
+static void
+item_free (gpointer data)
+{
+  CacheItem *item = data;
+
+  g_object_unref (item->font);
+  pango_glyph_string_free (item->glyphs);
+  g_free (item->coords);
+  g_free (item);
+}
+
+static void
+ensure_cache (GskVulkanRenderer *renderer)
+{
+  if (!renderer->glyph_cache)
+    renderer->glyph_cache = g_hash_table_new_full (item_hash, item_equal, NULL, item_free);
+}
+
+static int
+find_cached_item (GskVulkanRenderer *renderer, PangoFont *font, PangoGlyphString *glyphs, GlyphCoords 
**coords)
+{
+  CacheItem key;
+  CacheItem *value;
+
+  key.font = font;
+  key.glyphs = glyphs;
+  key.hash = 0;
+  key.coords = NULL;
+  key.num_coords = 0;
+
+  ensure_cache (renderer);
+
+  value = g_hash_table_lookup (renderer->glyph_cache, &key);
+  if (value)
+    {
+      *coords = value->coords;
+      return value->num_coords;
+    }
+
+  return 0;
+}
+
+static void
+cache_item (GskVulkanRenderer *renderer, PangoFont *font, PangoGlyphString *glyphs, GlyphCoords *coords, int 
num_coords)
+{
+  CacheItem *item;
+
+  item = g_new (CacheItem, 1);
+
+  item->font = g_object_ref (font);
+  item->glyphs = pango_glyph_string_copy (glyphs);
+  item->hash = 0;
+  item->coords = coords;
+  item->num_coords = num_coords;
+
+  ensure_cache (renderer);
+
+  g_hash_table_add (renderer->glyph_cache, item);
+}
+
 GskVulkanImage *
 gsk_vulkan_renderer_ref_glyph_image (GskVulkanRenderer  *self,
                                      GskVulkanUploader  *uploader,
@@ -424,10 +552,10 @@ gsk_vulkan_renderer_ref_glyph_image (GskVulkanRenderer  *self,
   cairo_surface_t *surface;
   cairo_t *cr;
   GskVulkanImage *image;
-  GskRectangle *glyph_rects;
-  int num_glyphs;
+  GlyphCoords *coords;
+  int num_coords;
 
-  glyph_rects = g_new (GskRectangle, glyphs->num_glyphs);
+  coords = g_new0 (GlyphCoords, glyphs->num_glyphs);
 
   pango_glyph_string_extents (glyphs, font, &ink_rect, NULL);
   pango_extents_to_pixels (&ink_rect, NULL);
@@ -437,7 +565,7 @@ gsk_vulkan_renderer_ref_glyph_image (GskVulkanRenderer  *self,
                                         ink_rect.height);
 
   cr = cairo_create (surface);
-  render_text (cr, font, glyphs, glyph_rects, &num_glyphs,
+  render_text (cr, font, glyphs, coords, &num_coords,
                0, - ink_rect.y, ink_rect.x + ink_rect.width, ink_rect.height);
   cairo_destroy (cr);
 
@@ -448,7 +576,41 @@ gsk_vulkan_renderer_ref_glyph_image (GskVulkanRenderer  *self,
                                           cairo_image_surface_get_stride (surface));
   cairo_surface_destroy (surface);
 
-  g_free (glyph_rects); // FIXME: keep this around per-image
+  cache_item (self, font, glyphs, coords, num_coords);
 
   return image;
 }
+
+void
+gsk_vulkan_renderer_get_glyph_coords (GskVulkanRenderer *self,
+                                      PangoFont         *font,
+                                      PangoGlyphString  *glyphs,
+                                      PangoGlyph         glyph,
+                                      float             *x,
+                                      float             *y,
+                                      float             *width,
+                                      float             *height)
+{
+  GlyphCoords *coords;
+  int num_coords;
+  int i;
+
+  *x = 0.0;
+  *y = 0.0;
+  *width = 1.0;
+  *height = 1.0;
+
+  num_coords = find_cached_item (self, font, glyphs, &coords);
+  for (i = 0; i < num_coords; i++)
+    {
+      if (coords[i].glyph == glyph)
+        {
+          *x = coords[i].x;
+          *y = coords[i].x;
+          *width = coords[i].width;
+          *height = coords[i].height;
+//g_print ("using %g %g %g %g\n", coords[i].x, coords[i].y, coords[i].width, coords[i].height);
+          break;
+        }
+    }
+}
diff --git a/gsk/gskvulkanrendererprivate.h b/gsk/gskvulkanrendererprivate.h
index 06fb1fb..679d8a0 100644
--- a/gsk/gskvulkanrendererprivate.h
+++ b/gsk/gskvulkanrendererprivate.h
@@ -33,6 +33,14 @@ GskVulkanImage *        gsk_vulkan_renderer_ref_glyph_image             (GskVulk
                                                                          GskVulkanUploader      *uploader,
                                                                          PangoFont              *font,
                                                                          PangoGlyphString       *glyphs);
+void                    gsk_vulkan_renderer_get_glyph_coords            (GskVulkanRenderer      *self,
+                                                                         PangoFont              *font,
+                                                                         PangoGlyphString       *glyphs,
+                                                                         PangoGlyph              glyph,
+                                                                         float                  *x,
+                                                                         float                  *y,
+                                                                         float                  *width,
+                                                                         float                  *height);
 
 G_END_DECLS
 
diff --git a/gsk/gskvulkanrenderpass.c b/gsk/gskvulkanrenderpass.c
index 364e6c8..ab8b668 100644
--- a/gsk/gskvulkanrenderpass.c
+++ b/gsk/gskvulkanrenderpass.c
@@ -19,6 +19,7 @@
 #include "gskvulkanimageprivate.h"
 #include "gskvulkanpushconstantsprivate.h"
 #include "gskvulkanrendererprivate.h"
+#include "gskprivate.h"
 
 #include <cairo-ft.h>
 
@@ -685,7 +686,8 @@ gsk_vulkan_render_pass_count_vertex_data (GskVulkanRenderPass *self)
           break;
 
         case GSK_VULKAN_OP_TEXT:
-          op->render.vertex_count = gsk_vulkan_text_pipeline_count_vertex_data (GSK_VULKAN_TEXT_PIPELINE 
(op->render.pipeline));
+          op->render.vertex_count = gsk_vulkan_text_pipeline_count_vertex_data (GSK_VULKAN_TEXT_PIPELINE 
(op->render.pipeline),
+                                                                                
pango_glyph_string_num_glyphs (gsk_text_node_get_glyphs (op->render.node)));
           n_bytes += op->render.vertex_count;
           break;
 
@@ -738,6 +740,7 @@ gsk_vulkan_render_pass_count_vertex_data (GskVulkanRenderPass *self)
 
 gsize
 gsk_vulkan_render_pass_collect_vertex_data (GskVulkanRenderPass *self,
+                                            GskVulkanRender     *render,
                                             guchar              *data,
                                             gsize                offset,
                                             gsize                total)
@@ -772,8 +775,13 @@ gsk_vulkan_render_pass_collect_vertex_data (GskVulkanRenderPass *self,
             op->render.vertex_offset = offset + n_bytes;
             gsk_vulkan_text_pipeline_collect_vertex_data (GSK_VULKAN_TEXT_PIPELINE (op->render.pipeline),
                                                           data + n_bytes + offset,
+                                                          GSK_VULKAN_RENDERER 
(gsk_vulkan_render_get_renderer (render)),
                                                           &op->render.node->bounds,
-                                                          gsk_text_node_get_color (op->render.node));
+                                                          gsk_text_node_get_font (op->render.node),
+                                                          gsk_text_node_get_glyphs (op->render.node),
+                                                          gsk_text_node_get_color (op->render.node),
+                                                          gsk_text_node_get_x (op->render.node),
+                                                          gsk_text_node_get_y (op->render.node));
             n_bytes += op->render.vertex_count;
           }
           break;
@@ -1038,7 +1046,7 @@ gsk_vulkan_render_pass_draw (GskVulkanRenderPass     *self,
 
           current_draw_index += gsk_vulkan_text_pipeline_draw (GSK_VULKAN_TEXT_PIPELINE (current_pipeline),
                                                                 command_buffer,
-                                                                current_draw_index, 1);
+                                                                current_draw_index, 
pango_glyph_string_num_glyphs (gsk_text_node_get_glyphs (op->render.node)));
           break;
 
         case GSK_VULKAN_OP_COLOR_TEXT:
diff --git a/gsk/gskvulkanrenderpassprivate.h b/gsk/gskvulkanrenderpassprivate.h
index c7afdb5..48a2461 100644
--- a/gsk/gskvulkanrenderpassprivate.h
+++ b/gsk/gskvulkanrenderpassprivate.h
@@ -26,6 +26,7 @@ void                    gsk_vulkan_render_pass_upload                   (GskVulk
 
 gsize                   gsk_vulkan_render_pass_count_vertex_data        (GskVulkanRenderPass    *self);
 gsize                   gsk_vulkan_render_pass_collect_vertex_data      (GskVulkanRenderPass    *self,
+                                                                         GskVulkanRender        *render,
                                                                          guchar                 *data,
                                                                          gsize                   offset,
                                                                          gsize                   total);
diff --git a/gsk/gskvulkantextpipeline.c b/gsk/gskvulkantextpipeline.c
index 7f504ee..fc2b47a 100644
--- a/gsk/gskvulkantextpipeline.c
+++ b/gsk/gskvulkantextpipeline.c
@@ -92,38 +92,74 @@ gsk_vulkan_text_pipeline_new (GskVulkanPipelineLayout *layout,
 }
 
 gsize
-gsk_vulkan_text_pipeline_count_vertex_data (GskVulkanTextPipeline *pipeline)
+gsk_vulkan_text_pipeline_count_vertex_data (GskVulkanTextPipeline *pipeline,
+                                            int                    num_instances)
 {
-  return sizeof (GskVulkanTextInstance);
+  return sizeof (GskVulkanTextInstance) * num_instances;
 }
 
 void
-gsk_vulkan_text_pipeline_collect_vertex_data (GskVulkanTextPipeline *pipeline,
-                                               guchar                 *data,
-                                               const graphene_rect_t  *rect,
-                                               const GdkRGBA          *color)
+gsk_vulkan_text_pipeline_collect_vertex_data (GskVulkanTextPipeline  *pipeline,
+                                              guchar                 *data,
+                                              GskVulkanRenderer      *renderer,
+                                              const graphene_rect_t  *rect,
+                                              PangoFont              *font,
+                                              PangoGlyphString       *glyphs,
+                                              const GdkRGBA          *color,
+                                              float                   x,
+                                              float                   y)
 {
-  GskVulkanTextInstance *instance = (GskVulkanTextInstance *) data;
-
-  instance->rect[0] = rect->origin.x;
-  instance->rect[1] = rect->origin.y;
-  instance->rect[2] = rect->size.width;
-  instance->rect[3] = rect->size.height;
-  instance->tex_rect[0] = 0.0;
-  instance->tex_rect[1] = 0.0;
-  instance->tex_rect[2] = 1.0;
-  instance->tex_rect[3] = 1.0;
-  instance->color[0] = color->red;
-  instance->color[1] = color->green;
-  instance->color[2] = color->blue;
-  instance->color[3] = color->alpha;
+  GskVulkanTextInstance *instances = (GskVulkanTextInstance *) data;
+  int i, count;
+  int x_position = 0;
+  float ink_rect_y;
+  float ink_rect_height;
+
+  /* XXX */
+  ink_rect_y = rect->origin.y - y;
+  ink_rect_height = rect->size.height;
+
+  count = 0;
+  for (i = 0; i < glyphs->num_glyphs; i++)
+    {
+      PangoGlyphInfo *gi = &glyphs->glyphs[i];
+
+      if (gi->glyph != PANGO_GLYPH_EMPTY)
+        {
+          double cx = (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
+          double cy = (double)(gi->geometry.y_offset) / PANGO_SCALE;
+
+          if (!(gi->glyph & PANGO_GLYPH_UNKNOWN_FLAG))
+            {
+              GskVulkanTextInstance *instance = &instances[count];
+
+              instance->rect[0] = x + cx;
+              instance->rect[1] = y + ink_rect_y + cy;
+              instance->rect[2] = (float)gi->geometry.width / PANGO_SCALE;
+              instance->rect[3] = ink_rect_height;
+              gsk_vulkan_renderer_get_glyph_coords (renderer, font, glyphs,
+                                                    gi->glyph,
+                                                    &instance->tex_rect[0],
+                                                    &instance->tex_rect[1],
+                                                    &instance->tex_rect[2],
+                                                    &instance->tex_rect[3]);
+              instance->color[0] = color->red;
+              instance->color[1] = color->green;
+              instance->color[2] = color->blue;
+              instance->color[3] = color->alpha;
+
+              count++;
+            }
+        }
+      x_position += gi->geometry.width;
+    }
 }
 
 gsize
 gsk_vulkan_text_pipeline_draw (GskVulkanTextPipeline *pipeline,
-                                VkCommandBuffer         command_buffer,
-                                gsize                   offset,
-                                gsize                   n_commands)
+                               VkCommandBuffer        command_buffer,
+                               gsize                  offset,
+                               gsize                  n_commands)
 {
   vkCmdDraw (command_buffer,
              6, n_commands,
diff --git a/gsk/gskvulkantextpipelineprivate.h b/gsk/gskvulkantextpipelineprivate.h
index 6ebdcac..a41846d 100644
--- a/gsk/gskvulkantextpipelineprivate.h
+++ b/gsk/gskvulkantextpipelineprivate.h
@@ -4,6 +4,7 @@
 #include <graphene.h>
 
 #include "gskvulkanpipelineprivate.h"
+#include "gskvulkanrendererprivate.h"
 
 G_BEGIN_DECLS
 
@@ -17,11 +18,17 @@ GskVulkanPipeline *     gsk_vulkan_text_pipeline_new                   (GskVulka
                                                                         const char                     
*shader_name,
                                                                         VkRenderPass                    
render_pass);
 
-gsize                   gsk_vulkan_text_pipeline_count_vertex_data     (GskVulkanTextPipeline         
*pipeline);
+gsize                   gsk_vulkan_text_pipeline_count_vertex_data     (GskVulkanTextPipeline         
*pipeline,
+                                                                        int                            
num_instances);
 void                    gsk_vulkan_text_pipeline_collect_vertex_data   (GskVulkanTextPipeline         
*pipeline,
                                                                         guchar                         *data,
+                                                                        GskVulkanRenderer              
*renderer,
                                                                         const graphene_rect_t          *rect,
-                                                                        const GdkRGBA                  
*color);
+                                                                        PangoFont                      *font,
+                                                                        PangoGlyphString               
*glyphs,
+                                                                        const GdkRGBA                  
*color,
+                                                                        float                           x,
+                                                                        float                           y);
 gsize                   gsk_vulkan_text_pipeline_draw                  (GskVulkanTextPipeline         
*pipeline,
                                                                         VkCommandBuffer                 
command_buffer,
                                                                         gsize                           
offset,


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