[gtk/glyphy2: 41/53] gsk/gl: start on basic glyphy renderjob integration




commit bd879d5ffe8d9df6628d1d3603d0a0a4ed13eee6
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]