diff --git a/gsk/vulkan/gskvulkanglyphcache.c b/gsk/vulkan/gskvulkanglyphcache.c index 1b5b916f11..a86d197e06 100644 --- a/gsk/vulkan/gskvulkanglyphcache.c +++ b/gsk/vulkan/gskvulkanglyphcache.c @@ -3,6 +3,8 @@ #include "gskvulkanglyphcacheprivate.h" #include "gskvulkanimageprivate.h" +#include "gskvulkanuploadopprivate.h" + #include "gskdebugprivate.h" #include "gskprivate.h" #include "gskrendererprivate.h" @@ -29,7 +31,6 @@ typedef struct { int width, height; int x, y, y0; int num_glyphs; - GList *dirty_glyphs; guint old_pixels; } Atlas; @@ -56,7 +57,6 @@ static gboolean glyph_cache_equal (gconstpointer v1, gconstpointer v2); static void glyph_cache_key_free (gpointer v); static void glyph_cache_value_free (gpointer v); -static void dirty_glyph_free (gpointer v); static Atlas * create_atlas (GskVulkanGlyphCache *cache) @@ -71,7 +71,6 @@ create_atlas (GskVulkanGlyphCache *cache) atlas->x = 0; atlas->image = NULL; atlas->num_glyphs = 0; - atlas->dirty_glyphs = NULL; atlas->image = gsk_vulkan_image_new_for_atlas (cache->vulkan, atlas->width, atlas->height); @@ -84,7 +83,6 @@ free_atlas (gpointer v) Atlas *atlas = v; g_clear_object (&atlas->image); - g_list_free_full (atlas->dirty_glyphs, dirty_glyph_free); g_free (atlas); } @@ -159,30 +157,14 @@ glyph_cache_value_free (gpointer v) g_free (v); } -typedef struct { - GlyphCacheKey *key; - GskVulkanCachedGlyph *value; - cairo_surface_t *surface; -} DirtyGlyph; - -static void -dirty_glyph_free (gpointer v) -{ - DirtyGlyph *glyph = v; - - if (glyph->surface) - cairo_surface_destroy (glyph->surface); - g_free (glyph); -} - static void add_to_cache (GskVulkanGlyphCache *cache, + GskVulkanRender *render, GlyphCacheKey *key, GskVulkanCachedGlyph *value) { Atlas *atlas; int i; - DirtyGlyph *dirty; int width = ceil (value->draw_width * key->scale / 1024.0); int height = ceil (value->draw_height * key->scale / 1024.0); int width_with_padding = width + 2 * PADDING; @@ -228,16 +210,28 @@ add_to_cache (GskVulkanGlyphCache *cache, value->tw = (float)width / atlas->width; value->th = (float)height / atlas->height; - dirty = g_new (DirtyGlyph, 1); - dirty->key = key; - dirty->value = value; - atlas->dirty_glyphs = g_list_prepend (atlas->dirty_glyphs, dirty); - atlas->x = atlas->x + width_with_padding; atlas->y = MAX (atlas->y, atlas->y0 + height_with_padding); atlas->num_glyphs++; + gsk_vulkan_upload_glyph_op (render, + atlas->image, + &(cairo_rectangle_int_t) { + .x = value->atlas_x, + .y = value->atlas_y, + .width = width_with_padding, + .height = height_with_padding + }, + key->font, + &(PangoGlyphInfo) { + .glyph = key->glyph, + .geometry.width = value->draw_width * PANGO_SCALE, + .geometry.x_offset = (0.25 * key->xshift - value->draw_x) * PANGO_SCALE, + .geometry.y_offset = (0.25 * key->yshift - value->draw_y) * PANGO_SCALE + }, + (float) key->scale / PANGO_SCALE); + #ifdef G_ENABLE_DEBUG if (GSK_DEBUG_CHECK (GLYPH_CACHE)) { @@ -245,9 +239,9 @@ add_to_cache (GskVulkanGlyphCache *cache, for (i = 0; i < cache->atlases->len; i++) { atlas = g_ptr_array_index (cache->atlases, i); - g_print ("\tAtlas %d (%dx%d): %d glyphs (%d dirty), %.2g%% old pixels, filled to %d, %d / %d\n", + g_print ("\tAtlas %d (%dx%d): %d glyphs, %.2g%% old pixels, filled to %d, %d / %d\n", i, atlas->width, atlas->height, - atlas->num_glyphs, g_list_length (atlas->dirty_glyphs), + atlas->num_glyphs, 100.0 * (double)atlas->old_pixels / (double)(atlas->width * atlas->height), atlas->x, atlas->y0, atlas->y); } @@ -255,82 +249,6 @@ add_to_cache (GskVulkanGlyphCache *cache, #endif } -static void -render_glyph (Atlas *atlas, - DirtyGlyph *glyph, - GskImageRegion *region) -{ - GlyphCacheKey *key = glyph->key; - GskVulkanCachedGlyph *value = glyph->value; - cairo_surface_t *surface; - cairo_t *cr; - PangoGlyphString glyphs; - PangoGlyphInfo gi; - int surface_height; - int surface_width; - - surface_width = ceil (value->draw_width * key->scale / 1024.0) + 2 * PADDING; - surface_height = ceil (value->draw_height * key->scale / 1024.0) + 2 * PADDING; - - surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, surface_width, surface_height); - cairo_surface_set_device_scale (surface, key->scale / 1024.0, key->scale / 1024.0); - - cr = cairo_create (surface); - - /* Make sure the entire surface is initialized to black */ - cairo_set_source_rgba (cr, 0, 0, 0, 0); - cairo_rectangle (cr, 0.0, 0.0, surface_width, surface_width); - cairo_fill (cr); - - /* Draw glyph */ - cairo_set_source_rgba (cr, 1, 1, 1, 1); - - gi.glyph = key->glyph; - gi.geometry.width = value->draw_width * 1024; - gi.geometry.x_offset = (0.25 * key->xshift - value->draw_x) * 1024; - gi.geometry.y_offset = (0.25 * key->yshift - value->draw_y) * 1024; - - glyphs.num_glyphs = 1; - glyphs.glyphs = &gi; - - pango_cairo_show_glyph_string (cr, key->font, &glyphs); - - cairo_destroy (cr); - - glyph->surface = surface; - - region->data = cairo_image_surface_get_data (surface); - region->width = cairo_image_surface_get_width (surface); - region->height = cairo_image_surface_get_height (surface); - region->stride = cairo_image_surface_get_stride (surface); - region->x = value->atlas_x; - region->y = value->atlas_y; -} - -static void -upload_dirty_glyphs (GskVulkanGlyphCache *cache, - Atlas *atlas, - GskVulkanUploader *uploader) -{ - GList *l; - guint num_regions; - GskImageRegion *regions; - int i; - - num_regions = g_list_length (atlas->dirty_glyphs); - regions = alloca (sizeof (GskImageRegion) * num_regions); - - for (l = atlas->dirty_glyphs, i = 0; l; l = l->next, i++) - render_glyph (atlas, (DirtyGlyph *)l->data, ®ions[i]); - - GSK_DEBUG (GLYPH_CACHE, "uploading %d glyphs to cache", num_regions); - - gsk_vulkan_image_upload_regions (atlas->image, uploader, num_regions, regions); - - g_list_free_full (atlas->dirty_glyphs, dirty_glyph_free); - atlas->dirty_glyphs = NULL; -} - GskVulkanGlyphCache * gsk_vulkan_glyph_cache_new (GdkVulkanContext *vulkan) { @@ -347,7 +265,7 @@ gsk_vulkan_glyph_cache_new (GdkVulkanContext *vulkan) GskVulkanCachedGlyph * gsk_vulkan_glyph_cache_lookup (GskVulkanGlyphCache *cache, - gboolean create, + GskVulkanRender *render, PangoFont *font, PangoGlyph glyph, int x, @@ -381,7 +299,7 @@ gsk_vulkan_glyph_cache_lookup (GskVulkanGlyphCache *cache, } } - if (create && value == NULL) + if (value == NULL) { GlyphCacheKey *key; PangoRectangle ink_rect; @@ -410,7 +328,7 @@ gsk_vulkan_glyph_cache_lookup (GskVulkanGlyphCache *cache, key->scale = (guint)(scale * 1024); if (ink_rect.width > 0 && ink_rect.height > 0) - add_to_cache (cache, key, value); + add_to_cache (cache, render, key, value); g_hash_table_insert (cache->hash_table, key, value); } @@ -418,22 +336,6 @@ gsk_vulkan_glyph_cache_lookup (GskVulkanGlyphCache *cache, return value; } -void -gsk_vulkan_glyph_cache_upload (GskVulkanGlyphCache *cache, - GskVulkanUploader *uploader) -{ - Atlas *atlas; - guint i; - - for (i = 0; i < cache->atlases->len; i++) - { - atlas = g_ptr_array_index (cache->atlases, i); - - if (atlas->dirty_glyphs) - upload_dirty_glyphs (cache, atlas, uploader); - } -} - void gsk_vulkan_glyph_cache_begin_frame (GskVulkanGlyphCache *cache) { diff --git a/gsk/vulkan/gskvulkanglyphcacheprivate.h b/gsk/vulkan/gskvulkanglyphcacheprivate.h index 4d845a6295..bd0977e6b1 100644 --- a/gsk/vulkan/gskvulkanglyphcacheprivate.h +++ b/gsk/vulkan/gskvulkanglyphcacheprivate.h @@ -2,6 +2,7 @@ #include #include "gskvulkanimageprivate.h" +#include "gskvulkanprivate.h" G_BEGIN_DECLS @@ -32,11 +33,8 @@ typedef struct GskVulkanGlyphCache *gsk_vulkan_glyph_cache_new (GdkVulkanContext *vulkan); -void gsk_vulkan_glyph_cache_upload (GskVulkanGlyphCache *cache, - GskVulkanUploader *uploader); - GskVulkanCachedGlyph *gsk_vulkan_glyph_cache_lookup (GskVulkanGlyphCache *cache, - gboolean create, + GskVulkanRender *render, PangoFont *font, PangoGlyph glyph, int x, diff --git a/gsk/vulkan/gskvulkanrender.c b/gsk/vulkan/gskvulkanrender.c index 6a9a1bac50..8b412b5470 100644 --- a/gsk/vulkan/gskvulkanrender.c +++ b/gsk/vulkan/gskvulkanrender.c @@ -511,9 +511,6 @@ gsk_vulkan_render_upload (GskVulkanRender *self) { GskVulkanOp *op; - gsk_vulkan_glyph_cache_upload (gsk_vulkan_renderer_get_glyph_cache (GSK_VULKAN_RENDERER (self->renderer)), - self->uploader); - for (op = self->first_op; op; op = op->next) { gsk_vulkan_op_upload (op, self->uploader); diff --git a/gsk/vulkan/gskvulkanrenderer.c b/gsk/vulkan/gskvulkanrenderer.c index 6985e92a66..862e278a5d 100644 --- a/gsk/vulkan/gskvulkanrenderer.c +++ b/gsk/vulkan/gskvulkanrenderer.c @@ -463,17 +463,6 @@ gsk_vulkan_renderer_get_glyph_cache (GskVulkanRenderer *self) return self->glyph_cache; } -GskVulkanCachedGlyph * -gsk_vulkan_renderer_cache_glyph (GskVulkanRenderer *self, - PangoFont *font, - PangoGlyph glyph, - int x, - int y, - float scale) -{ - return gsk_vulkan_glyph_cache_lookup (self->glyph_cache, TRUE, font, glyph, x, y, scale); -} - /** * gsk_vulkan_renderer_new: * diff --git a/gsk/vulkan/gskvulkanrendererprivate.h b/gsk/vulkan/gskvulkanrendererprivate.h index 65809afabd..af4cbccf72 100644 --- a/gsk/vulkan/gskvulkanrendererprivate.h +++ b/gsk/vulkan/gskvulkanrendererprivate.h @@ -12,13 +12,6 @@ void gsk_vulkan_renderer_add_texture_image (GskVulk GdkTexture *texture, GskVulkanImage *image); -GskVulkanCachedGlyph *gsk_vulkan_renderer_cache_glyph (GskVulkanRenderer *renderer, - PangoFont *font, - PangoGlyph glyph, - int x, - int y, - float scale); - GskVulkanGlyphCache * gsk_vulkan_renderer_get_glyph_cache (GskVulkanRenderer *self); diff --git a/gsk/vulkan/gskvulkanrenderpass.c b/gsk/vulkan/gskvulkanrenderpass.c index 6f16a0a950..1c951a604e 100644 --- a/gsk/vulkan/gskvulkanrenderpass.c +++ b/gsk/vulkan/gskvulkanrenderpass.c @@ -1041,7 +1041,7 @@ gsk_vulkan_render_pass_add_text_node (GskVulkanRenderPass *self, GskRenderNode *node) { const PangoGlyphInfo *glyphs; - GskVulkanRenderer *renderer; + GskVulkanGlyphCache *cache; const graphene_point_t *node_offset; const PangoFont *font; guint num_glyphs; @@ -1049,12 +1049,11 @@ gsk_vulkan_render_pass_add_text_node (GskVulkanRenderPass *self, int i; float scale; - renderer = GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)); + cache = gsk_vulkan_renderer_get_glyph_cache (GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render))); num_glyphs = gsk_text_node_get_num_glyphs (node); glyphs = gsk_text_node_get_glyphs (node, NULL); font = gsk_text_node_get_font (node); - scale = MAX (graphene_vec2_get_x (&state->scale), graphene_vec2_get_y (&state->scale)); node_offset = gsk_text_node_get_offset (node); @@ -1065,12 +1064,13 @@ gsk_vulkan_render_pass_add_text_node (GskVulkanRenderPass *self, const PangoGlyphInfo *gi = &glyphs[i]; graphene_rect_t glyph_bounds, glyph_tex_rect; - glyph = gsk_vulkan_renderer_cache_glyph (renderer, - (PangoFont *)font, - gi->glyph, - x_position + gi->geometry.x_offset, - gi->geometry.y_offset, - scale); + glyph = gsk_vulkan_glyph_cache_lookup (cache, + render, + (PangoFont *)font, + gi->glyph, + x_position + gi->geometry.x_offset, + gi->geometry.y_offset, + scale); glyph_bounds = GRAPHENE_RECT_INIT (glyph->draw_x + node_offset->x + (float) (x_position + gi->geometry.x_offset) / PANGO_SCALE, glyph->draw_y + node_offset->y + (float) (gi->geometry.y_offset) / PANGO_SCALE, diff --git a/gsk/vulkan/gskvulkanuploadop.c b/gsk/vulkan/gskvulkanuploadop.c index 908a286a4b..ef6b4ef95b 100644 --- a/gsk/vulkan/gskvulkanuploadop.c +++ b/gsk/vulkan/gskvulkanuploadop.c @@ -408,3 +408,133 @@ gsk_vulkan_upload_cairo_op (GskVulkanRender *render, return self->image; } + +typedef struct _GskVulkanUploadGlyphOp GskVulkanUploadGlyphOp; + +struct _GskVulkanUploadGlyphOp +{ + GskVulkanOp op; + + GskVulkanImage *image; + cairo_rectangle_int_t area; + PangoFont *font; + PangoGlyphInfo glyph_info; + float scale; + + GskVulkanBuffer *buffer; +}; + +static void +gsk_vulkan_upload_glyph_op_finish (GskVulkanOp *op) +{ + GskVulkanUploadGlyphOp *self = (GskVulkanUploadGlyphOp *) op; + + g_object_unref (self->image); + g_object_unref (self->font); + + g_clear_pointer (&self->buffer, gsk_vulkan_buffer_free); +} + +static void +gsk_vulkan_upload_glyph_op_print (GskVulkanOp *op, + GString *string, + guint indent) +{ + GskVulkanUploadGlyphOp *self = (GskVulkanUploadGlyphOp *) op; + + print_indent (string, indent); + g_string_append (string, "upload-glyph "); + print_int_rect (string, &self->area); + g_string_append_printf (string, "glyph %u @ %g ", self->glyph_info.glyph, self->scale); + print_newline (string); +} + +static void +gsk_vulkan_upload_glyph_op_draw (GskVulkanOp *op, + guchar *data, + gsize stride) +{ + GskVulkanUploadGlyphOp *self = (GskVulkanUploadGlyphOp *) op; + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_image_surface_create_for_data (data, + CAIRO_FORMAT_ARGB32, + self->area.width, + self->area.height, + stride); + cairo_surface_set_device_scale (surface, self->scale, self->scale); + + cr = cairo_create (surface); + + /* Make sure the entire surface is initialized to black */ + cairo_set_source_rgba (cr, 0, 0, 0, 0); + cairo_rectangle (cr, 0.0, 0.0, self->area.width, self->area.height); + cairo_fill (cr); + + /* Draw glyph */ + cairo_set_source_rgba (cr, 1, 1, 1, 1); + + pango_cairo_show_glyph_string (cr, + self->font, + &(PangoGlyphString) { + .num_glyphs = 1, + .glyphs = &self->glyph_info + }); + + cairo_destroy (cr); + + cairo_surface_finish (surface); + cairo_surface_destroy (surface); +} + +static GskVulkanOp * +gsk_vulkan_upload_glyph_op_command (GskVulkanOp *op, + GskVulkanRender *render, + VkPipelineLayout pipeline_layout, + VkCommandBuffer command_buffer) +{ + GskVulkanUploadGlyphOp *self = (GskVulkanUploadGlyphOp *) op; + + return gsk_vulkan_upload_op_command_with_area (op, + render, + pipeline_layout, + command_buffer, + self->image, + &self->area, + gsk_vulkan_upload_glyph_op_draw, + &self->buffer); +} + +static const GskVulkanOpClass GSK_VULKAN_UPLOAD_GLYPH_OP_CLASS = { + GSK_VULKAN_OP_SIZE (GskVulkanUploadGlyphOp), + GSK_VULKAN_STAGE_UPLOAD, + NULL, + NULL, + gsk_vulkan_upload_glyph_op_finish, + gsk_vulkan_upload_glyph_op_print, + gsk_vulkan_upload_op_upload, + gsk_vulkan_upload_op_count_vertex_data, + gsk_vulkan_upload_op_collect_vertex_data, + gsk_vulkan_upload_op_reserve_descriptor_sets, + gsk_vulkan_upload_glyph_op_command +}; + +void +gsk_vulkan_upload_glyph_op (GskVulkanRender *render, + GskVulkanImage *image, + cairo_rectangle_int_t *area, + PangoFont *font, + PangoGlyphInfo *glyph_info, + float scale) +{ + GskVulkanUploadGlyphOp *self; + + self = (GskVulkanUploadGlyphOp *) gsk_vulkan_op_alloc (render, &GSK_VULKAN_UPLOAD_GLYPH_OP_CLASS); + + self->image = g_object_ref (image); + self->area = *area; + self->font = g_object_ref (font); + self->glyph_info = *glyph_info; + self->scale = scale; +} diff --git a/gsk/vulkan/gskvulkanuploadopprivate.h b/gsk/vulkan/gskvulkanuploadopprivate.h index dbb1fcfb83..675337e032 100644 --- a/gsk/vulkan/gskvulkanuploadopprivate.h +++ b/gsk/vulkan/gskvulkanuploadopprivate.h @@ -14,6 +14,12 @@ GskVulkanImage * gsk_vulkan_upload_cairo_op (GskVulk const graphene_vec2_t *scale, const graphene_rect_t *viewport); +void gsk_vulkan_upload_glyph_op (GskVulkanRender *render, + GskVulkanImage *image, + cairo_rectangle_int_t *area, + PangoFont *font, + PangoGlyphInfo *glyph_info, + float scale); G_END_DECLS