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 (®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; +} + 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 +#include 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 - 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; 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 + +#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 @@ -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 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 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 + +#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 Binary files /dev/null and b/gsk/resources/vulkan/mask-clip-rounded.frag.spv 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 Binary files /dev/null and b/gsk/resources/vulkan/mask-clip-rounded.vert.spv 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 Binary files /dev/null and b/gsk/resources/vulkan/mask-clip.frag.spv 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 Binary files /dev/null and b/gsk/resources/vulkan/mask-clip.vert.spv 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 Binary files /dev/null and b/gsk/resources/vulkan/mask.frag.spv 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 Binary files /dev/null and b/gsk/resources/vulkan/mask.vert.spv 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