#include "gskvulkanglyphcacheprivate.h"
#include "gskvulkanimageprivate.h"
+#include "gskvulkanuploadopprivate.h"
+
#include "gskdebugprivate.h"
#include "gskprivate.h"
#include "gskrendererprivate.h"
int width, height;
int x, y, y0;
int num_glyphs;
- GList *dirty_glyphs;
guint old_pixels;
} Atlas;
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)
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);
Atlas *atlas = v;
g_clear_object (&atlas->image);
- g_list_free_full (atlas->dirty_glyphs, dirty_glyph_free);
g_free (atlas);
}
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;
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))
{
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);
}
#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)
{
GskVulkanCachedGlyph *
gsk_vulkan_glyph_cache_lookup (GskVulkanGlyphCache *cache,
- gboolean create,
+ GskVulkanRender *render,
PangoFont *font,
PangoGlyph glyph,
int x,
}
}
- if (create && value == NULL)
+ if (value == NULL)
{
GlyphCacheKey *key;
PangoRectangle ink_rect;
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);
}
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)
{
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;
+}