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.
This commit is contained in:
committed by
Matthias Clasen
parent
5cadf635ab
commit
ad9d916dfd
@@ -87,3 +87,22 @@ GSK_GL_DEFINE_PROGRAM (unblurred_outset_shadow,
|
|||||||
GSK_GL_ADD_UNIFORM (1, UNBLURRED_OUTSET_SHADOW_SPREAD, u_spread)
|
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 (2, UNBLURRED_OUTSET_SHADOW_OFFSET, u_offset)
|
||||||
GSK_GL_ADD_UNIFORM (3, UNBLURRED_OUTSET_SHADOW_OUTLINE_RECT, u_outline_rect))
|
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))
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
#include "gskglcommandqueueprivate.h"
|
#include "gskglcommandqueueprivate.h"
|
||||||
#include "gskgldriverprivate.h"
|
#include "gskgldriverprivate.h"
|
||||||
#include "gskglglyphlibraryprivate.h"
|
#include "gskglglyphlibraryprivate.h"
|
||||||
|
#include "gskglglyphylibraryprivate.h"
|
||||||
#include "gskgliconlibraryprivate.h"
|
#include "gskgliconlibraryprivate.h"
|
||||||
#include "gskglprogramprivate.h"
|
#include "gskglprogramprivate.h"
|
||||||
#include "gskglrenderjobprivate.h"
|
#include "gskglrenderjobprivate.h"
|
||||||
@@ -3093,12 +3094,193 @@ gsk_gl_render_job_visit_text_node_legacy (GskGLRenderJob *job,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Keep this in sync with glyph_vertex_transcode in glyphy.vs.glsl */
|
||||||
|
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
|
static inline void
|
||||||
gsk_gl_render_job_visit_text_node_glyphy (GskGLRenderJob *job,
|
gsk_gl_render_job_visit_text_node_glyphy (GskGLRenderJob *job,
|
||||||
const GskRenderNode *node,
|
const GskRenderNode *node,
|
||||||
const GdkRGBA *color,
|
const GdkRGBA *color)
|
||||||
gboolean force_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
|
static inline void
|
||||||
@@ -3108,7 +3290,7 @@ gsk_gl_render_job_visit_text_node (GskGLRenderJob *job,
|
|||||||
gboolean force_color)
|
gboolean force_color)
|
||||||
{
|
{
|
||||||
if (!gsk_text_node_has_color_glyphs (node))
|
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
|
else
|
||||||
gsk_gl_render_job_visit_text_node_legacy (job, node, color, force_color);
|
gsk_gl_render_job_visit_text_node_legacy (job, node, color, force_color);
|
||||||
}
|
}
|
||||||
|
|||||||
15
gsk/gl/resources/glyphy.atlas.glsl
Normal file
15
gsk/gl/resources/glyphy.atlas.glsl
Normal file
@@ -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);
|
||||||
|
}
|
||||||
88
gsk/gl/resources/glyphy.fs.glsl
Normal file
88
gsk/gl/resources/glyphy.fs.glsl
Normal file
@@ -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);
|
||||||
|
}
|
||||||
25
gsk/gl/resources/glyphy.vs.glsl
Normal file
25
gsk/gl/resources/glyphy.vs.glsl
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// VERTEX_SHADER:
|
||||||
|
// glyphy.vs.glsl
|
||||||
|
|
||||||
|
_OUT_ vec4 v_glyph;
|
||||||
|
_OUT_ vec4 final_color;
|
||||||
|
|
||||||
|
// Keep this in sync with glyph_encode in gskglrenderjob.c
|
||||||
|
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);
|
||||||
|
}
|
||||||
@@ -20,6 +20,9 @@ gsk_private_gl_shaders = [
|
|||||||
'gl/resources/custom.glsl',
|
'gl/resources/custom.glsl',
|
||||||
'gl/resources/filled_border.glsl',
|
'gl/resources/filled_border.glsl',
|
||||||
'gl/resources/mask.glsl',
|
'gl/resources/mask.glsl',
|
||||||
|
'gl/resources/glyphy.atlas.glsl',
|
||||||
|
'gl/resources/glyphy.fs.glsl',
|
||||||
|
'gl/resources/glyphy.vs.glsl',
|
||||||
]
|
]
|
||||||
|
|
||||||
gsk_public_sources = files([
|
gsk_public_sources = files([
|
||||||
|
|||||||
Reference in New Issue
Block a user