Compare commits

...

20 Commits

Author SHA1 Message Date
Matthias Clasen
5e87f96aaf Per-glyph instance for color text as well 2017-09-10 13:44:43 -04:00
Matthias Clasen
ffd2e620ba fixup 2017-09-10 13:32:42 -04:00
Matthias Clasen
aec50193b0 wip: work towards per-glyph instances
Doesn't quite work yet
2017-09-10 13:27:58 -04:00
Matthias Clasen
2f46bd772e drop todo
All of this is backend work now
2017-09-10 10:11:20 -04:00
Matthias Clasen
797042e616 Drop has-color from text node
The vulkan code now figures this out when it needs to.
2017-09-10 10:09:29 -04:00
Matthias Clasen
ab00930bca update todo 2017-09-10 10:05:00 -04:00
Matthias Clasen
8b70b91a76 Use vulkan images for text
We are still using a single texture for each
glyph string.

Along the way, we drop the surface from the text node
and return gsk_text_node_draw to the way it was initially,
directly drawing on the provided cairo_t.
2017-09-10 10:03:32 -04:00
Matthias Clasen
b47fe87d61 Add code to put glyphs in a vulkan image 2017-09-10 10:02:41 -04:00
Matthias Clasen
63a1dc16ae Drop the surface caching 2017-09-10 10:02:41 -04:00
Matthias Clasen
f1a36a93cb update todo 2017-09-10 10:02:41 -04:00
Matthias Clasen
e1adca7301 Use color text pipeline
At the same time, rename the render ops to TEXT and COLOR_TEXT.
2017-09-10 10:02:41 -04:00
Matthias Clasen
0152a4b309 Add a color text pipeline
For now, this will be just the same as the blend pipeline,
but it will eventually do per-glyph instances.
2017-09-10 08:01:03 -04:00
Matthias Clasen
e4b5835185 Rename mask pipeline to text pipeline
It will become text-specific when we move to using one
instance per glyph, so rename it already.
2017-09-10 07:52:22 -04:00
Matthias Clasen
a6a3186bd7 update todo 2017-09-10 07:37:00 -04:00
Matthias Clasen
40de42cff9 update todo list 2017-09-09 23:00:13 -04:00
Matthias Clasen
36001547f5 Fix the mask renderer 2017-09-09 22:59:29 -04:00
Matthias Clasen
a87b120a2d more work-in-progress
Use the proper blend factors for masks. Still doesn't work.
2017-09-09 22:31:02 -04:00
Matthias Clasen
fca1a9244e wip: add a mask shader
It doesn't work yet.
2017-09-09 12:43:42 -04:00
Matthias Clasen
ae574b168a More text node work
Use the surface as a plain texture. This currently doesn't do
the right thing for masking, and loses text color. Keep a simple
cache of the surfaces.
2017-09-09 11:41:43 -04:00
Matthias Clasen
344bad9788 More work on text nodes
This commit takes several steps towards rendering text
like we want to. We use cairo to create a mask surface.
In draw(), we use it to paint individual glyphs with the
text color, unless we are dealing with color glyphs,
in which case we use the surface as source. The surface
will eventually be replaced by a font atlas texture.

This commit also simplifies the text node api to just
have a single offset, which determines the left end of
the text baseline, like all our other text drawing APIs.

We temporarily drop text node serialization, since it
will have to change anyway.
2017-09-09 09:22:57 -04:00
28 changed files with 1074 additions and 164 deletions

View File

@@ -15,3 +15,23 @@ gsk_ensure_resources (void)
g_once (&register_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;
}

View File

@@ -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__ */

View File

@@ -178,10 +178,8 @@ GDK_AVAILABLE_IN_3_92
GskRenderNode * gsk_text_node_new (PangoFont *font,
PangoGlyphString *glyphs,
const GdkRGBA *color,
int x_offset,
int y_offset,
double base_x,
double base_y);
double x,
double y);
GDK_AVAILABLE_IN_3_92
GskRenderNode * gsk_blur_node_new (GskRenderNode *child,

View File

@@ -26,8 +26,6 @@
#include "gskroundedrectprivate.h"
#include "gsktextureprivate.h"
#include <cairo-ft.h>
static gboolean
check_variant_type (GVariant *variant,
const char *type_string,
@@ -3812,13 +3810,13 @@ struct _GskTextNode
GskRenderNode render_node;
PangoFont *font;
gboolean has_color;
PangoGlyphString *glyphs;
GdkRGBA color;
int x_offset;
int y_offset;
double base_x;
double base_y;
double x;
double y;
double ink_rect_y;
double ink_rect_height;
};
static void
@@ -3830,20 +3828,6 @@ gsk_text_node_finalize (GskRenderNode *node)
pango_glyph_string_free (self->glyphs);
}
static gboolean
_pango_cairo_font_install (PangoFont *font,
cairo_t *cr)
{
cairo_scaled_font_t *scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *)font);
if (G_UNLIKELY (scaled_font == NULL || cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS))
return FALSE;
cairo_set_scaled_font (cr, scaled_font);
return TRUE;
}
#ifndef STACK_BUFFER_SIZE
#define STACK_BUFFER_SIZE (512 * sizeof (int))
#endif
@@ -3857,16 +3841,19 @@ gsk_text_node_draw (GskRenderNode *node,
GskTextNode *self = (GskTextNode *) node;
int i, count;
int x_position = 0;
cairo_scaled_font_t *scaled_font;
cairo_glyph_t *cairo_glyphs;
cairo_glyph_t stack_glyphs[STACK_ARRAY_LENGTH (cairo_glyph_t)];
scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *)self->font);
if (G_UNLIKELY (!scaled_font || cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS))
return;
cairo_save (cr);
cairo_translate (cr, self->x_offset, self->y_offset);
cairo_translate (cr, self->x, self->y);
cairo_set_scaled_font (cr, scaled_font);
gdk_cairo_set_source_rgba (cr, &self->color);
if (!_pango_cairo_font_install (self->font, cr))
goto done;
if (self->glyphs->num_glyphs > (int) G_N_ELEMENTS (stack_glyphs))
cairo_glyphs = g_new (cairo_glyph_t, self->glyphs->num_glyphs);
@@ -3880,8 +3867,8 @@ gsk_text_node_draw (GskRenderNode *node,
if (gi->glyph != PANGO_GLYPH_EMPTY)
{
double cx = self->base_x + (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
double cy = gi->geometry.y_offset == 0 ? self->base_y : self->base_y + (double)(gi->geometry.y_offset) / PANGO_SCALE;
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))
{
@@ -3899,107 +3886,22 @@ gsk_text_node_draw (GskRenderNode *node,
if (cairo_glyphs != stack_glyphs)
g_free (cairo_glyphs);
done:
cairo_restore (cr);
}
#define GSK_TEXT_NODE_VARIANT_TYPE "(sddddiidda(uiiii))"
static GVariant *
gsk_text_node_serialize (GskRenderNode *node)
{
GskTextNode *self = (GskTextNode *) node;
GVariant *v;
GVariantBuilder builder;
int i;
PangoFontDescription *desc;
char *s;
desc = pango_font_describe (self->font);
s = pango_font_description_to_string (desc);
for (i = 0; i < self->glyphs->num_glyphs; i++)
{
PangoGlyphInfo *glyph = &self->glyphs->glyphs[i];
g_variant_builder_add (&builder, "(uiiii)",
glyph->glyph,
glyph->geometry.width,
glyph->geometry.x_offset,
glyph->geometry.y_offset,
glyph->attr.is_cluster_start);
}
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(uiiii)"));
v = g_variant_new (GSK_TEXT_NODE_VARIANT_TYPE,
s,
self->color.red,
self->color.green,
self->color.blue,
self->color.alpha,
self->x_offset,
self->y_offset,
self->base_x,
self->base_y,
&builder);
g_free (s);
pango_font_description_free (desc);
return v;
g_assert_not_reached ();
return NULL;
}
static GskRenderNode *
gsk_text_node_deserialize (GVariant *variant,
GError **error)
{
PangoFont *font;
PangoGlyphString *glyphs;
GVariantIter iter;
GskRenderNode *result;
PangoGlyphInfo glyph;
PangoFontDescription *desc;
PangoFontMap *fontmap;
PangoContext *context;
int cluster_start;
char *s;
GdkRGBA color;
int x_offset, y_offset;
double base_x, base_y;
int i;
if (!check_variant_type (variant, GSK_TEXT_NODE_VARIANT_TYPE, error))
return NULL;
g_variant_get (variant, "(&sddddiidda(uiiii))",
&color.red, &color.green, &color.blue, &color.alpha,
&x_offset, &y_offset,
&base_x, &base_y,
&s, &iter);
desc = pango_font_description_from_string (s);
fontmap = pango_cairo_font_map_get_default ();
context = pango_font_map_create_context (fontmap);
font = pango_font_map_load_font (fontmap, context, desc);
glyphs = pango_glyph_string_new ();
pango_glyph_string_set_size (glyphs, g_variant_iter_n_children (&iter));
i = 0;
while (g_variant_iter_next (&iter, "(uiiii)", &glyph.glyph, &glyph.geometry.width, &glyph.geometry.x_offset, &glyph.geometry.y_offset, &cluster_start))
{
glyph.attr.is_cluster_start = cluster_start;
glyphs->glyphs[i] = glyph;
i++;
}
result = gsk_text_node_new (font, glyphs, &color, /* FIXME: Avoid copying glyphs */
x_offset, y_offset,
base_x, base_y);
pango_glyph_string_free (glyphs);
pango_font_description_free (desc);
g_object_unref (context);
g_object_unref (font);
return result;
g_assert_not_reached ();
return NULL;
}
static const GskRenderNodeClass GSK_TEXT_NODE_CLASS = {
@@ -4012,31 +3914,12 @@ static const GskRenderNodeClass GSK_TEXT_NODE_CLASS = {
gsk_text_node_deserialize
};
static gboolean
font_has_color_glyphs (PangoFont *font)
{
cairo_scaled_font_t *scaled_font;
gboolean has_color = FALSE;
scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *)font);
if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_FT)
{
FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
has_color = (FT_HAS_COLOR (ft_face) != 0);
cairo_ft_scaled_font_unlock_face (scaled_font);
}
return has_color;
}
GskRenderNode *
gsk_text_node_new (PangoFont *font,
PangoGlyphString *glyphs,
const GdkRGBA *color,
int x_offset,
int y_offset,
double base_x,
double base_y)
double x,
double y)
{
GskTextNode *self;
PangoRectangle ink_rect;
@@ -4053,23 +3936,70 @@ gsk_text_node_new (PangoFont *font,
self->font = g_object_ref (font);
self->glyphs = pango_glyph_string_copy (glyphs);
self->color = *color;
self->x_offset = x_offset;
self->y_offset = y_offset;
self->base_x = base_x;
self->base_y = base_y;
self->has_color = font_has_color_glyphs (font);
self->x = x;
self->y = y;
self->ink_rect_y = ink_rect.y;
self->ink_rect_height = ink_rect.height;
graphene_rect_init (&self->render_node.bounds,
x_offset + base_x + ink_rect.x,
y_offset + base_y + ink_rect.y,
ink_rect.width,
x,
y + ink_rect.y,
ink_rect.x + ink_rect.width,
ink_rect.height);
return &self->render_node;
}
const GdkRGBA *
gsk_text_node_get_color (GskRenderNode *node)
{
GskTextNode *self = (GskTextNode *) node;
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_TEXT_NODE), NULL);
return &self->color;
}
PangoFont *
gsk_text_node_get_font (GskRenderNode *node)
{
GskTextNode *self = (GskTextNode *) node;
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_TEXT_NODE), NULL);
return self->font;
}
PangoGlyphString *
gsk_text_node_get_glyphs (GskRenderNode *node)
{
GskTextNode *self = (GskTextNode *) node;
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_TEXT_NODE), NULL);
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;

View File

@@ -81,6 +81,12 @@ cairo_surface_t *gsk_cairo_node_get_surface (GskRenderNode *node);
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);
const graphene_rect_t * gsk_clip_node_peek_clip (GskRenderNode *node);

View File

@@ -0,0 +1,156 @@
#include "config.h"
#include "gskvulkancolortextpipelineprivate.h"
struct _GskVulkanColorTextPipeline
{
GObject parent_instance;
};
typedef struct _GskVulkanColorTextInstance GskVulkanColorTextInstance;
struct _GskVulkanColorTextInstance
{
float rect[4];
float tex_rect[4];
};
G_DEFINE_TYPE (GskVulkanColorTextPipeline, gsk_vulkan_color_text_pipeline, GSK_TYPE_VULKAN_PIPELINE)
static const VkPipelineVertexInputStateCreateInfo *
gsk_vulkan_color_text_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
{
static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
{
.binding = 0,
.stride = sizeof (GskVulkanColorTextInstance),
.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
}
};
static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
{
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanColorTextInstance, rect),
},
{
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanColorTextInstance, tex_rect),
},
};
static const VkPipelineVertexInputStateCreateInfo info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
.pVertexBindingDescriptions = vertexBindingDescriptions,
.vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
.pVertexAttributeDescriptions = vertexInputAttributeDescription
};
return &info;
}
static void
gsk_vulkan_color_text_pipeline_finalize (GObject *gobject)
{
//GskVulkanColorTextPipeline *self = GSK_VULKAN_COLOR_TEXT_PIPELINE (gobject);
G_OBJECT_CLASS (gsk_vulkan_color_text_pipeline_parent_class)->finalize (gobject);
}
static void
gsk_vulkan_color_text_pipeline_class_init (GskVulkanColorTextPipelineClass *klass)
{
GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_color_text_pipeline_finalize;
pipeline_class->get_input_state_create_info = gsk_vulkan_color_text_pipeline_get_input_state_create_info;
}
static void
gsk_vulkan_color_text_pipeline_init (GskVulkanColorTextPipeline *self)
{
}
GskVulkanPipeline *
gsk_vulkan_color_text_pipeline_new (GskVulkanPipelineLayout *layout,
const char *shader_name,
VkRenderPass render_pass)
{
return gsk_vulkan_pipeline_new_full (GSK_TYPE_VULKAN_COLOR_TEXT_PIPELINE, layout, shader_name, render_pass,
VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA);
}
gsize
gsk_vulkan_color_text_pipeline_count_vertex_data (GskVulkanColorTextPipeline *pipeline,
int num_instances)
{
return sizeof (GskVulkanColorTextInstance) * num_instances;
}
void
gsk_vulkan_color_text_pipeline_collect_vertex_data (GskVulkanColorTextPipeline *pipeline,
guchar *data,
GskVulkanRenderer *renderer,
const graphene_rect_t *rect,
PangoFont *font,
PangoGlyphString *glyphs,
float x,
float y)
{
GskVulkanColorTextInstance *instances = (GskVulkanColorTextInstance *) 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))
{
GskVulkanColorTextInstance *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]);
count++;
}
}
x_position += gi->geometry.width;
}
}
gsize
gsk_vulkan_color_text_pipeline_draw (GskVulkanColorTextPipeline *pipeline,
VkCommandBuffer command_buffer,
gsize offset,
gsize n_commands)
{
vkCmdDraw (command_buffer,
6, n_commands,
0, offset);
return n_commands;
}

View File

@@ -0,0 +1,38 @@
#ifndef __GSK_VULKAN_COLOR_TEXT_PIPELINE_PRIVATE_H__
#define __GSK_VULKAN_COLOR_TEXT_PIPELINE_PRIVATE_H__
#include <graphene.h>
#include "gskvulkanpipelineprivate.h"
#include "gskvulkanrendererprivate.h"
G_BEGIN_DECLS
typedef struct _GskVulkanColorTextPipelineLayout GskVulkanColorTextPipelineLayout;
#define GSK_TYPE_VULKAN_COLOR_TEXT_PIPELINE (gsk_vulkan_color_text_pipeline_get_type ())
G_DECLARE_FINAL_TYPE (GskVulkanColorTextPipeline, gsk_vulkan_color_text_pipeline, GSK, VULKAN_COLOR_TEXT_PIPELINE, GskVulkanPipeline)
GskVulkanPipeline * gsk_vulkan_color_text_pipeline_new (GskVulkanPipelineLayout *layout,
const char *shader_name,
VkRenderPass render_pass);
gsize gsk_vulkan_color_text_pipeline_count_vertex_data (GskVulkanColorTextPipeline *pipeline,
int num_instances);
void gsk_vulkan_color_text_pipeline_collect_vertex_data (GskVulkanColorTextPipeline *pipeline,
guchar *data,
GskVulkanRenderer *renderer,
const graphene_rect_t *rect,
PangoFont *font,
PangoGlyphString *glyphs,
float x,
float y);
gsize gsk_vulkan_color_text_pipeline_draw (GskVulkanColorTextPipeline *pipeline,
VkCommandBuffer command_buffer,
gsize offset,
gsize n_commands);
G_END_DECLS
#endif /* __GSK_VULKAN_COLOR_TEXT_PIPELINE_PRIVATE_H__ */

View File

@@ -67,6 +67,19 @@ gsk_vulkan_pipeline_new (GType pipeline_type,
GskVulkanPipelineLayout *layout,
const char *shader_name,
VkRenderPass render_pass)
{
return gsk_vulkan_pipeline_new_full (pipeline_type, layout, shader_name, render_pass,
VK_BLEND_FACTOR_ONE,
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA);
}
GskVulkanPipeline *
gsk_vulkan_pipeline_new_full (GType pipeline_type,
GskVulkanPipelineLayout *layout,
const char *shader_name,
VkRenderPass render_pass,
VkBlendFactor srcBlendFactor,
VkBlendFactor dstBlendFactor)
{
GskVulkanPipelinePrivate *priv;
GskVulkanPipeline *self;
@@ -134,11 +147,11 @@ gsk_vulkan_pipeline_new (GType pipeline_type,
{
.blendEnable = VK_TRUE,
.colorBlendOp = VK_BLEND_OP_ADD,
.srcColorBlendFactor = VK_BLEND_FACTOR_ONE,
.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
.srcColorBlendFactor = srcBlendFactor,
.dstColorBlendFactor = dstBlendFactor,
.alphaBlendOp = VK_BLEND_OP_ADD,
.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
.srcAlphaBlendFactor = srcBlendFactor,
.dstAlphaBlendFactor = dstBlendFactor,
.colorWriteMask = VK_COLOR_COMPONENT_A_BIT
| VK_COLOR_COMPONENT_R_BIT
| VK_COLOR_COMPONENT_G_BIT

View File

@@ -48,6 +48,12 @@ GskVulkanPipeline * gsk_vulkan_pipeline_new (GType
GskVulkanPipelineLayout *layout,
const char *shader_name,
VkRenderPass render_pass);
GskVulkanPipeline * gsk_vulkan_pipeline_new_full (GType pipeline_type,
GskVulkanPipelineLayout *layout,
const char *shader_name,
VkRenderPass render_pass,
VkBlendFactor srcBlendFactor,
VkBlendFactor dstBlendFactor);
VkPipeline gsk_vulkan_pipeline_get_pipeline (GskVulkanPipeline *self);

View File

@@ -15,8 +15,10 @@
#include "gskvulkanborderpipelineprivate.h"
#include "gskvulkanboxshadowpipelineprivate.h"
#include "gskvulkancolorpipelineprivate.h"
#include "gskvulkancolortextpipelineprivate.h"
#include "gskvulkaneffectpipelineprivate.h"
#include "gskvulkanlineargradientpipelineprivate.h"
#include "gskvulkantextpipelineprivate.h"
#define ORTHO_NEAR_PLANE -10000
#define ORTHO_FAR_PLANE 10000
@@ -303,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);
}
@@ -344,6 +346,12 @@ gsk_vulkan_render_get_pipeline (GskVulkanRender *self,
{ "blur", gsk_vulkan_blur_pipeline_new },
{ "blur-clip", gsk_vulkan_blur_pipeline_new },
{ "blur-clip-rounded", gsk_vulkan_blur_pipeline_new },
{ "mask", gsk_vulkan_text_pipeline_new },
{ "mask-clip", gsk_vulkan_text_pipeline_new },
{ "mask-clip-rounded", gsk_vulkan_text_pipeline_new },
{ "blend", gsk_vulkan_color_text_pipeline_new },
{ "blend-clip", gsk_vulkan_color_text_pipeline_new },
{ "blend-clip-rounded", gsk_vulkan_color_text_pipeline_new },
};
g_return_val_if_fail (type < GSK_VULKAN_N_PIPELINES, NULL);

View File

@@ -44,6 +44,8 @@ struct _GskVulkanRenderer
GSList *textures;
GHashTable *glyph_cache;
#ifdef G_ENABLE_DEBUG
ProfileTimers profile_timers;
#endif
@@ -343,3 +345,271 @@ gsk_vulkan_renderer_ref_texture_image (GskVulkanRenderer *self,
return image;
}
#ifndef STACK_BUFFER_SIZE
#define STACK_BUFFER_SIZE (512 * sizeof (int))
#endif
#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,
GlyphCoords *coords,
int *num_coords,
float x,
float y,
float width,
float height)
{
int i, count;
int x_position = 0;
cairo_scaled_font_t *scaled_font;
cairo_glyph_t *cairo_glyphs;
cairo_glyph_t stack_glyphs[STACK_ARRAY_LENGTH (cairo_glyph_t)];
scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *)font);
if (G_UNLIKELY (!scaled_font || cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS))
return;
cairo_set_scaled_font (cr, scaled_font);
cairo_set_source_rgba (cr, 0, 0, 0, 1);
if (glyphs->num_glyphs > (int) G_N_ELEMENTS (stack_glyphs))
cairo_glyphs = g_new (cairo_glyph_t, glyphs->num_glyphs);
else
cairo_glyphs = stack_glyphs;
count = 0;
for (i = 0; i < glyphs->num_glyphs; i++)
{
PangoGlyphInfo *gi = &glyphs->glyphs[i];
if (gi->glyph != PANGO_GLYPH_EMPTY)
{
double cx = x + (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
double cy = y + (double)(gi->geometry.y_offset) / PANGO_SCALE;
if (!(gi->glyph & PANGO_GLYPH_UNKNOWN_FLAG))
{
cairo_glyphs[count].index = gi->glyph;
cairo_glyphs[count].x = cx;
cairo_glyphs[count].y = cy;
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++;
}
}
x_position += gi->geometry.width;
}
*num_coords = count;
cairo_show_glyphs (cr, cairo_glyphs, count);
if (cairo_glyphs != stack_glyphs)
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,
PangoFont *font,
PangoGlyphString *glyphs)
{
PangoRectangle ink_rect;
cairo_surface_t *surface;
cairo_t *cr;
GskVulkanImage *image;
GlyphCoords *coords;
int num_coords;
coords = g_new0 (GlyphCoords, glyphs->num_glyphs);
pango_glyph_string_extents (glyphs, font, &ink_rect, NULL);
pango_extents_to_pixels (&ink_rect, NULL);
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
ink_rect.x + ink_rect.width,
ink_rect.height);
cr = cairo_create (surface);
render_text (cr, font, glyphs, coords, &num_coords,
0, - ink_rect.y, ink_rect.x + ink_rect.width, ink_rect.height);
cairo_destroy (cr);
image = gsk_vulkan_image_new_from_data (uploader,
cairo_image_surface_get_data (surface),
cairo_image_surface_get_width (surface),
cairo_image_surface_get_height (surface),
cairo_image_surface_get_stride (surface));
cairo_surface_destroy (surface);
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].y;
*width = coords[i].width;
*height = coords[i].height;
break;
}
}
}

View File

@@ -25,6 +25,23 @@ GskVulkanImage * gsk_vulkan_renderer_ref_texture_image (GskVulk
GskTexture *texture,
GskVulkanUploader *uploader);
typedef struct {
float x, y, width, height;
} GskRectangle;
GskVulkanImage * gsk_vulkan_renderer_ref_glyph_image (GskVulkanRenderer *self,
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
#endif /* __GSK_VULKAN_RENDERER_PRIVATE_H__ */

View File

@@ -12,11 +12,16 @@
#include "gskvulkanboxshadowpipelineprivate.h"
#include "gskvulkanclipprivate.h"
#include "gskvulkancolorpipelineprivate.h"
#include "gskvulkancolortextpipelineprivate.h"
#include "gskvulkaneffectpipelineprivate.h"
#include "gskvulkanlineargradientpipelineprivate.h"
#include "gskvulkantextpipelineprivate.h"
#include "gskvulkanimageprivate.h"
#include "gskvulkanpushconstantsprivate.h"
#include "gskvulkanrendererprivate.h"
#include "gskprivate.h"
#include <cairo-ft.h>
typedef union _GskVulkanOp GskVulkanOp;
typedef struct _GskVulkanOpRender GskVulkanOpRender;
@@ -29,6 +34,8 @@ typedef enum {
GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP,
GSK_VULKAN_OP_SURFACE,
GSK_VULKAN_OP_TEXTURE,
GSK_VULKAN_OP_TEXT,
GSK_VULKAN_OP_COLOR_TEXT,
GSK_VULKAN_OP_COLOR,
GSK_VULKAN_OP_LINEAR_GRADIENT,
GSK_VULKAN_OP_OPACITY,
@@ -95,6 +102,23 @@ gsk_vulkan_render_pass_free (GskVulkanRenderPass *self)
g_slice_free (GskVulkanRenderPass, self);
}
static gboolean
font_has_color_glyphs (PangoFont *font)
{
cairo_scaled_font_t *scaled_font;
gboolean has_color = FALSE;
scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *)font);
if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_FT)
{
FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
has_color = (FT_HAS_COLOR (ft_face) != 0);
cairo_ft_scaled_font_unlock_face (scaled_font);
}
return has_color;
}
#define FALLBACK(...) G_STMT_START { \
GSK_NOTE (FALLBACK, g_print (__VA_ARGS__)); \
goto fallback; \
@@ -172,6 +196,35 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
g_array_append_val (self->render_ops, op);
return;
case GSK_TEXT_NODE:
if (font_has_color_glyphs (gsk_text_node_get_font (node)))
{
if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
pipeline_type = GSK_VULKAN_PIPELINE_COLOR_TEXT;
else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
pipeline_type = GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP;
else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
pipeline_type = GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP_ROUNDED;
else
FALLBACK ("Text nodes can't deal with clip type %u\n", constants->clip.type);
op.type = GSK_VULKAN_OP_COLOR_TEXT;
}
else
{
if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
pipeline_type = GSK_VULKAN_PIPELINE_TEXT;
else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
pipeline_type = GSK_VULKAN_PIPELINE_TEXT_CLIP;
else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
pipeline_type = GSK_VULKAN_PIPELINE_TEXT_CLIP_ROUNDED;
else
FALLBACK ("Text nodes can't deal with clip type %u\n", constants->clip.type);
op.type = GSK_VULKAN_OP_TEXT;
}
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
g_array_append_val (self->render_ops, op);
return;
case GSK_TEXTURE_NODE:
if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
pipeline_type = GSK_VULKAN_PIPELINE_BLEND;
@@ -528,7 +581,9 @@ gsk_vulkan_render_pass_upload (GskVulkanRenderPass *self,
case GSK_VULKAN_OP_SURFACE:
{
cairo_surface_t *surface = gsk_cairo_node_get_surface (op->render.node);
cairo_surface_t *surface;
surface = gsk_cairo_node_get_surface (op->render.node);
op->render.source = gsk_vulkan_image_new_from_data (uploader,
cairo_image_surface_get_data (surface),
cairo_image_surface_get_width (surface),
@@ -538,6 +593,17 @@ gsk_vulkan_render_pass_upload (GskVulkanRenderPass *self,
}
break;
case GSK_VULKAN_OP_TEXT:
case GSK_VULKAN_OP_COLOR_TEXT:
{
op->render.source = gsk_vulkan_renderer_ref_glyph_image (GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
uploader,
gsk_text_node_get_font (op->render.node),
gsk_text_node_get_glyphs (op->render.node));
gsk_vulkan_render_add_cleanup_image (render, op->render.source);
}
break;
case GSK_VULKAN_OP_TEXTURE:
{
op->render.source = gsk_vulkan_renderer_ref_texture_image (GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
@@ -619,6 +685,18 @@ gsk_vulkan_render_pass_count_vertex_data (GskVulkanRenderPass *self)
n_bytes += op->render.vertex_count;
break;
case GSK_VULKAN_OP_TEXT:
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;
case GSK_VULKAN_OP_COLOR_TEXT:
op->render.vertex_count = gsk_vulkan_color_text_pipeline_count_vertex_data (GSK_VULKAN_COLOR_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;
case GSK_VULKAN_OP_COLOR:
op->render.vertex_count = gsk_vulkan_color_pipeline_count_vertex_data (GSK_VULKAN_COLOR_PIPELINE (op->render.pipeline));
n_bytes += op->render.vertex_count;
@@ -663,6 +741,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)
@@ -692,6 +771,37 @@ gsk_vulkan_render_pass_collect_vertex_data (GskVulkanRenderPass *self,
}
break;
case GSK_VULKAN_OP_TEXT:
{
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_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;
case GSK_VULKAN_OP_COLOR_TEXT:
{
op->render.vertex_offset = offset + n_bytes;
gsk_vulkan_color_text_pipeline_collect_vertex_data (GSK_VULKAN_COLOR_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_font (op->render.node),
gsk_text_node_get_glyphs (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;
case GSK_VULKAN_OP_COLOR:
{
op->render.vertex_offset = offset + n_bytes;
@@ -834,6 +944,8 @@ gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self,
case GSK_VULKAN_OP_FALLBACK_CLIP:
case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
case GSK_VULKAN_OP_SURFACE:
case GSK_VULKAN_OP_TEXT:
case GSK_VULKAN_OP_COLOR_TEXT:
case GSK_VULKAN_OP_TEXTURE:
case GSK_VULKAN_OP_OPACITY:
case GSK_VULKAN_OP_BLUR:
@@ -910,6 +1022,72 @@ gsk_vulkan_render_pass_draw (GskVulkanRenderPass *self,
current_draw_index, 1);
break;
case GSK_VULKAN_OP_TEXT:
if (current_pipeline != op->render.pipeline)
{
current_pipeline = op->render.pipeline;
vkCmdBindPipeline (command_buffer,
VK_PIPELINE_BIND_POINT_GRAPHICS,
gsk_vulkan_pipeline_get_pipeline (current_pipeline));
vkCmdBindVertexBuffers (command_buffer,
0,
1,
(VkBuffer[1]) {
gsk_vulkan_buffer_get_buffer (vertex_buffer)
},
(VkDeviceSize[1]) { op->render.vertex_offset });
current_draw_index = 0;
}
vkCmdBindDescriptorSets (command_buffer,
VK_PIPELINE_BIND_POINT_GRAPHICS,
gsk_vulkan_pipeline_layout_get_pipeline_layout (layout),
0,
1,
(VkDescriptorSet[1]) {
gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index)
},
0,
NULL);
current_draw_index += gsk_vulkan_text_pipeline_draw (GSK_VULKAN_TEXT_PIPELINE (current_pipeline),
command_buffer,
current_draw_index, pango_glyph_string_num_glyphs (gsk_text_node_get_glyphs (op->render.node)));
break;
case GSK_VULKAN_OP_COLOR_TEXT:
if (current_pipeline != op->render.pipeline)
{
current_pipeline = op->render.pipeline;
vkCmdBindPipeline (command_buffer,
VK_PIPELINE_BIND_POINT_GRAPHICS,
gsk_vulkan_pipeline_get_pipeline (current_pipeline));
vkCmdBindVertexBuffers (command_buffer,
0,
1,
(VkBuffer[1]) {
gsk_vulkan_buffer_get_buffer (vertex_buffer)
},
(VkDeviceSize[1]) { op->render.vertex_offset });
current_draw_index = 0;
}
vkCmdBindDescriptorSets (command_buffer,
VK_PIPELINE_BIND_POINT_GRAPHICS,
gsk_vulkan_pipeline_layout_get_pipeline_layout (layout),
0,
1,
(VkDescriptorSet[1]) {
gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index)
},
0,
NULL);
current_draw_index += gsk_vulkan_color_text_pipeline_draw (GSK_VULKAN_COLOR_TEXT_PIPELINE (current_pipeline),
command_buffer,
current_draw_index, pango_glyph_string_num_glyphs (gsk_text_node_get_glyphs (op->render.node)));
break;
case GSK_VULKAN_OP_OPACITY:
case GSK_VULKAN_OP_COLOR_MATRIX:
if (current_pipeline != op->render.pipeline)

View File

@@ -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);

View File

@@ -34,6 +34,12 @@ typedef enum {
GSK_VULKAN_PIPELINE_BLUR,
GSK_VULKAN_PIPELINE_BLUR_CLIP,
GSK_VULKAN_PIPELINE_BLUR_CLIP_ROUNDED,
GSK_VULKAN_PIPELINE_TEXT,
GSK_VULKAN_PIPELINE_TEXT_CLIP,
GSK_VULKAN_PIPELINE_TEXT_CLIP_ROUNDED,
GSK_VULKAN_PIPELINE_COLOR_TEXT,
GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP,
GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP_ROUNDED,
/* add more */
GSK_VULKAN_N_PIPELINES
} GskVulkanPipelineType;

169
gsk/gskvulkantextpipeline.c Normal file
View File

@@ -0,0 +1,169 @@
#include "config.h"
#include "gskvulkantextpipelineprivate.h"
struct _GskVulkanTextPipeline
{
GObject parent_instance;
};
typedef struct _GskVulkanTextInstance GskVulkanTextInstance;
struct _GskVulkanTextInstance
{
float rect[4];
float tex_rect[4];
float color[4];
};
G_DEFINE_TYPE (GskVulkanTextPipeline, gsk_vulkan_text_pipeline, GSK_TYPE_VULKAN_PIPELINE)
static const VkPipelineVertexInputStateCreateInfo *
gsk_vulkan_text_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
{
static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
{
.binding = 0,
.stride = sizeof (GskVulkanTextInstance),
.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
}
};
static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
{
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanTextInstance, rect),
},
{
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanTextInstance, tex_rect),
},
{
.location = 2,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanTextInstance, color),
}
};
static const VkPipelineVertexInputStateCreateInfo info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
.pVertexBindingDescriptions = vertexBindingDescriptions,
.vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
.pVertexAttributeDescriptions = vertexInputAttributeDescription
};
return &info;
}
static void
gsk_vulkan_text_pipeline_finalize (GObject *gobject)
{
//GskVulkanTextPipeline *self = GSK_VULKAN_TEXT_PIPELINE (gobject);
G_OBJECT_CLASS (gsk_vulkan_text_pipeline_parent_class)->finalize (gobject);
}
static void
gsk_vulkan_text_pipeline_class_init (GskVulkanTextPipelineClass *klass)
{
GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_text_pipeline_finalize;
pipeline_class->get_input_state_create_info = gsk_vulkan_text_pipeline_get_input_state_create_info;
}
static void
gsk_vulkan_text_pipeline_init (GskVulkanTextPipeline *self)
{
}
GskVulkanPipeline *
gsk_vulkan_text_pipeline_new (GskVulkanPipelineLayout *layout,
const char *shader_name,
VkRenderPass render_pass)
{
return gsk_vulkan_pipeline_new_full (GSK_TYPE_VULKAN_TEXT_PIPELINE, layout, shader_name, render_pass,
VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA);
}
gsize
gsk_vulkan_text_pipeline_count_vertex_data (GskVulkanTextPipeline *pipeline,
int num_instances)
{
return sizeof (GskVulkanTextInstance) * num_instances;
}
void
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 *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)
{
vkCmdDraw (command_buffer,
6, n_commands,
0, offset);
return n_commands;
}

View File

@@ -0,0 +1,39 @@
#ifndef __GSK_VULKAN_TEXT_PIPELINE_PRIVATE_H__
#define __GSK_VULKAN_TEXT_PIPELINE_PRIVATE_H__
#include <graphene.h>
#include "gskvulkanpipelineprivate.h"
#include "gskvulkanrendererprivate.h"
G_BEGIN_DECLS
typedef struct _GskVulkanTextPipelineLayout GskVulkanTextPipelineLayout;
#define GSK_TYPE_VULKAN_TEXT_PIPELINE (gsk_vulkan_text_pipeline_get_type ())
G_DECLARE_FINAL_TYPE (GskVulkanTextPipeline, gsk_vulkan_text_pipeline, GSK, VULKAN_TEXT_PIPELINE, GskVulkanPipeline)
GskVulkanPipeline * gsk_vulkan_text_pipeline_new (GskVulkanPipelineLayout * layout,
const char *shader_name,
VkRenderPass render_pass);
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,
PangoFont *font,
PangoGlyphString *glyphs,
const GdkRGBA *color,
float x,
float y);
gsize gsk_vulkan_text_pipeline_draw (GskVulkanTextPipeline *pipeline,
VkCommandBuffer command_buffer,
gsize offset,
gsize n_commands);
G_END_DECLS
#endif /* __GSK_VULKAN_TEXT_PIPELINE_PRIVATE_H__ */

View File

@@ -61,10 +61,12 @@ if have_vulkan
'gskvulkanbuffer.c',
'gskvulkanclip.c',
'gskvulkancolorpipeline.c',
'gskvulkancolortextpipeline.c',
'gskvulkancommandpool.c',
'gskvulkaneffectpipeline.c',
'gskvulkanlineargradientpipeline.c',
'gskvulkanimage.c',
'gskvulkantextpipeline.c',
'gskvulkanmemory.c',
'gskvulkanpipeline.c',
'gskvulkanpushconstants.c',

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,16 @@
#version 420 core
#include "clip.frag.glsl"
layout(location = 0) in vec2 inPos;
layout(location = 1) in vec2 inTexCoord;
layout(location = 2) in vec4 inColor;
layout(set = 0, binding = 0) uniform sampler2D inTexture;
layout(location = 0) out vec4 color;
void main()
{
color = clip (inPos, vec4(inColor.rgb, texture(inTexture, inTexCoord).a));
}

Binary file not shown.

View File

@@ -0,0 +1,38 @@
#version 420 core
#include "clip.vert.glsl"
layout(location = 0) in vec4 inRect;
layout(location = 1) in vec4 inTexRect;
layout(location = 2) in vec4 inColor;
layout(location = 0) out vec2 outPos;
layout(location = 1) out vec2 outTexCoord;
layout(location = 2) out flat vec4 outColor;
out gl_PerVertex {
vec4 gl_Position;
};
vec2 offsets[6] = { vec2(0.0, 0.0),
vec2(1.0, 0.0),
vec2(0.0, 1.0),
vec2(0.0, 1.0),
vec2(1.0, 0.0),
vec2(1.0, 1.0) };
void main() {
vec4 rect = clip (inRect);
vec2 pos = rect.xy + rect.zw * offsets[gl_VertexIndex];
gl_Position = push.mvp * vec4 (pos, 0.0, 1.0);
outPos = pos;
vec4 texrect = vec4((rect.xy - inRect.xy) / inRect.zw,
rect.zw / inRect.zw);
texrect = vec4(inTexRect.xy + inTexRect.zw * texrect.xy,
inTexRect.zw * texrect.zw);
outTexCoord = texrect.xy + texrect.zw * offsets[gl_VertexIndex];
outColor = inColor;
}

Binary file not shown.

View File

@@ -14,6 +14,7 @@ gsk_private_vulkan_fragment_shaders = [
'color-matrix.frag',
'inset-shadow.frag',
'linear.frag',
'mask.frag',
'outset-shadow.frag',
]
@@ -25,6 +26,7 @@ gsk_private_vulkan_vertex_shaders = [
'color-matrix.vert',
'inset-shadow.vert',
'linear.vert',
'mask.vert',
'outset-shadow.vert',
]

View File

@@ -112,8 +112,6 @@ gsk_pango_renderer_show_text_glyphs (PangoRenderer *renderer,
int y)
{
GskPangoRenderer *crenderer = (GskPangoRenderer *) (renderer);
double base_x = (double)x / PANGO_SCALE;
double base_y = (double)y / PANGO_SCALE;
int x_offset, y_offset;
GskRenderNode *node;
GdkRGBA color;
@@ -121,7 +119,7 @@ gsk_pango_renderer_show_text_glyphs (PangoRenderer *renderer,
gtk_snapshot_get_offset (crenderer->snapshot, &x_offset, &y_offset);
get_color (crenderer, PANGO_RENDER_PART_FOREGROUND, &color);
node = gsk_text_node_new (font, glyphs, &color, x_offset, y_offset, base_x, base_y);
node = gsk_text_node_new (font, glyphs, &color, x_offset + (double)x/PANGO_SCALE, y_offset + (double)y/PANGO_SCALE);
if (node == NULL)
return;
@@ -132,12 +130,8 @@ gsk_pango_renderer_show_text_glyphs (PangoRenderer *renderer,
gsk_render_node_set_name (node, name);
}
gtk_snapshot_offset (crenderer->snapshot, base_x, base_y);
gtk_snapshot_append_node (crenderer->snapshot, node);
gsk_render_node_unref (node);
gtk_snapshot_offset (crenderer->snapshot, -base_x, -base_y);
}
static void