gtk/gsk/gskvulkantextpipeline.c
Matthias Clasen a0bbd14325 gsk: Scale glyphs in the glyph cache
Pass a scale factor when caching glyphs or looking them
up in the cache. The glyphs in the cache are rendered
with subpixel precision determined by the scale. Update
all callers to pass a scale factor according to the window
scale. This lets us render crisp glyphs on hidpi systems.
2017-10-28 13:13:31 -04:00

175 lines
6.0 KiB
C

#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 (GdkVulkanContext *context,
VkPipelineLayout layout,
const char *shader_name,
VkRenderPass render_pass)
{
return gsk_vulkan_pipeline_new_full (GSK_TYPE_VULKAN_TEXT_PIPELINE, context, 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,
guint total_glyphs,
const PangoGlyphInfo *glyphs,
const GdkRGBA *color,
float x,
float y,
guint start_glyph,
guint num_glyphs,
float scale)
{
GskVulkanTextInstance *instances = (GskVulkanTextInstance *) data;
int i;
int count = 0;
int x_position = 0;
for (i = 0; i < start_glyph; i++)
x_position += glyphs[i].geometry.width;
for (; i < total_glyphs && count < num_glyphs; i++)
{
const PangoGlyphInfo *gi = &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];
GskVulkanCachedGlyph *glyph;
glyph = gsk_vulkan_renderer_get_cached_glyph (renderer, font, gi->glyph, scale);
instance->tex_rect[0] = glyph->tx;
instance->tex_rect[1] = glyph->ty;
instance->tex_rect[2] = glyph->tw;
instance->tex_rect[3] = glyph->th;
instance->rect[0] = x + cx + glyph->draw_x;
instance->rect[1] = y + cy + glyph->draw_y;
instance->rect[2] = glyph->draw_width;
instance->rect[3] = glyph->draw_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;
}
}
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;
}