From 534d5367dea7203721304d796b2ab2e4d2dbff6c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 20 Nov 2022 03:59:01 +0900 Subject: [PATCH] [vulkan] Use linear sampling for glyphs This requires having padding around the glyphs to avoid texel leak, but as the atlas is created at runtime, it's possible to get the padding in. --- libs/video/renderer/r_font.c | 12 ++++++++--- libs/video/renderer/r_progs.c | 9 ++++++++ libs/video/renderer/vulkan/qfpipeline.plist | 17 +++++++++++++++ libs/video/renderer/vulkan/vulkan_draw.c | 24 +++++++++++---------- 4 files changed, 48 insertions(+), 14 deletions(-) diff --git a/libs/video/renderer/r_font.c b/libs/video/renderer/r_font.c index f667491bd..08131ac74 100644 --- a/libs/video/renderer/r_font.c +++ b/libs/video/renderer/r_font.c @@ -102,7 +102,8 @@ R_FontLoad (QFile *font_file, int size) FT_Load_Glyph (font->face, gind, FT_LOAD_DEFAULT); __auto_type g = font->face->glyph; - pixels += g->bitmap.width * g->bitmap.rows; + // include padding around the glyph to avoid texel leaks + pixels += (g->bitmap.width + 1) * (g->bitmap.rows + 1); } pixels = sqrt (5 * pixels / 4); pixels = BITOP_RUP (pixels); @@ -118,10 +119,15 @@ R_FontLoad (QFile *font_file, int size) FT_Load_Glyph (font->face, gind, FT_LOAD_DEFAULT); __auto_type slot = font->face->glyph; FT_Render_Glyph (slot, FT_RENDER_MODE_NORMAL); - int width = slot->bitmap.width; - int height = slot->bitmap.rows; + // add padding to create a buffer around the glyph to prevent texel + // leaks + int width = slot->bitmap.width + 1; + int height = slot->bitmap.rows + 1; *rect = *R_ScrapAlloc (&font->scrap, width, height); *bearing = (vec2i_t) { slot->bitmap_left, slot->bitmap_top }; + // shrink the rect so as to NOT include the padding + rect->width -= 1; + rect->height -= 1; copy_glyph (rect, slot, font); } diff --git a/libs/video/renderer/r_progs.c b/libs/video/renderer/r_progs.c index 9c00c35f9..054629d7a 100644 --- a/libs/video/renderer/r_progs.c +++ b/libs/video/renderer/r_progs.c @@ -474,6 +474,12 @@ bi_Draw_PrintBuffer (progs_t *pr, void *_res) Draw_PrintBuffer (cbuff->buffer, str); } +static void +bi_Draw_SetScale (progs_t *pr, void *_res) +{ + Draw_SetScale (P_INT (pr, 0)); +} + static const char * bi_draw_get_key (const void *p, void *unused) { @@ -540,6 +546,9 @@ static builtin_t builtins[] = { bi(Draw_ScrollBuffer, 2, p(ptr), p(int)), bi(Draw_CharBuffer, 3, p(int), p(int), p(ptr)), bi(Draw_PrintBuffer, 2, p(ptr), p(string)), + + bi(Draw_SetScale, 1, p(int)), + {0} }; diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 8ae2927d0..4945613c5 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -23,6 +23,23 @@ borderColor = float_transparent_black; unnormalizedCoordinates = false; }; + glyph = { + magFilter = linear; + minFilter = linear; + mipmapMode = linear; + addressModeU = clamp_to_edge; + addressModeV = clamp_to_edge; + addressModeW = clamp_to_edge; + mipLodBias = 0; + anisotropyEnable = false; + maxAnisotropy = 0; + compareEnable = false; + compareOp = always; + minLod = 0; + maxLod = 0; + borderColor = float_transparent_black; + unnormalizedCoordinates = false; + }; palette_sampler = { magFilter = nearest; minFilter = nearest; diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 77e673664..c8f13da03 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -168,7 +168,8 @@ typedef struct drawfontset_s DARRAY_TYPE (drawfont_t) drawfontset_t; typedef struct drawctx_s { - VkSampler sampler; + VkSampler pic_sampler; + VkSampler glyph_sampler; scrap_t *scrap; qfv_stagebuf_t *stage; qpic_t *crosshair; @@ -576,7 +577,8 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) ctx->cmdpool); dctx->scrap = QFV_CreateScrap (device, "draw_atlas", 2048, tex_rgba, dctx->stage); - dctx->sampler = Vulkan_CreateSampler (ctx, "quakepic"); + dctx->pic_sampler = Vulkan_CreateSampler (ctx, "quakepic"); + dctx->glyph_sampler = Vulkan_CreateSampler (ctx, "glyph"); draw_chars = W_GetLumpName ("conchars"); if (draw_chars) { @@ -623,7 +625,7 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) __auto_type pool = Vulkan_CreateDescriptorPool (ctx, "twod_pool"); VkDescriptorImageInfo imageInfo = { - dctx->sampler, + dctx->pic_sampler, QFV_ScrapImageView (dctx->scrap), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, }; @@ -1369,20 +1371,20 @@ Vulkan_Draw_AddFont (rfont_t *rfont, vulkan_ctx_t *ctx) float s = 1.0 / rfont->scrap.width; float t = 1.0 / rfont->scrap.height; verts[i * 4 + 0] = (glyphvert_t) { - .offset = { x + 0, y + 0 }, - .uv = {(u + 0.25) * s, (v + 0.25) * t }, + .offset = { x, y }, + .uv = { u * s, v * t }, }; verts[i * 4 + 1] = (glyphvert_t) { - .offset = { x + 0, y + h }, - .uv = {(u + 0.25) * s, (v + h - 0.25) * t }, + .offset = { x, y + h }, + .uv = { u * s, (v + h) * t }, }; verts[i * 4 + 2] = (glyphvert_t) { - .offset = { x + w, y + 0 }, - .uv = {(u + w - 0.25) * s, (v + 0.25) * t }, + .offset = { x + w, y }, + .uv = {(u + w) * s, v * t }, }; verts[i * 4 + 3] = (glyphvert_t) { .offset = { x + w, y + h }, - .uv = {(u + w - 0.25) * s, (v + h - 0.25) * t }, + .uv = {(u + w) * s, (v + h) * t }, }; } QFV_PacketCopyBuffer (packet, glyph_data->buffer.buffer, @@ -1403,7 +1405,7 @@ Vulkan_Draw_AddFont (rfont_t *rfont, vulkan_ctx_t *ctx) __auto_type glyph_sets = QFV_AllocateDescriptorSet (device, pool, layouts); font->set = glyph_sets->a[0]; VkDescriptorImageInfo imageInfo = { - dctx->sampler, + dctx->glyph_sampler, glyph_iview->image_view.view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, };