summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gsk/gskprivate.c20
-rw-r--r--gsk/gskprivate.h3
-rw-r--r--gsk/gskrendernode.h6
-rw-r--r--gsk/gskrendernodeimpl.c154
-rw-r--r--gsk/gskrendernodeprivate.h6
-rw-r--r--gsk/gskvulkancolortextpipeline.c161
-rw-r--r--gsk/gskvulkancolortextpipelineprivate.h38
-rw-r--r--gsk/gskvulkanpipeline.c21
-rw-r--r--gsk/gskvulkanpipelineprivate.h6
-rw-r--r--gsk/gskvulkanrender.c10
-rw-r--r--gsk/gskvulkanrenderer.c141
-rw-r--r--gsk/gskvulkanrendererprivate.h14
-rw-r--r--gsk/gskvulkanrenderpass.c180
-rw-r--r--gsk/gskvulkanrenderpassprivate.h1
-rw-r--r--gsk/gskvulkanrenderprivate.h6
-rw-r--r--gsk/gskvulkantextpipeline.c173
-rw-r--r--gsk/gskvulkantextpipelineprivate.h39
-rw-r--r--gsk/meson.build2
-rw-r--r--gsk/resources/vulkan/mask-clip-rounded.frag.spvbin0 -> 8508 bytes
-rw-r--r--gsk/resources/vulkan/mask-clip-rounded.vert.spvbin0 -> 5016 bytes
-rw-r--r--gsk/resources/vulkan/mask-clip.frag.spvbin0 -> 1600 bytes
-rw-r--r--gsk/resources/vulkan/mask-clip.vert.spvbin0 -> 5016 bytes
-rw-r--r--gsk/resources/vulkan/mask.frag16
-rw-r--r--gsk/resources/vulkan/mask.frag.spvbin0 -> 1600 bytes
-rw-r--r--gsk/resources/vulkan/mask.vert38
-rw-r--r--gsk/resources/vulkan/mask.vert.spvbin0 -> 3284 bytes
-rw-r--r--gsk/resources/vulkan/meson.build2
-rw-r--r--gtk/gskpango.c8
28 files changed, 954 insertions, 91 deletions
diff --git a/gsk/gskprivate.c b/gsk/gskprivate.c
index 8404b9dbc6..d9e1c3e30f 100644
--- a/gsk/gskprivate.c
+++ b/gsk/gskprivate.c
@@ -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;
+}
+
diff --git a/gsk/gskprivate.h b/gsk/gskprivate.h
index 84539c1557..8584be6960 100644
--- a/gsk/gskprivate.h
+++ b/gsk/gskprivate.h
@@ -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__ */
diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h
index 46f6094ec3..3816e1c58f 100644
--- a/gsk/gskrendernode.h
+++ b/gsk/gskrendernode.h
@@ -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,
diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c
index 6ddbb2b431..a71bea7515 100644
--- a/gsk/gskrendernodeimpl.c
+++ b/gsk/gskrendernodeimpl.c
@@ -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,11 @@ 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;
};
static void
@@ -3830,20 +3826,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 +3839,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)];
- cairo_save (cr);
+ 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_translate (cr, self->x_offset, self->y_offset);
+ cairo_save (cr);
+ 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 +3865,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,11 +3884,10 @@ 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))"
+#define GSK_TEXT_NODE_VARIANT_TYPE "(sdddddda(uiiii))"
static GVariant *
gsk_text_node_serialize (GskRenderNode *node)
@@ -3935,10 +3919,8 @@ gsk_text_node_serialize (GskRenderNode *node)
self->color.green,
self->color.blue,
self->color.alpha,
- self->x_offset,
- self->y_offset,
- self->base_x,
- self->base_y,
+ self->x,
+ self->y,
&builder);
g_free (s);
@@ -3962,18 +3944,15 @@ gsk_text_node_deserialize (GVariant *variant,
int cluster_start;
char *s;
GdkRGBA color;
- int x_offset, y_offset;
- double base_x, base_y;
+ double x, 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);
+ &s, &color.red, &color.green, &color.blue, &color.alpha,
+ &x, &y, &iter);
desc = pango_font_description_from_string (s);
fontmap = pango_cairo_font_map_get_default ();
@@ -3983,16 +3962,17 @@ gsk_text_node_deserialize (GVariant *variant,
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))
+ 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);
+ result = gsk_text_node_new (font, glyphs, &color, x, y); /* FIXME: Avoid copying glyphs */
pango_glyph_string_free (glyphs);
pango_font_description_free (desc);
@@ -4012,31 +3992,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 +4014,68 @@ 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;
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;
diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h
index be29f8725c..4934ea3817 100644
--- a/gsk/gskrendernodeprivate.h
+++ b/gsk/gskrendernodeprivate.h
@@ -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);
diff --git a/gsk/gskvulkancolortextpipeline.c b/gsk/gskvulkancolortextpipeline.c
new file mode 100644
index 0000000000..5e3bafb3d1
--- /dev/null
+++ b/gsk/gskvulkancolortextpipeline.c
@@ -0,0 +1,161 @@
+#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;
+ GskGlyphCoords *coords;
+
+ /* XXX */
+ ink_rect_y = rect->origin.y - y;
+ ink_rect_height = rect->size.height;
+
+ coords = g_new (GskGlyphCoords, glyphs->num_glyphs);
+ gsk_vulkan_renderer_get_glyph_coords (renderer, font, glyphs, coords);
+
+ 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;
+ instance->tex_rect[0] = coords[i].x;
+ instance->tex_rect[1] = coords[i].y;
+ instance->tex_rect[2] = coords[i].width;
+ instance->tex_rect[3] = coords[i].height;
+
+ count++;
+ }
+ }
+ x_position += gi->geometry.width;
+ }
+
+ g_free (coords);
+}
+
+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;
+}
diff --git a/gsk/gskvulkancolortextpipelineprivate.h b/gsk/gskvulkancolortextpipelineprivate.h
new file mode 100644
index 0000000000..b341abde34
--- /dev/null
+++ b/gsk/gskvulkancolortextpipelineprivate.h
@@ -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__ */
diff --git a/gsk/gskvulkanpipeline.c b/gsk/gskvulkanpipeline.c
index 7fff1d2760..71ea27e814 100644
--- a/gsk/gskvulkanpipeline.c
+++ b/gsk/gskvulkanpipeline.c
@@ -68,6 +68,19 @@ gsk_vulkan_pipeline_new (GType pipeline_type,
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
diff --git a/gsk/gskvulkanpipelineprivate.h b/gsk/gskvulkanpipelineprivate.h
index 91ffee8f38..504306a714 100644
--- a/gsk/gskvulkanpipelineprivate.h
+++ b/gsk/gskvulkanpipelineprivate.h
@@ -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);
diff --git a/gsk/gskvulkanrender.c b/gsk/gskvulkanrender.c
index 4da8e48566..63988295b1 100644
--- a/gsk/gskvulkanrender.c
+++ b/gsk/gskvulkanrender.c
@@ -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);
diff --git a/gsk/gskvulkanrenderer.c b/gsk/gskvulkanrenderer.c
index 4ae0f4deee..7ae536f800 100644
--- a/gsk/gskvulkanrenderer.c
+++ b/gsk/gskvulkanrenderer.c
@@ -44,6 +44,8 @@ struct _GskVulkanRenderer
GSList *textures;
+ GHashTable *glyph_cache;
+
#ifdef G_ENABLE_DEBUG
ProfileTimers profile_timers;
#endif
@@ -343,3 +345,142 @@ 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))
+
+static void
+render_text (cairo_t *cr,
+ PangoFont *font,
+ PangoGlyphString *glyphs,
+ 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;
+ count++;
+ }
+ }
+ x_position += gi->geometry.width;
+ }
+
+ cairo_show_glyphs (cr, cairo_glyphs, count);
+
+ if (cairo_glyphs != stack_glyphs)
+ g_free (cairo_glyphs);
+}
+
+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;
+
+ 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, 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);
+
+ return image;
+}
+
+static void
+place_text (PangoFont *font,
+ PangoGlyphString *glyphs,
+ GskGlyphCoords *coords,
+ float x,
+ float y,
+ float width,
+ float height)
+{
+ int i;
+ int x_position = 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;
+
+ if (!(gi->glyph & PANGO_GLYPH_UNKNOWN_FLAG))
+ {
+ coords[i].glyph = gi->glyph;
+ coords[i].x = cx / width;
+ coords[i].y = 0.0;
+ coords[i].width = (float)gi->geometry.width / (PANGO_SCALE * width);
+ coords[i].height = 1.0; // FIXME get actual glyph height
+ }
+ }
+ x_position += gi->geometry.width;
+ }
+}
+
+void
+gsk_vulkan_renderer_get_glyph_coords (GskVulkanRenderer *self,
+ PangoFont *font,
+ PangoGlyphString *glyphs,
+ GskGlyphCoords *coords)
+{
+ PangoRectangle ink_rect;
+
+ pango_glyph_string_extents (glyphs, font, &ink_rect, NULL);
+ pango_extents_to_pixels (&ink_rect, NULL);
+
+ place_text (font, glyphs, coords, 0, - ink_rect.y, ink_rect.x + ink_rect.width, ink_rect.height);
+}
diff --git a/gsk/gskvulkanrendererprivate.h b/gsk/gskvulkanrendererprivate.h
index 5794ba1d53..8e9aefd6f1 100644
--- a/gsk/gskvulkanrendererprivate.h
+++ b/gsk/gskvulkanrendererprivate.h
@@ -25,6 +25,20 @@ GskVulkanImage * gsk_vulkan_renderer_ref_texture_image (GskVulk
GskTexture *texture,
GskVulkanUploader *uploader);
+typedef struct {
+ PangoGlyph glyph;
+ float x, y, width, height;
+} GskGlyphCoords;
+
+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,
+ GskGlyphCoords *coords);
+
G_END_DECLS
#endif /* __GSK_VULKAN_RENDERER_PRIVATE_H__ */
diff --git a/gsk/gskvulkanrenderpass.c b/gsk/gskvulkanrenderpass.c
index f3b2b0cb92..0752b85f05 100644
--- a/gsk/gskvulkanrenderpass.c
+++ b/gsk/gskvulkanrenderpass.c
@@ -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)
diff --git a/gsk/gskvulkanrenderpassprivate.h b/gsk/gskvulkanrenderpassprivate.h
index c7afdb5a21..48a2461246 100644
--- a/gsk/gskvulkanrenderpassprivate.h
+++ b/gsk/gskvulkanrenderpassprivate.h
@@ -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);
diff --git a/gsk/gskvulkanrenderprivate.h b/gsk/gskvulkanrenderprivate.h
index 4c01e82e9a..f372282d25 100644
--- a/gsk/gskvulkanrenderprivate.h
+++ b/gsk/gskvulkanrenderprivate.h
@@ -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;
diff --git a/gsk/gskvulkantextpipeline.c b/gsk/gskvulkantextpipeline.c
new file mode 100644
index 0000000000..430a2310e8
--- /dev/null
+++ b/gsk/gskvulkantextpipeline.c
@@ -0,0 +1,173 @@
+#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;
+ GskGlyphCoords *coords;
+
+ /* XXX */
+ ink_rect_y = rect->origin.y - y;
+ ink_rect_height = rect->size.height;
+
+ coords = g_new (GskGlyphCoords, glyphs->num_glyphs);
+ gsk_vulkan_renderer_get_glyph_coords (renderer, font, glyphs, coords);
+
+ 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;
+ instance->tex_rect[0] = coords[i].x;
+ instance->tex_rect[1] = coords[i].y;
+ instance->tex_rect[2] = coords[i].width;
+ instance->tex_rect[3] = coords[i].height;
+ 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;
+ }
+
+ g_free (coords);
+}
+
+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;
+}
diff --git a/gsk/gskvulkantextpipelineprivate.h b/gsk/gskvulkantextpipelineprivate.h
new file mode 100644
index 0000000000..a41846d57a
--- /dev/null
+++ b/gsk/gskvulkantextpipelineprivate.h
@@ -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__ */
diff --git a/gsk/meson.build b/gsk/meson.build
index 3c1278f12d..635361532f 100644
--- a/gsk/meson.build
+++ b/gsk/meson.build
@@ -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',
diff --git a/gsk/resources/vulkan/mask-clip-rounded.frag.spv b/gsk/resources/vulkan/mask-clip-rounded.frag.spv
new file mode 100644
index 0000000000..0791cb599b
--- /dev/null
+++ b/gsk/resources/vulkan/mask-clip-rounded.frag.spv
Binary files differ
diff --git a/gsk/resources/vulkan/mask-clip-rounded.vert.spv b/gsk/resources/vulkan/mask-clip-rounded.vert.spv
new file mode 100644
index 0000000000..34156b4535
--- /dev/null
+++ b/gsk/resources/vulkan/mask-clip-rounded.vert.spv
Binary files differ
diff --git a/gsk/resources/vulkan/mask-clip.frag.spv b/gsk/resources/vulkan/mask-clip.frag.spv
new file mode 100644
index 0000000000..85fc5f01d5
--- /dev/null
+++ b/gsk/resources/vulkan/mask-clip.frag.spv
Binary files differ
diff --git a/gsk/resources/vulkan/mask-clip.vert.spv b/gsk/resources/vulkan/mask-clip.vert.spv
new file mode 100644
index 0000000000..34156b4535
--- /dev/null
+++ b/gsk/resources/vulkan/mask-clip.vert.spv
Binary files differ
diff --git a/gsk/resources/vulkan/mask.frag b/gsk/resources/vulkan/mask.frag
new file mode 100644
index 0000000000..f713371bc6
--- /dev/null
+++ b/gsk/resources/vulkan/mask.frag
@@ -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));
+}
diff --git a/gsk/resources/vulkan/mask.frag.spv b/gsk/resources/vulkan/mask.frag.spv
new file mode 100644
index 0000000000..85fc5f01d5
--- /dev/null
+++ b/gsk/resources/vulkan/mask.frag.spv
Binary files differ
diff --git a/gsk/resources/vulkan/mask.vert b/gsk/resources/vulkan/mask.vert
new file mode 100644
index 0000000000..f4bd9c18e3
--- /dev/null
+++ b/gsk/resources/vulkan/mask.vert
@@ -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;
+}
diff --git a/gsk/resources/vulkan/mask.vert.spv b/gsk/resources/vulkan/mask.vert.spv
new file mode 100644
index 0000000000..22cd856995
--- /dev/null
+++ b/gsk/resources/vulkan/mask.vert.spv
Binary files differ
diff --git a/gsk/resources/vulkan/meson.build b/gsk/resources/vulkan/meson.build
index b18a298aa8..1007858525 100644
--- a/gsk/resources/vulkan/meson.build
+++ b/gsk/resources/vulkan/meson.build
@@ -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',
]
diff --git a/gtk/gskpango.c b/gtk/gskpango.c
index 698688a26a..ff91d08f1c 100644
--- a/gtk/gskpango.c
+++ b/gtk/gskpango.c
@@ -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