[gtk/glyphy2: 42/47] gsk/gl: start on basic glyphy renderjob integration
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/glyphy2: 42/47] gsk/gl: start on basic glyphy renderjob integration
- Date: Sun, 3 Apr 2022 01:02:26 +0000 (UTC)
commit 7854c4e31c22eaa1b092ffd7d5f173a9be4adccf
Author: Christian Hergert <chergert redhat com>
Date: Thu Mar 17 16:54:46 2022 -0700
gsk/gl: start on basic glyphy renderjob integration
This doesn't work correctly yet, as there are lots of bumps along the way
to still smooth out.
gsk/gl/gskglprograms.defs | 19 ++++
gsk/gl/gskglrenderjob.c | 186 ++++++++++++++++++++++++++++++++++++-
gsk/gl/resources/glyphy.atlas.glsl | 15 +++
gsk/gl/resources/glyphy.fs.glsl | 88 ++++++++++++++++++
gsk/gl/resources/glyphy.vs.glsl | 24 +++++
gsk/meson.build | 3 +
6 files changed, 332 insertions(+), 3 deletions(-)
---
diff --git a/gsk/gl/gskglprograms.defs b/gsk/gl/gskglprograms.defs
index 1ff99fab89..a0a1cc26d9 100644
--- a/gsk/gl/gskglprograms.defs
+++ b/gsk/gl/gskglprograms.defs
@@ -82,3 +82,22 @@ GSK_GL_DEFINE_PROGRAM (unblurred_outset_shadow,
GSK_GL_ADD_UNIFORM (1, UNBLURRED_OUTSET_SHADOW_SPREAD, u_spread)
GSK_GL_ADD_UNIFORM (2, UNBLURRED_OUTSET_SHADOW_OFFSET, u_offset)
GSK_GL_ADD_UNIFORM (3, UNBLURRED_OUTSET_SHADOW_OUTLINE_RECT, u_outline_rect))
+
+GSK_GL_DEFINE_PROGRAM (glyphy,
+ GSK_GL_SHADER_JOINED (VERTEX,
+ GSK_GL_SHADER_RESOURCE ("glyphy.vs.glsl"),
+ NULL)
+ GSK_GL_SHADER_JOINED (FRAGMENT,
+ GSK_GL_SHADER_RESOURCE ("glyphy.atlas.glsl"),
+ GSK_GL_SHADER_STRING (glyphy_common_shader_source ()),
+ GSK_GL_SHADER_STRING ("#define GLYPHY_SDF_PSEUDO_DISTANCE 1\n"),
+ GSK_GL_SHADER_STRING (glyphy_sdf_shader_source ()),
+ GSK_GL_SHADER_RESOURCE ("glyphy.fs.glsl"),
+ NULL),
+ GSK_GL_ADD_UNIFORM (0, GLYPHY_CONTRAST, u_contrast)
+ GSK_GL_ADD_UNIFORM (1, GLYPHY_GAMMA_ADJUST, u_gamma_adjust)
+ GSK_GL_ADD_UNIFORM (2, GLYPHY_OUTLINE_THICKNESS, u_outline_thickness)
+ GSK_GL_ADD_UNIFORM (3, GLYPHY_OUTLINE, u_outline)
+ GSK_GL_ADD_UNIFORM (4, GLYPHY_BOLDNESS, u_boldness)
+ GSK_GL_ADD_UNIFORM (5, GLYPHY_DEBUG, u_debug)
+ GSK_GL_ADD_UNIFORM (6, GLYPHY_ATLAS_INFO, u_atlas_info))
diff --git a/gsk/gl/gskglrenderjob.c b/gsk/gl/gskglrenderjob.c
index 41d662d9ea..7cdfd815db 100644
--- a/gsk/gl/gskglrenderjob.c
+++ b/gsk/gl/gskglrenderjob.c
@@ -3068,12 +3068,192 @@ gsk_gl_render_job_visit_text_node_legacy (GskGLRenderJob *job,
gsk_gl_render_job_end_draw (job);
}
+typedef struct
+{
+ float x;
+ float y;
+ float g16hi;
+ float g16lo;
+} EncodedGlyph;
+
+static unsigned int
+glyph_encode (guint atlas_x , /* 7 bits */
+ guint atlas_y, /* 7 bits */
+ guint corner_x, /* 1 bit */
+ guint corner_y, /* 1 bit */
+ guint nominal_w, /* 6 bits */
+ guint nominal_h) /* 6 bits */
+{
+ guint x, y;
+
+ g_assert (0 == (atlas_x & ~0x7F));
+ g_assert (0 == (atlas_y & ~0x7F));
+ g_assert (0 == (corner_x & ~1));
+ g_assert (0 == (corner_y & ~1));
+ g_assert (0 == (nominal_w & ~0x3F));
+ g_assert (0 == (nominal_h & ~0x3F));
+
+ x = (((atlas_x << 6) | nominal_w) << 1) | corner_x;
+ y = (((atlas_y << 6) | nominal_h) << 1) | corner_y;
+
+ return (x << 16) | y;
+}
+
+static void
+encoded_glyph_init (EncodedGlyph *eg,
+ float x,
+ float y,
+ guint corner_x,
+ guint corner_y,
+ const GskGLGlyphyValue *gi)
+{
+ guint encoded = glyph_encode (gi->atlas_x, gi->atlas_y, corner_x, corner_y, gi->nominal_w, gi->nominal_h);
+
+ eg->x = x;
+ eg->y = y;
+ eg->g16hi = encoded >> 16;
+ eg->g16lo = encoded & 0xFFFF;
+}
+
+static inline void
+add_encoded_glyph (GskGLDrawVertex *vertices,
+ const EncodedGlyph *eg,
+ const guint16 c[4])
+{
+ *vertices = (GskGLDrawVertex) { .position = { eg->x, eg->y}, .uv = { eg->g16hi, eg->g16lo}, .color = {
c[0], c[1], c[2], c[3] } };
+}
+
static inline void
gsk_gl_render_job_visit_text_node_glyphy (GskGLRenderJob *job,
const GskRenderNode *node,
- const GdkRGBA *color,
- gboolean force_color)
+ const GdkRGBA *color)
{
+ const graphene_point_t *offset;
+ const PangoGlyphInfo *glyphs;
+ const PangoGlyphInfo *gi;
+ GskGLGlyphyLibrary *library;
+ GskGLCommandBatch *batch;
+ const PangoFont *font;
+ GskGLDrawVertex *vertices;
+ const guint16 *c;
+ GskGLGlyphyKey lookup;
+ guint16 cc[4];
+ float x;
+ float y;
+ guint last_texture = 0;
+ guint num_glyphs;
+ guint used = 0;
+ guint i;
+ int x_position = 0;
+
+ g_assert (!gsk_text_node_has_color_glyphs (node));
+
+ if (!(num_glyphs = gsk_text_node_get_num_glyphs (node)))
+ return;
+
+ if (RGBA_IS_CLEAR (color))
+ return;
+
+ font = gsk_text_node_get_font (node);
+ glyphs = gsk_text_node_get_glyphs (node, NULL);
+ library = job->driver->glyphy_library;
+ offset = gsk_text_node_get_offset (node);
+ x = offset->x + job->offset_x;
+ y = offset->y + job->offset_y;
+
+ rgba_to_half (color, cc);
+ c = cc;
+
+ gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, glyphy));
+
+ batch = gsk_gl_command_queue_get_batch (job->command_queue);
+ vertices = gsk_gl_command_queue_add_n_vertices (job->command_queue, num_glyphs);
+
+ lookup.font = (PangoFont *)font;
+
+ for (i = 0, gi = glyphs; i < num_glyphs; i++, gi++)
+ {
+ const GskGLGlyphyValue *glyph;
+ float cx = 0, cy = 0;
+ guint texture_id;
+
+ lookup.glyph = gi->glyph;
+ texture_id = gsk_gl_glyphy_library_lookup_or_add (library, &lookup, &glyph);
+ if G_UNLIKELY (texture_id == 0)
+ continue;
+
+ if G_UNLIKELY (last_texture != texture_id || batch->draw.vbo_count + GSK_GL_N_VERTICES > 0xffff)
+ {
+ if G_LIKELY (last_texture != 0)
+ {
+ guint vbo_offset = batch->draw.vbo_offset + batch->draw.vbo_count;
+
+ /* Since we have batched added our VBO vertices to avoid repeated
+ * calls to the buffer, we need to manually tweak the vbo offset
+ * of the new batch as otherwise it will point at the end of our
+ * vbo array.
+ */
+ gsk_gl_render_job_split_draw (job);
+ batch = gsk_gl_command_queue_get_batch (job->command_queue);
+ batch->draw.vbo_offset = vbo_offset;
+ }
+
+ gsk_gl_program_set_uniform4i (job->current_program,
+ UNIFORM_GLYPHY_ATLAS_INFO, 0,
+ GSK_GL_TEXTURE_LIBRARY (library)->atlas_width,
+ GSK_GL_TEXTURE_LIBRARY (library)->atlas_height,
+ library->item_w,
+ library->item_h_q);
+ gsk_gl_program_set_uniform_texture (job->current_program,
+ UNIFORM_SHARED_SOURCE, 0,
+ GL_TEXTURE_2D,
+ GL_TEXTURE0,
+ texture_id);
+ gsk_gl_program_set_uniform1f (job->current_program,
+ UNIFORM_GLYPHY_GAMMA_ADJUST, 0,
+ 1.0);
+ gsk_gl_program_set_uniform1f (job->current_program,
+ UNIFORM_GLYPHY_CONTRAST, 0,
+ 1.0);
+
+ last_texture = texture_id;
+ }
+
+ cx = (float)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
+ if G_UNLIKELY (gi->geometry.y_offset != 0)
+ cy = (float)(gi->geometry.y_offset) / PANGO_SCALE;
+
+ x_position += gi->geometry.width;
+
+ EncodedGlyph encoded[4];
+#define ENCODE_CORNER(_cx, _cy) \
+ G_STMT_START { \
+ float _vx = x + cx + ((1-_cx) * glyph->extents.min_x + _cx * glyph->extents.max_x); \
+ float _vy = y + cy - ((1-_cy) * glyph->extents.min_y + _cy * glyph->extents.max_y); \
+ encoded_glyph_init (&encoded[_cx * 2 + _cy], _vx, _vy, _cx, _cy, glyph); \
+ } G_STMT_END
+ ENCODE_CORNER (0, 0);
+ ENCODE_CORNER (0, 1);
+ ENCODE_CORNER (1, 0);
+ ENCODE_CORNER (1, 1);
+#undef ENCODE_CORNER
+
+ add_encoded_glyph (vertices++, &encoded[0], c);
+ add_encoded_glyph (vertices++, &encoded[1], c);
+ add_encoded_glyph (vertices++, &encoded[2], c);
+
+ add_encoded_glyph (vertices++, &encoded[1], c);
+ add_encoded_glyph (vertices++, &encoded[2], c);
+ add_encoded_glyph (vertices++, &encoded[3], c);
+
+ batch->draw.vbo_count += GSK_GL_N_VERTICES;
+ used++;
+ }
+
+ if (used != num_glyphs)
+ gsk_gl_command_queue_retract_n_vertices (job->command_queue, num_glyphs - used);
+
+ gsk_gl_render_job_end_draw (job);
}
static inline void
@@ -3083,7 +3263,7 @@ gsk_gl_render_job_visit_text_node (GskGLRenderJob *job,
gboolean force_color)
{
if (!gsk_text_node_has_color_glyphs (node))
- gsk_gl_render_job_visit_text_node_glyphy (job, node, color, force_color);
+ gsk_gl_render_job_visit_text_node_glyphy (job, node, color);
else
gsk_gl_render_job_visit_text_node_legacy (job, node, color, force_color);
}
diff --git a/gsk/gl/resources/glyphy.atlas.glsl b/gsk/gl/resources/glyphy.atlas.glsl
new file mode 100644
index 0000000000..af5910e46c
--- /dev/null
+++ b/gsk/gl/resources/glyphy.atlas.glsl
@@ -0,0 +1,15 @@
+uniform ivec4 u_atlas_info;
+
+#define GLYPHY_TEXTURE1D_EXTRA_DECLS , sampler2D _tex, ivec4 _atlas_info, ivec2 _atlas_pos
+#define GLYPHY_TEXTURE1D_EXTRA_ARGS , _tex, _atlas_info, _atlas_pos
+#define GLYPHY_DEMO_EXTRA_ARGS , u_source, u_atlas_info, gi.atlas_pos
+
+vec4
+glyphy_texture1D_func (int offset GLYPHY_TEXTURE1D_EXTRA_DECLS)
+{
+ ivec2 item_geom = _atlas_info.zw;
+ vec2 pos = (vec2 (_atlas_pos.xy * item_geom +
+ ivec2 (mod (float (offset), float (item_geom.x)), offset / item_geom.x)) +
+ + vec2 (.5, .5)) / vec2(_atlas_info.xy);
+ return GskTexture (_tex, pos);
+}
diff --git a/gsk/gl/resources/glyphy.fs.glsl b/gsk/gl/resources/glyphy.fs.glsl
new file mode 100644
index 0000000000..691ad77b1f
--- /dev/null
+++ b/gsk/gl/resources/glyphy.fs.glsl
@@ -0,0 +1,88 @@
+// FRAGMENT_SHADER:
+// glyphy.fs.glsl
+
+uniform float u_contrast;
+uniform float u_gamma_adjust;
+uniform float u_outline_thickness;
+uniform bool u_outline;
+uniform float u_boldness;
+uniform bool u_debug;
+
+_IN_ vec4 v_glyph;
+_IN_ vec4 final_color;
+
+#define SQRT2_2 0.70710678118654757 /* 1 / sqrt(2.) */
+#define SQRT2 1.4142135623730951
+
+struct glyph_info_t {
+ ivec2 nominal_size;
+ ivec2 atlas_pos;
+};
+
+glyph_info_t
+glyph_info_decode (vec4 v)
+{
+ glyph_info_t gi;
+ gi.nominal_size = (ivec2 (mod (v.zw, 256.)) + 2) / 4;
+ gi.atlas_pos = ivec2 (v_glyph.zw) / 256;
+ return gi;
+}
+
+
+float
+antialias (float d)
+{
+ return smoothstep (-.75, +.75, d);
+}
+
+void
+main()
+{
+ vec2 p = v_glyph.xy;
+ glyph_info_t gi = glyph_info_decode (v_glyph);
+
+ /* isotropic antialiasing */
+ vec2 dpdx = dFdx (p);
+ vec2 dpdy = dFdy (p);
+ float m = length (vec2 (length (dpdx), length (dpdy))) * SQRT2_2;
+
+ vec4 color = final_color;
+
+ float gsdist = glyphy_sdf (p, gi.nominal_size GLYPHY_DEMO_EXTRA_ARGS);
+ float sdist = gsdist / m * u_contrast;
+
+ if (!u_debug) {
+ sdist -= u_boldness * 10.;
+ if (u_outline)
+ sdist = abs (sdist) - u_outline_thickness * .5;
+ if (sdist > 1.)
+ discard;
+ float alpha = antialias (-sdist);
+ if (u_gamma_adjust != 1.)
+ alpha = pow (alpha, 1./u_gamma_adjust);
+ color = vec4 (color.rgb,color.a * alpha);
+ } else {
+ color = vec4 (0,0,0,0);
+
+ // Color the inside of the glyph a light red
+ color += vec4 (.5,0,0,.5) * smoothstep (1., -1., sdist);
+
+ float udist = abs (sdist);
+ float gudist = abs (gsdist);
+ // Color the outline red
+ color += vec4 (1,0,0,1) * smoothstep (2., 1., udist);
+ // Color the distance field in green
+ if (!glyphy_isinf (udist))
+ color += vec4(0,.4,0,.4 - (abs(gsdist) / max(float(gi.nominal_size.x), float(gi.nominal_size.y))) *
4.);
+
+ float pdist = glyphy_point_dist (p, gi.nominal_size GLYPHY_DEMO_EXTRA_ARGS);
+ // Color points green
+ color = mix (vec4 (0,1,0,.5), color, smoothstep (.05, .06, pdist));
+
+ glyphy_arc_list_t arc_list = glyphy_arc_list (p, gi.nominal_size GLYPHY_DEMO_EXTRA_ARGS);
+ // Color the number of endpoints per cell blue
+ color += vec4 (0,0,1,.1) * float(arc_list.num_endpoints) * 32./255.;
+ }
+
+ gskSetOutputColor(color);
+}
diff --git a/gsk/gl/resources/glyphy.vs.glsl b/gsk/gl/resources/glyphy.vs.glsl
new file mode 100644
index 0000000000..4e2ec4c2e0
--- /dev/null
+++ b/gsk/gl/resources/glyphy.vs.glsl
@@ -0,0 +1,24 @@
+// VERTEX_SHADER:
+// glyphy.vs.glsl
+
+_OUT_ vec4 v_glyph;
+_OUT_ vec4 final_color;
+
+vec4
+glyph_vertex_transcode (vec2 v)
+{
+ ivec2 g = ivec2 (v);
+ ivec2 corner = ivec2 (mod (v, 2.));
+ g /= 2;
+ ivec2 nominal_size = ivec2 (mod (vec2(g), 64.));
+ return vec4 (corner * nominal_size, g * 4);
+}
+
+void
+main()
+{
+ v_glyph = glyph_vertex_transcode(aUv);
+ vUv = v_glyph.zw;
+ gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+ final_color = gsk_scaled_premultiply(aColor, u_alpha);
+}
diff --git a/gsk/meson.build b/gsk/meson.build
index 4a9f16211a..7f37434ce6 100644
--- a/gsk/meson.build
+++ b/gsk/meson.build
@@ -19,6 +19,9 @@ gsk_private_gl_shaders = [
'gl/resources/repeat.glsl',
'gl/resources/custom.glsl',
'gl/resources/filled_border.glsl',
+ 'gl/resources/glyphy.atlas.glsl',
+ 'gl/resources/glyphy.fs.glsl',
+ 'gl/resources/glyphy.vs.glsl',
]
gsk_public_sources = files([
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]