forked from AuroraMiddleware/gtk
More work on text nodes
This commit takes several steps towards rendering text like we want to. The creation of the cairo surface and texture is moved to the backend (in GskVulkanRenderer). We add a mask shader that is used in the next text pipeline to use the texture as a mask, like cairo_mask_surface does. There is a separate color text pipeline that uses the already existing blend shaders to use the texture as a source, like cairo_paint does. The text node api is simplified to have just a single offset, which determines the left end of the text baseline, like all our other text drawing APIs.
This commit is contained in:
parent
edc73e78b8
commit
b0e8d8483d
@ -15,3 +15,23 @@ gsk_ensure_resources (void)
|
||||
|
||||
g_once (®ister_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;
|
||||
}
|
||||
|
||||
|
@ -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__ */
|
||||
|
@ -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,
|
||||
|
@ -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)];
|
||||
|
||||
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 +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;
|
||||
|
@ -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);
|
||||
|
161
gsk/gskvulkancolortextpipeline.c
Normal file
161
gsk/gskvulkancolortextpipeline.c
Normal file
@ -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;
|
||||
}
|
38
gsk/gskvulkancolortextpipelineprivate.h
Normal file
38
gsk/gskvulkancolortextpipelineprivate.h
Normal 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__ */
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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__ */
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
173
gsk/gskvulkantextpipeline.c
Normal file
173
gsk/gskvulkantextpipeline.c
Normal file
@ -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;
|
||||
}
|
39
gsk/gskvulkantextpipelineprivate.h
Normal file
39
gsk/gskvulkantextpipelineprivate.h
Normal 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__ */
|
@ -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',
|
||||
|
BIN
gsk/resources/vulkan/mask-clip-rounded.frag.spv
Normal file
BIN
gsk/resources/vulkan/mask-clip-rounded.frag.spv
Normal file
Binary file not shown.
BIN
gsk/resources/vulkan/mask-clip-rounded.vert.spv
Normal file
BIN
gsk/resources/vulkan/mask-clip-rounded.vert.spv
Normal file
Binary file not shown.
BIN
gsk/resources/vulkan/mask-clip.frag.spv
Normal file
BIN
gsk/resources/vulkan/mask-clip.frag.spv
Normal file
Binary file not shown.
BIN
gsk/resources/vulkan/mask-clip.vert.spv
Normal file
BIN
gsk/resources/vulkan/mask-clip.vert.spv
Normal file
Binary file not shown.
16
gsk/resources/vulkan/mask.frag
Normal file
16
gsk/resources/vulkan/mask.frag
Normal 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));
|
||||
}
|
BIN
gsk/resources/vulkan/mask.frag.spv
Normal file
BIN
gsk/resources/vulkan/mask.frag.spv
Normal file
Binary file not shown.
38
gsk/resources/vulkan/mask.vert
Normal file
38
gsk/resources/vulkan/mask.vert
Normal 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;
|
||||
}
|
BIN
gsk/resources/vulkan/mask.vert.spv
Normal file
BIN
gsk/resources/vulkan/mask.vert.spv
Normal file
Binary file not shown.
@ -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',
|
||||
]
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user