vulkan: Add an UploadGlyphOp

Now all the uploads have their own op.
This commit is contained in:
Benjamin Otte 2023-07-14 20:55:45 +02:00
parent 68b337d457
commit 93db1cc89e
8 changed files with 172 additions and 157 deletions

View File

@ -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, &regions[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)
{

View File

@ -2,6 +2,7 @@
#include <pango/pango.h>
#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,

View File

@ -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);

View File

@ -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:
*

View File

@ -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);

View File

@ -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,

View File

@ -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;
}

View File

@ -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