[gtk+/wip/matthiasc/text-node] Use vulkan images for text



commit 8b70b91a7607e50abec0217b33a913276c61a148
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Sep 10 09:57:42 2017 -0400

    Use vulkan images for text
    
    We are still using a single texture for each
    glyph string.
    
    Along the way, we drop the surface from the text node
    and return gsk_text_node_draw to the way it was initially,
    directly drawing on the provided cairo_t.

 gsk/gskrendernodeimpl.c        |  122 +++++++++++++---------------------------
 gsk/gskrendernodeprivate.h     |    3 +-
 gsk/gskvulkanrenderer.c        |   12 +++-
 gsk/gskvulkanrendererprivate.h |    4 +-
 gsk/gskvulkanrenderpass.c      |   24 ++++----
 5 files changed, 62 insertions(+), 103 deletions(-)
---
diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c
index fecc133..5ea2a13 100644
--- a/gsk/gskrendernodeimpl.c
+++ b/gsk/gskrendernodeimpl.c
@@ -3811,8 +3811,8 @@ struct _GskTextNode
 {
   GskRenderNode render_node;
 
+  PangoFont *font;
   PangoGlyphString *glyphs;
-  cairo_surface_t *surface;
 
   GdkRGBA color;
   gboolean has_color;
@@ -3827,8 +3827,8 @@ gsk_text_node_finalize (GskRenderNode *node)
 {
   GskTextNode *self = (GskTextNode *) node;
 
+  g_object_unref (self->font);
   pango_glyph_string_free (self->glyphs);
-  cairo_surface_destroy (self->surface);
 }
 
 #ifndef STACK_BUFFER_SIZE
@@ -3838,39 +3838,40 @@ gsk_text_node_finalize (GskRenderNode *node)
 #define STACK_ARRAY_LENGTH(T) (STACK_BUFFER_SIZE / sizeof(T))
 
 static void
-render_text (cairo_t          *cr,
-             PangoGlyphString *glyphs,
-             PangoFont        *font,
-             double            x,
-             double            y)
+gsk_text_node_draw (GskRenderNode *node,
+                    cairo_t       *cr)
 {
+  GskTextNode *self = (GskTextNode *) node;
   int i, count;
   int x_position = 0;
   cairo_scaled_font_t *scaled_font;
   cairo_glyph_t *cairo_glyphs;
   cairo_glyph_t stack_glyphs[STACK_ARRAY_LENGTH (cairo_glyph_t)];
 
-  scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *)font);
+  scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *)self->font);
   if (G_UNLIKELY (!scaled_font || cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS))
     return;
 
+  cairo_save (cr);
+
+  cairo_translate (cr, self->x, self->y);
   cairo_set_scaled_font (cr, scaled_font);
-  cairo_set_source_rgba (cr, 0, 0, 0, 1);
+  gdk_cairo_set_source_rgba (cr, &self->color);
 
-  if (glyphs->num_glyphs > (int) G_N_ELEMENTS (stack_glyphs))
-    cairo_glyphs = g_new (cairo_glyph_t, glyphs->num_glyphs);
+  if (self->glyphs->num_glyphs > (int) G_N_ELEMENTS (stack_glyphs))
+    cairo_glyphs = g_new (cairo_glyph_t, self->glyphs->num_glyphs);
   else
     cairo_glyphs = stack_glyphs;
 
   count = 0;
-  for (i = 0; i < glyphs->num_glyphs; i++)
+  for (i = 0; i < self->glyphs->num_glyphs; i++)
     {
-      PangoGlyphInfo *gi = &glyphs->glyphs[i];
+      PangoGlyphInfo *gi = &self->glyphs->glyphs[i];
 
       if (gi->glyph != PANGO_GLYPH_EMPTY)
         {
-          double cx = x + (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
-          double cy = y + (double)(gi->geometry.y_offset) / PANGO_SCALE;
+          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))
             {
@@ -3887,6 +3888,8 @@ render_text (cairo_t          *cr,
 
   if (cairo_glyphs != stack_glyphs)
     g_free (cairo_glyphs);
+
+  cairo_restore (cr);
 }
 
 /*
@@ -3897,56 +3900,6 @@ render_text (cairo_t          *cr,
  * - switch to using a font atlas instead of per-call cached surfaces
  */
 
-static void
-gsk_text_node_draw (GskRenderNode *node,
-                    cairo_t       *cr)
-{
-  GskTextNode *self = (GskTextNode *) node;
-  int i;
-  int x_position = 0;
-
-  cairo_save (cr);
-
-  cairo_translate (cr, self->x, self->y);
-
-  gdk_cairo_set_source_rgba (cr, &self->color);
-
-  for (i = 0; i < self->glyphs->num_glyphs; i++)
-    {
-      PangoGlyphInfo *gi = &self->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))
-            {
-              cairo_rectangle (cr, cx,
-                                   cy + self->ink_rect_y,
-                                   gi->geometry.width / PANGO_SCALE,
-                                   self->ink_rect_height);
-              cairo_clip (cr);
-
-              cairo_move_to (cr, cx, cy + self->ink_rect_y);
-              if (self->has_color)
-                {
-                  cairo_set_source_surface (cr, self->surface, 0, self->ink_rect_y);
-                  cairo_paint (cr);
-                }
-              else
-                {
-                  cairo_mask_surface (cr, self->surface, 0, self->ink_rect_y);
-                }
-              cairo_reset_clip (cr);
-            }
-        }
-      x_position += gi->geometry.width;
-    }
-
-  cairo_restore (cr);
-}
-
 static GVariant *
 gsk_text_node_serialize (GskRenderNode *node)
 {
@@ -3998,7 +3951,6 @@ gsk_text_node_new (PangoFont        *font,
 {
   GskTextNode *self;
   PangoRectangle ink_rect;
-  cairo_t *cr;
 
   pango_glyph_string_extents (glyphs, font, &ink_rect, NULL);
   pango_extents_to_pixels (&ink_rect, NULL);
@@ -4009,6 +3961,7 @@ gsk_text_node_new (PangoFont        *font,
 
   self = (GskTextNode *) gsk_render_node_new (&GSK_TEXT_NODE_CLASS, 0);
 
+  self->font = g_object_ref (font);
   self->glyphs = pango_glyph_string_copy (glyphs);
   self->color = *color;
   self->x = x;
@@ -4023,26 +3976,9 @@ gsk_text_node_new (PangoFont        *font,
                       ink_rect.x + ink_rect.width,
                       ink_rect.height);
 
-  self->surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
-                                              ink_rect.x + ink_rect.width,
-                                              ink_rect.height);
-  cr = cairo_create (self->surface);
-  render_text (cr, glyphs, font, 0, - ink_rect.y);
-  cairo_destroy (cr);
-
   return &self->render_node;
 }
 
-cairo_surface_t *
-gsk_text_node_get_surface (GskRenderNode *node)
-{
-  GskTextNode *self = (GskTextNode *) node;
-
-  g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_TEXT_NODE), NULL);
-
-  return self->surface;
-}
-
 gboolean
 gsk_text_node_get_has_color (GskRenderNode *node)
 {
@@ -4063,6 +3999,26 @@ gsk_text_node_get_color (GskRenderNode *node)
   return &self->color;
 }
 
+PangoFont *
+gsk_text_node_get_font (GskRenderNode *node)
+{
+  GskTextNode *self = (GskTextNode *) node;
+
+  g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_TEXT_NODE), NULL);
+
+  return self->font;
+}
+
+PangoGlyphString *
+gsk_text_node_get_glyphs (GskRenderNode *node)
+{
+  GskTextNode *self = (GskTextNode *) node;
+
+  g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_TEXT_NODE), NULL);
+
+  return self->glyphs;
+}
+
 /*** GSK_BLUR_NODE ***/
 
 typedef struct _GskBlurNode GskBlurNode;
diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h
index f2fd507..008bdea 100644
--- a/gsk/gskrendernodeprivate.h
+++ b/gsk/gskrendernodeprivate.h
@@ -81,7 +81,8 @@ cairo_surface_t *gsk_cairo_node_get_surface (GskRenderNode *node);
 
 GskTexture *gsk_texture_node_get_texture (GskRenderNode *node);
 
-cairo_surface_t *gsk_text_node_get_surface (GskRenderNode *node);
+PangoFont *gsk_text_node_get_font (GskRenderNode *node);
+PangoGlyphString *gsk_text_node_get_glyphs (GskRenderNode *node);
 gboolean gsk_text_node_get_has_color (GskRenderNode *node);
 const GdkRGBA *gsk_text_node_get_color (GskRenderNode *node);
 
diff --git a/gsk/gskvulkanrenderer.c b/gsk/gskvulkanrenderer.c
index f70935f..57262e6 100644
--- a/gsk/gskvulkanrenderer.c
+++ b/gsk/gskvulkanrenderer.c
@@ -418,14 +418,16 @@ GskVulkanImage *
 gsk_vulkan_renderer_ref_glyph_image (GskVulkanRenderer  *self,
                                      GskVulkanUploader  *uploader,
                                      PangoFont          *font,
-                                     PangoGlyphString   *glyphs,
-                                     GskRectangle       *glyph_rects,
-                                     int                *num_glyphs)
+                                     PangoGlyphString   *glyphs)
 {
   PangoRectangle ink_rect;
   cairo_surface_t *surface;
   cairo_t *cr;
   GskVulkanImage *image;
+  GskRectangle *glyph_rects;
+  int num_glyphs;
+
+  glyph_rects = g_new (GskRectangle, glyphs->num_glyphs);
 
   pango_glyph_string_extents (glyphs, font, &ink_rect, NULL);
   pango_extents_to_pixels (&ink_rect, NULL);
@@ -435,7 +437,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, glyph_rects, &num_glyphs,
                0, - ink_rect.y, ink_rect.x + ink_rect.width, ink_rect.height);
   cairo_destroy (cr);
 
@@ -446,5 +448,7 @@ 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
+
   return image;
 }
diff --git a/gsk/gskvulkanrendererprivate.h b/gsk/gskvulkanrendererprivate.h
index 6d06bc1..06fb1fb 100644
--- a/gsk/gskvulkanrendererprivate.h
+++ b/gsk/gskvulkanrendererprivate.h
@@ -32,9 +32,7 @@ typedef struct {
 GskVulkanImage *        gsk_vulkan_renderer_ref_glyph_image             (GskVulkanRenderer      *self,
                                                                          GskVulkanUploader      *uploader,
                                                                          PangoFont              *font,
-                                                                         PangoGlyphString       *glyphs,
-                                                                         GskRectangle           *glyph_rects,
-                                                                         int                    *num_glyphs);
+                                                                         PangoGlyphString       *glyphs);
 
 G_END_DECLS
 
diff --git a/gsk/gskvulkanrenderpass.c b/gsk/gskvulkanrenderpass.c
index cb56fce..70e1f06 100644
--- a/gsk/gskvulkanrenderpass.c
+++ b/gsk/gskvulkanrenderpass.c
@@ -177,8 +177,6 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass           *self,
       return;
 
     case GSK_TEXT_NODE:
-      if (gsk_text_node_get_surface (node) == NULL)
-        return;
       if (gsk_text_node_get_has_color (node))
         {
           if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
@@ -448,10 +446,6 @@ gsk_vulkan_render_pass_get_node_as_texture (GskVulkanRenderPass   *self,
           surface = cairo_surface_reference (gsk_cairo_node_get_surface (node));
           goto got_surface;
 
-        case GSK_TEXT_NODE:
-          surface = cairo_surface_reference (gsk_text_node_get_surface (node));
-          goto got_surface;
-
         default:
           break;
         }
@@ -566,15 +560,10 @@ gsk_vulkan_render_pass_upload (GskVulkanRenderPass  *self,
           break;
 
         case GSK_VULKAN_OP_SURFACE:
-        case GSK_VULKAN_OP_TEXT:
-        case GSK_VULKAN_OP_COLOR_TEXT:
           {
             cairo_surface_t *surface;
 
-            if (gsk_render_node_get_node_type (op->render.node) == GSK_CAIRO_NODE)
-              surface = gsk_cairo_node_get_surface (op->render.node);
-            else
-              surface = gsk_text_node_get_surface (op->render.node);
+            surface = gsk_cairo_node_get_surface (op->render.node);
             op->render.source = gsk_vulkan_image_new_from_data (uploader,
                                                                 cairo_image_surface_get_data (surface),
                                                                 cairo_image_surface_get_width (surface),
@@ -584,6 +573,17 @@ gsk_vulkan_render_pass_upload (GskVulkanRenderPass  *self,
           }
           break;
 
+        case GSK_VULKAN_OP_TEXT:
+        case GSK_VULKAN_OP_COLOR_TEXT:
+          {
+            op->render.source = gsk_vulkan_renderer_ref_glyph_image (GSK_VULKAN_RENDERER 
(gsk_vulkan_render_get_renderer (render)),
+                                                                     uploader,
+                                                                     gsk_text_node_get_font 
(op->render.node),
+                                                                     gsk_text_node_get_glyphs 
(op->render.node));
+            gsk_vulkan_render_add_cleanup_image (render, op->render.source);
+          }
+          break;
+
         case GSK_VULKAN_OP_TEXTURE:
           {
             op->render.source = gsk_vulkan_renderer_ref_texture_image (GSK_VULKAN_RENDERER 
(gsk_vulkan_render_get_renderer (render)),


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