gpu: Add glyphs support
This is very rudimentary, but it's a step in the direction of getting text going. There's lots of things missing still.
This commit is contained in:
@@ -2,15 +2,20 @@
|
||||
|
||||
#include "gskgpudeviceprivate.h"
|
||||
|
||||
#include "gskgpuframeprivate.h"
|
||||
#include "gskgpuuploadopprivate.h"
|
||||
|
||||
#include "gdk/gdkdisplayprivate.h"
|
||||
#include "gdk/gdktextureprivate.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GSK_GPU_CACHE_TEXTURE
|
||||
GSK_GPU_CACHE_TEXTURE,
|
||||
GSK_GPU_CACHE_GLYPH
|
||||
} GskGpuCacheType;
|
||||
|
||||
typedef struct _GskGpuCachedTexture GskGpuCachedTexture;
|
||||
typedef struct _GskGpuCachedGlyph GskGpuCachedGlyph;
|
||||
typedef struct _GskGpuCacheEntry GskGpuCacheEntry;
|
||||
|
||||
struct _GskGpuCacheEntry
|
||||
@@ -26,6 +31,19 @@ struct _GskGpuCachedTexture
|
||||
GskGpuImage *image;
|
||||
};
|
||||
|
||||
struct _GskGpuCachedGlyph
|
||||
{
|
||||
GskGpuCacheEntry entry;
|
||||
PangoFont *font;
|
||||
PangoGlyph glyph;
|
||||
GskGpuGlyphLookupFlags flags;
|
||||
float scale;
|
||||
|
||||
GskGpuImage *image;
|
||||
graphene_rect_t bounds;
|
||||
graphene_point_t origin;
|
||||
};
|
||||
|
||||
#define GDK_ARRAY_NAME gsk_gpu_cache_entries
|
||||
#define GDK_ARRAY_TYPE_NAME GskGpuCacheEntries
|
||||
#define GDK_ARRAY_ELEMENT_TYPE GskGpuCacheEntry *
|
||||
@@ -41,10 +59,35 @@ struct _GskGpuDevicePrivate
|
||||
|
||||
GskGpuCacheEntries cache;
|
||||
guint cache_gc_source;
|
||||
GHashTable *glyph_cache;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (GskGpuDevice, gsk_gpu_device, G_TYPE_OBJECT)
|
||||
|
||||
static guint
|
||||
gsk_gpu_cached_glyph_hash (gconstpointer data)
|
||||
{
|
||||
const GskGpuCachedGlyph *glyph = data;
|
||||
|
||||
return GPOINTER_TO_UINT (glyph->font) ^
|
||||
glyph->glyph ^
|
||||
(glyph->flags << 24) ^
|
||||
((guint) glyph->scale * PANGO_SCALE);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_gpu_cached_glyph_equal (gconstpointer v1,
|
||||
gconstpointer v2)
|
||||
{
|
||||
const GskGpuCachedGlyph *glyph1 = v1;
|
||||
const GskGpuCachedGlyph *glyph2 = v2;
|
||||
|
||||
return glyph1->font == glyph2->font
|
||||
&& glyph1->glyph == glyph2->glyph
|
||||
&& glyph1->flags == glyph2->flags
|
||||
&& glyph1->scale == glyph2->scale;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gpu_device_gc (GskGpuDevice *self,
|
||||
gint64 timestamp)
|
||||
@@ -69,6 +112,9 @@ gsk_gpu_device_gc (GskGpuDevice *self,
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_GPU_CACHE_GLYPH:
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
@@ -105,6 +151,16 @@ gsk_gpu_device_clear_cache (GskGpuDevice *self)
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_GPU_CACHE_GLYPH:
|
||||
{
|
||||
GskGpuCachedGlyph *glyph = (GskGpuCachedGlyph *) entry;
|
||||
|
||||
g_object_unref (glyph->font);
|
||||
g_object_unref (glyph->image);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
@@ -122,6 +178,7 @@ gsk_gpu_device_dispose (GObject *object)
|
||||
GskGpuDevice *self = GSK_GPU_DEVICE (object);
|
||||
GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self);
|
||||
|
||||
g_hash_table_unref (priv->glyph_cache);
|
||||
gsk_gpu_device_clear_cache (self);
|
||||
gsk_gpu_cache_entries_clear (&priv->cache);
|
||||
|
||||
@@ -154,6 +211,8 @@ gsk_gpu_device_init (GskGpuDevice *self)
|
||||
GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self);
|
||||
|
||||
gsk_gpu_cache_entries_init (&priv->cache);
|
||||
priv->glyph_cache = g_hash_table_new (gsk_gpu_cached_glyph_hash,
|
||||
gsk_gpu_cached_glyph_equal);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -241,3 +300,77 @@ gsk_gpu_device_cache_texture_image (GskGpuDevice *self,
|
||||
gdk_texture_set_render_data (texture, self, cache, gsk_gpu_device_cache_texture_destroy_cb);
|
||||
gsk_gpu_cache_entries_append (&priv->cache, (GskGpuCacheEntry *) cache);
|
||||
}
|
||||
|
||||
GskGpuImage *
|
||||
gsk_gpu_device_lookup_glyph_image (GskGpuDevice *self,
|
||||
GskGpuFrame *frame,
|
||||
PangoFont *font,
|
||||
PangoGlyph glyph,
|
||||
GskGpuGlyphLookupFlags flags,
|
||||
float scale,
|
||||
graphene_rect_t *out_bounds,
|
||||
graphene_point_t *out_origin)
|
||||
{
|
||||
GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self);
|
||||
GskGpuCachedGlyph lookup = {
|
||||
.font = font,
|
||||
.glyph = glyph,
|
||||
.flags = flags,
|
||||
.scale = scale
|
||||
};
|
||||
GskGpuCachedGlyph *cache;
|
||||
PangoRectangle ink_rect;
|
||||
graphene_rect_t rect;
|
||||
|
||||
cache = g_hash_table_lookup (priv->glyph_cache, &lookup);
|
||||
if (cache)
|
||||
{
|
||||
cache->entry.last_use_timestamp = gsk_gpu_frame_get_timestamp (frame);
|
||||
*out_bounds = cache->bounds;
|
||||
*out_origin = cache->origin;
|
||||
return cache->image;
|
||||
}
|
||||
|
||||
cache = g_new (GskGpuCachedGlyph, 1);
|
||||
pango_font_get_glyph_extents (font, glyph, &ink_rect, NULL);
|
||||
rect.origin.x = floor (ink_rect.x * scale / PANGO_SCALE) - 1;
|
||||
rect.origin.y = floor (ink_rect.y * scale / PANGO_SCALE) - 1;
|
||||
rect.size.width = ceil ((ink_rect.x + ink_rect.width) * scale / PANGO_SCALE) - rect.origin.x + 2;
|
||||
rect.size.height = ceil ((ink_rect.y + ink_rect.height) * scale / PANGO_SCALE) - rect.origin.y + 2;
|
||||
|
||||
*cache = (GskGpuCachedGlyph) {
|
||||
.entry = {
|
||||
.type = GSK_GPU_CACHE_GLYPH,
|
||||
.last_use_timestamp = gsk_gpu_frame_get_timestamp (frame),
|
||||
},
|
||||
.font = g_object_ref (font),
|
||||
.glyph = glyph,
|
||||
.flags = flags,
|
||||
.scale = scale,
|
||||
.image = gsk_gpu_device_create_upload_image (self, GDK_MEMORY_DEFAULT, rect.size.width, rect.size.height),
|
||||
.bounds = GRAPHENE_RECT_INIT (0, 0, rect.size.width, rect.size.height),
|
||||
.origin = GRAPHENE_POINT_INIT (-rect.origin.x + (flags & 3) / 4.f,
|
||||
-rect.origin.y + ((flags >> 2) & 3) / 4.f)
|
||||
};
|
||||
|
||||
gsk_gpu_upload_glyph_op (frame,
|
||||
cache->image,
|
||||
font,
|
||||
glyph,
|
||||
&(cairo_rectangle_int_t) {
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = rect.size.width,
|
||||
.height = rect.size.height
|
||||
},
|
||||
scale,
|
||||
&cache->origin);
|
||||
|
||||
g_hash_table_insert (priv->glyph_cache, cache, cache);
|
||||
gsk_gpu_cache_entries_append (&priv->cache, (GskGpuCacheEntry *) cache);
|
||||
|
||||
*out_bounds = cache->bounds;
|
||||
*out_origin = cache->origin;
|
||||
return cache->image;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include "gskgputypesprivate.h"
|
||||
|
||||
#include <graphene.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_GPU_DEVICE (gsk_gpu_device_get_type ())
|
||||
@@ -58,6 +60,26 @@ void gsk_gpu_device_cache_texture_image (GskGpuD
|
||||
gint64 timestamp,
|
||||
GskGpuImage *image);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GSK_GPU_GLYPH_X_OFFSET_1 = 0x1,
|
||||
GSK_GPU_GLYPH_X_OFFSET_2 = 0x2,
|
||||
GSK_GPU_GLYPH_X_OFFSET_3 = 0x3,
|
||||
GSK_GPU_GLYPH_Y_OFFSET_1 = 0x4,
|
||||
GSK_GPU_GLYPH_Y_OFFSET_2 = 0x8,
|
||||
GSK_GPU_GLYPH_Y_OFFSET_3 = 0xC
|
||||
} GskGpuGlyphLookupFlags;
|
||||
|
||||
GskGpuImage * gsk_gpu_device_lookup_glyph_image (GskGpuDevice *self,
|
||||
GskGpuFrame *frame,
|
||||
PangoFont *font,
|
||||
PangoGlyph glyph,
|
||||
GskGpuGlyphLookupFlags flags,
|
||||
float scale,
|
||||
graphene_rect_t *out_bounds,
|
||||
graphene_point_t *out_origin);
|
||||
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GskGpuDevice, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
@@ -766,6 +766,97 @@ gsk_gpu_node_processor_create_texture_pattern (GskGpuNodeProcessor *self,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_gpu_node_processor_create_glyph_pattern (GskGpuNodeProcessor *self,
|
||||
GskGpuBufferWriter *writer,
|
||||
GskRenderNode *node,
|
||||
GskGpuShaderImage *images,
|
||||
gsize n_images,
|
||||
gsize *out_n_images)
|
||||
{
|
||||
GskGpuDevice *device;
|
||||
const PangoGlyphInfo *glyphs;
|
||||
PangoFont *font;
|
||||
guint num_glyphs;
|
||||
gsize i;
|
||||
float scale, inv_scale;
|
||||
guint n_used;
|
||||
guint32 tex_id;
|
||||
GskGpuImage *last_image;
|
||||
graphene_point_t offset;
|
||||
|
||||
if (gsk_text_node_has_color_glyphs (node))
|
||||
return FALSE;
|
||||
|
||||
device = gsk_gpu_frame_get_device (self->frame);
|
||||
num_glyphs = gsk_text_node_get_num_glyphs (node);
|
||||
glyphs = gsk_text_node_get_glyphs (node, NULL);
|
||||
font = gsk_text_node_get_font (node);
|
||||
offset = *gsk_text_node_get_offset (node);
|
||||
offset.x += self->offset.x;
|
||||
offset.y += self->offset.y;
|
||||
|
||||
scale = MAX (graphene_vec2_get_x (&self->scale), graphene_vec2_get_y (&self->scale));
|
||||
inv_scale = 1.f / scale;
|
||||
|
||||
gsk_gpu_buffer_writer_append_uint (writer, GSK_GPU_PATTERN_GLYPHS);
|
||||
gsk_gpu_buffer_writer_append_rgba (writer, gsk_text_node_get_color (node));
|
||||
gsk_gpu_buffer_writer_append_uint (writer, num_glyphs);
|
||||
|
||||
last_image = NULL;
|
||||
n_used = 0;
|
||||
for (i = 0; i < num_glyphs; i++)
|
||||
{
|
||||
GskGpuImage *image;
|
||||
graphene_rect_t glyph_bounds;
|
||||
graphene_point_t glyph_offset;
|
||||
|
||||
image = gsk_gpu_device_lookup_glyph_image (device,
|
||||
self->frame,
|
||||
font,
|
||||
glyphs[i].glyph,
|
||||
0,
|
||||
scale,
|
||||
&glyph_bounds,
|
||||
&glyph_offset);
|
||||
|
||||
if (image != last_image)
|
||||
{
|
||||
if (n_used >= n_images)
|
||||
return FALSE;
|
||||
|
||||
tex_id = gsk_gpu_frame_get_image_descriptor (self->frame, image, GSK_GPU_SAMPLER_DEFAULT);
|
||||
images[n_used].image = image;
|
||||
images[n_used].sampler = GSK_GPU_SAMPLER_DEFAULT;
|
||||
images[n_used].descriptor = tex_id;
|
||||
last_image = image;
|
||||
n_used++;
|
||||
}
|
||||
|
||||
graphene_rect_scale (&glyph_bounds, inv_scale, inv_scale, &glyph_bounds);
|
||||
glyph_offset = GRAPHENE_POINT_INIT (offset.x - glyph_offset.x * inv_scale + (float) glyphs[i].geometry.x_offset / PANGO_SCALE,
|
||||
offset.y - glyph_offset.y * inv_scale + (float) glyphs[i].geometry.y_offset / PANGO_SCALE);
|
||||
|
||||
gsk_gpu_buffer_writer_append_uint (writer, tex_id);
|
||||
gsk_gpu_buffer_writer_append_rect (writer,
|
||||
&glyph_bounds,
|
||||
&glyph_offset);
|
||||
gsk_gpu_buffer_writer_append_rect (writer,
|
||||
&GRAPHENE_RECT_INIT (
|
||||
0, 0,
|
||||
gsk_gpu_image_get_width (image) * inv_scale,
|
||||
gsk_gpu_image_get_height (image) * inv_scale
|
||||
),
|
||||
&glyph_offset);
|
||||
|
||||
offset.x += (float) glyphs[i].geometry.width / PANGO_SCALE;
|
||||
}
|
||||
|
||||
*out_n_images = n_used;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_gpu_node_processor_create_opacity_pattern (GskGpuNodeProcessor *self,
|
||||
GskGpuBufferWriter *writer,
|
||||
@@ -944,7 +1035,7 @@ static const struct
|
||||
[GSK_TEXT_NODE] = {
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
gsk_gpu_node_processor_create_glyph_pattern,
|
||||
},
|
||||
[GSK_BLUR_NODE] = {
|
||||
0,
|
||||
|
||||
@@ -33,5 +33,6 @@ typedef enum {
|
||||
GSK_GPU_PATTERN_OPACITY,
|
||||
GSK_GPU_PATTERN_TEXTURE,
|
||||
GSK_GPU_PATTERN_COLOR_MATRIX,
|
||||
GSK_GPU_PATTERN_GLYPHS,
|
||||
} GskGpuPatternType;
|
||||
|
||||
|
||||
@@ -445,3 +445,151 @@ gsk_gpu_upload_cairo_op (GskGpuFrame *frame,
|
||||
return self->image;
|
||||
}
|
||||
|
||||
typedef struct _GskGpuUploadGlyphOp GskGpuUploadGlyphOp;
|
||||
|
||||
struct _GskGpuUploadGlyphOp
|
||||
{
|
||||
GskGpuOp op;
|
||||
|
||||
GskGpuImage *image;
|
||||
cairo_rectangle_int_t area;
|
||||
PangoFont *font;
|
||||
PangoGlyph glyph;
|
||||
float scale;
|
||||
graphene_point_t origin;
|
||||
|
||||
GskGpuBuffer *buffer;
|
||||
};
|
||||
|
||||
static void
|
||||
gsk_gpu_upload_glyph_op_finish (GskGpuOp *op)
|
||||
{
|
||||
GskGpuUploadGlyphOp *self = (GskGpuUploadGlyphOp *) op;
|
||||
|
||||
g_object_unref (self->image);
|
||||
g_object_unref (self->font);
|
||||
|
||||
g_clear_object (&self->buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gpu_upload_glyph_op_print (GskGpuOp *op,
|
||||
GskGpuFrame *frame,
|
||||
GString *string,
|
||||
guint indent)
|
||||
{
|
||||
GskGpuUploadGlyphOp *self = (GskGpuUploadGlyphOp *) op;
|
||||
|
||||
gsk_gpu_print_op (string, indent, "upload-glyph");
|
||||
gsk_gpu_print_int_rect (string, &self->area);
|
||||
g_string_append_printf (string, "glyph %u @ %g ", self->glyph, self->scale);
|
||||
gsk_gpu_print_newline (string);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gpu_upload_glyph_op_draw (GskGpuOp *op,
|
||||
guchar *data,
|
||||
gsize stride)
|
||||
{
|
||||
GskGpuUploadGlyphOp *self = (GskGpuUploadGlyphOp *) op;
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cr;
|
||||
|
||||
surface = cairo_image_surface_create_for_data (data,
|
||||
CAIRO_FORMAT_ARGB32,
|
||||
self->area.width,
|
||||
self->area.height,
|
||||
stride);
|
||||
cairo_surface_set_device_offset (surface, self->origin.x, self->origin.y);
|
||||
cairo_surface_set_device_scale (surface, self->scale, self->scale);
|
||||
|
||||
cr = cairo_create (surface);
|
||||
|
||||
/* Make sure the entire surface is initialized to black */
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
|
||||
cairo_paint (cr);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
||||
|
||||
/* Draw glyph */
|
||||
cairo_set_source_rgba (cr, 1, 1, 1, 1);
|
||||
|
||||
pango_cairo_show_glyph_string (cr,
|
||||
self->font,
|
||||
&(PangoGlyphString) {
|
||||
.num_glyphs = 1,
|
||||
.glyphs = (PangoGlyphInfo[1]) { {
|
||||
.glyph = self->glyph
|
||||
} }
|
||||
});
|
||||
|
||||
cairo_destroy (cr);
|
||||
|
||||
cairo_surface_finish (surface);
|
||||
cairo_surface_destroy (surface);
|
||||
}
|
||||
|
||||
#ifdef GDK_RENDERING_VULKAN
|
||||
static GskGpuOp *
|
||||
gsk_gpu_upload_glyph_op_vk_command (GskGpuOp *op,
|
||||
GskGpuFrame *frame,
|
||||
VkRenderPass render_pass,
|
||||
VkFormat format,
|
||||
VkCommandBuffer command_buffer)
|
||||
{
|
||||
GskGpuUploadGlyphOp *self = (GskGpuUploadGlyphOp *) op;
|
||||
|
||||
return gsk_gpu_upload_op_vk_command_with_area (op,
|
||||
frame,
|
||||
command_buffer,
|
||||
GSK_VULKAN_IMAGE (self->image),
|
||||
&self->area,
|
||||
gsk_gpu_upload_glyph_op_draw,
|
||||
&self->buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
static GskGpuOp *
|
||||
gsk_gpu_upload_glyph_op_gl_command (GskGpuOp *op,
|
||||
GskGpuFrame *frame,
|
||||
gsize flip_y)
|
||||
{
|
||||
GskGpuUploadGlyphOp *self = (GskGpuUploadGlyphOp *) op;
|
||||
|
||||
return gsk_gpu_upload_op_gl_command_with_area (op,
|
||||
frame,
|
||||
self->image,
|
||||
&self->area,
|
||||
gsk_gpu_upload_glyph_op_draw);
|
||||
}
|
||||
|
||||
static const GskGpuOpClass GSK_GPU_UPLOAD_GLYPH_OP_CLASS = {
|
||||
GSK_GPU_OP_SIZE (GskGpuUploadGlyphOp),
|
||||
GSK_GPU_STAGE_UPLOAD,
|
||||
gsk_gpu_upload_glyph_op_finish,
|
||||
gsk_gpu_upload_glyph_op_print,
|
||||
#ifdef GDK_RENDERING_VULKAN
|
||||
gsk_gpu_upload_glyph_op_vk_command,
|
||||
#endif
|
||||
gsk_gpu_upload_glyph_op_gl_command,
|
||||
};
|
||||
|
||||
void
|
||||
gsk_gpu_upload_glyph_op (GskGpuFrame *frame,
|
||||
GskGpuImage *image,
|
||||
PangoFont *font,
|
||||
const PangoGlyph glyph,
|
||||
const cairo_rectangle_int_t *area,
|
||||
float scale,
|
||||
const graphene_point_t *origin)
|
||||
{
|
||||
GskGpuUploadGlyphOp *self;
|
||||
|
||||
self = (GskGpuUploadGlyphOp *) gsk_gpu_op_alloc (frame, &GSK_GPU_UPLOAD_GLYPH_OP_CLASS);
|
||||
|
||||
self->image = g_object_ref (image);
|
||||
self->area = *area;
|
||||
self->font = g_object_ref (font);
|
||||
self->glyph = glyph;
|
||||
self->scale = scale;
|
||||
self->origin = *origin;
|
||||
}
|
||||
|
||||
@@ -16,10 +16,11 @@ GskGpuImage * gsk_gpu_upload_cairo_op (GskGpuF
|
||||
|
||||
void gsk_gpu_upload_glyph_op (GskGpuFrame *frame,
|
||||
GskGpuImage *image,
|
||||
cairo_rectangle_int_t *area,
|
||||
PangoFont *font,
|
||||
PangoGlyphInfo *glyph_info,
|
||||
float scale);
|
||||
PangoGlyph glyph,
|
||||
const cairo_rectangle_int_t *area,
|
||||
float scale,
|
||||
const graphene_point_t *origin);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@@ -10,5 +10,6 @@
|
||||
#define GSK_GPU_PATTERN_OPACITY 2u
|
||||
#define GSK_GPU_PATTERN_TEXTURE 3u
|
||||
#define GSK_GPU_PATTERN_COLOR_MATRIX 4u
|
||||
#define GSK_GPU_PATTERN_GLYPHS 5u
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define _PATTERN_
|
||||
|
||||
#include "common.glsl"
|
||||
#include "rect.glsl"
|
||||
|
||||
#ifdef GSK_FRAGMENT_SHADER
|
||||
|
||||
@@ -27,6 +28,12 @@ read_vec4 (inout uint reader)
|
||||
return vec4 (read_float (reader), read_float (reader), read_float (reader), read_float (reader));
|
||||
}
|
||||
|
||||
Rect
|
||||
read_rect (inout uint reader)
|
||||
{
|
||||
return rect_from_gsk (read_vec4 (reader));
|
||||
}
|
||||
|
||||
mat4
|
||||
read_mat4 (inout uint reader)
|
||||
{
|
||||
@@ -68,6 +75,29 @@ color_matrix_pattern (inout uint reader,
|
||||
color = color_premultiply (color);
|
||||
}
|
||||
|
||||
vec4
|
||||
glyphs_pattern (inout uint reader,
|
||||
vec2 pos)
|
||||
{
|
||||
float opacity = 0.0;
|
||||
vec4 color = color_premultiply (read_vec4 (reader));
|
||||
uint num_glyphs = read_uint (reader);
|
||||
uint i;
|
||||
|
||||
for (i = 0u; i < num_glyphs; i++)
|
||||
{
|
||||
uint tex_id = read_uint (reader);
|
||||
Rect glyph_bounds = read_rect (reader);
|
||||
vec4 tex_rect = read_vec4 (reader);
|
||||
|
||||
float coverage = rect_coverage (glyph_bounds, pos);
|
||||
if (coverage > 0.0)
|
||||
opacity += coverage * texture (gsk_get_texture (tex_id), (pos - push.scale * tex_rect.xy) / (push.scale * tex_rect.zw)).a;
|
||||
}
|
||||
|
||||
return color * opacity;
|
||||
}
|
||||
|
||||
vec4
|
||||
texture_pattern (inout uint reader,
|
||||
vec2 pos)
|
||||
@@ -106,6 +136,9 @@ pattern (uint reader,
|
||||
case GSK_GPU_PATTERN_TEXTURE:
|
||||
color = texture_pattern (reader, pos);
|
||||
break;
|
||||
case GSK_GPU_PATTERN_GLYPHS:
|
||||
color = glyphs_pattern (reader, pos);
|
||||
break;
|
||||
case GSK_GPU_PATTERN_COLOR_MATRIX:
|
||||
color_matrix_pattern (reader, color, pos);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user