[gtk+/wip/matthiasc/text-node] More text node work
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/matthiasc/text-node] More text node work
- Date: Sat, 9 Sep 2017 16:44:29 +0000 (UTC)
commit ae574b168acf36b5a3cd3a1ccd75fb196608c0dc
Author: Matthias Clasen <mclasen redhat com>
Date: Sat Sep 9 11:40:15 2017 -0400
More text node work
Use the surface as a plain texture. This currently doesn't do
the right thing for masking, and loses text color. Keep a simple
cache of the surfaces.
gsk/gskrendernodeimpl.c | 143 ++++++++++++++++++++++++++++++++++++++++++--
gsk/gskrendernodeprivate.h | 2 +
gsk/gskvulkanrenderpass.c | 27 ++++++++-
3 files changed, 165 insertions(+), 7 deletions(-)
---
diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c
index 4b91076..2474468 100644
--- a/gsk/gskrendernodeimpl.c
+++ b/gsk/gskrendernodeimpl.c
@@ -3889,6 +3889,13 @@ render_text (cairo_t *cr,
g_free (cairo_glyphs);
}
+/*
+ * Next steps:
+ * - figure out A8 textures and masking
+ * - make the shader use per-glyph rects from a larger texture
+ * - switch to using a font atlas insead of per-call cached surfaces
+ */
+
static void
gsk_text_node_draw (GskRenderNode *node,
cairo_t *cr)
@@ -3981,6 +3988,116 @@ font_has_color_glyphs (PangoFont *font)
return has_color;
}
+typedef struct {
+ PangoFont *font;
+ PangoGlyphString *glyphs;
+ guint hash;
+ cairo_surface_t *surface;
+} 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);
+ if (item->surface)
+ cairo_surface_destroy (item->surface);
+
+ g_free (item);
+}
+
+static GHashTable *cache;
+
+static cairo_surface_t *
+find_cached_surface (PangoFont *font, PangoGlyphString *glyphs)
+{
+ CacheItem key;
+ CacheItem *value;
+
+ key.font = font;
+ key.glyphs = glyphs;
+ key.hash = 0;
+ key.surface = NULL;
+
+ if (!cache)
+ cache = g_hash_table_new_full (item_hash, item_equal, NULL, item_free);
+
+ value = g_hash_table_lookup (cache, &key);
+ if (value)
+ return cairo_surface_reference (value->surface);
+
+ return NULL;
+}
+
+static void
+cache_surface (PangoFont *font, PangoGlyphString *glyphs, cairo_surface_t *surface)
+{
+ CacheItem *item;
+
+ item = g_new (CacheItem, 1);
+
+ item->font = g_object_ref (font);
+ item->glyphs = pango_glyph_string_copy (glyphs);
+ item->hash = 0;
+ item->surface = cairo_surface_reference (surface);
+
+ g_hash_table_insert (cache, item, item);
+}
+
GskRenderNode *
gsk_text_node_new (PangoFont *font,
PangoGlyphString *glyphs,
@@ -4016,16 +4133,30 @@ gsk_text_node_new (PangoFont *font,
ink_rect.x + ink_rect.width,
ink_rect.height);
- self->surface = cairo_image_surface_create (self->has_color ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_A8,
- 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);
+ self->surface = find_cached_surface (font, glyphs);
+ if (!self->surface)
+ {
+ self->surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, //self->has_color ?
CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_A8,
+ 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);
+
+ cache_surface (font, glyphs, self->surface);
+ }
return &self->render_node;
}
+cairo_surface_t *
+gsk_text_node_get_surface (GskRenderNode *node)
+{
+ GskTextNode *self = (GskTextNode *) node;
+
+ return self->surface;
+}
+
/*** GSK_BLUR_NODE ***/
typedef struct _GskBlurNode GskBlurNode;
diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h
index be29f87..a0b0429 100644
--- a/gsk/gskrendernodeprivate.h
+++ b/gsk/gskrendernodeprivate.h
@@ -81,6 +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);
+
const GdkRGBA *gsk_color_node_peek_color (GskRenderNode *node);
const graphene_rect_t * gsk_clip_node_peek_clip (GskRenderNode *node);
diff --git a/gsk/gskvulkanrenderpass.c b/gsk/gskvulkanrenderpass.c
index f3b2b0c..1308c3a 100644
--- a/gsk/gskvulkanrenderpass.c
+++ b/gsk/gskvulkanrenderpass.c
@@ -172,6 +172,22 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
g_array_append_val (self->render_ops, op);
return;
+ case GSK_TEXT_NODE:
+ if (gsk_text_node_get_surface (node) == NULL)
+ return;
+ if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+ pipeline_type = GSK_VULKAN_PIPELINE_BLEND;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+ pipeline_type = GSK_VULKAN_PIPELINE_BLEND_CLIP;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+ pipeline_type = GSK_VULKAN_PIPELINE_BLEND_CLIP_ROUNDED;
+ else
+ FALLBACK ("Cairo nodes can't deal with clip type %u\n", constants->clip.type);
+ op.type = GSK_VULKAN_OP_SURFACE;
+ op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+ g_array_append_val (self->render_ops, op);
+ return;
+
case GSK_TEXTURE_NODE:
if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
pipeline_type = GSK_VULKAN_PIPELINE_BLEND;
@@ -413,6 +429,10 @@ 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;
}
@@ -528,7 +548,12 @@ gsk_vulkan_render_pass_upload (GskVulkanRenderPass *self,
case GSK_VULKAN_OP_SURFACE:
{
- cairo_surface_t *surface = gsk_cairo_node_get_surface (op->render.node);
+ 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);
op->render.source = gsk_vulkan_image_new_from_data (uploader,
cairo_image_surface_get_data (surface),
cairo_image_surface_get_width (surface),
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]