[gtk+/wip/matthiasc/text-node] wip: work towards per-glyph instances
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/matthiasc/text-node] wip: work towards per-glyph instances
- Date: Sun, 10 Sep 2017 17:28:25 +0000 (UTC)
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 (®ister_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]