glyph cache progress

This commit is contained in:
jacob 2025-12-12 19:50:44 -06:00
parent 5fd73b7911
commit c8a9970438
14 changed files with 1138 additions and 304 deletions

View File

@ -93,12 +93,12 @@ void *PushBytesNoZero(Arena *arena, u64 size, u64 align)
Assert(align > 0); Assert(align > 0);
u8 *base = ArenaFirst(arena, u8); u8 *base = ArenaFirst(arena, u8);
u64 start_pos = AlignU64(arena->pos, align); u64 start_pos = AlignU64(arena->pos, align);
u64 end_pos = start_pos + size; u64 end_pos = start_pos + size;
void *result = base + start_pos;
/* Commit new block(s) */ /* Commit new block(s) */
if (end_pos > arena->committed) if (size > 0 && end_pos > arena->committed)
{ {
u64 blocks_needed = (end_pos - arena->committed + ArenaBlockSize - 1) / ArenaBlockSize; u64 blocks_needed = (end_pos - arena->committed + ArenaBlockSize - 1) / ArenaBlockSize;
u64 commit_bytes = blocks_needed * ArenaBlockSize; u64 commit_bytes = blocks_needed * ArenaBlockSize;
@ -119,8 +119,7 @@ void *PushBytesNoZero(Arena *arena, u64 size, u64 align)
AsanPoison(commit_address, commit_bytes); AsanPoison(commit_address, commit_bytes);
} }
void *result = base + start_pos; AsanUnpoison(result, size);
AsanUnpoison(result, end_pos - start_pos);
arena->pos = end_pos; arena->pos = end_pos;
return result; return result;

View File

@ -10,10 +10,10 @@
# include "base_arena.h" # include "base_arena.h"
# include "base_futex.h" # include "base_futex.h"
# include "base_sync.h" # include "base_sync.h"
# include "base_wave.h"
# include "base_time.h" # include "base_time.h"
# include "base_uid.h" # include "base_uid.h"
# include "base_math.h" # include "base_math.h"
# include "base_wave.h"
# include "base_string.h" # include "base_string.h"
# include "base_cmdline.h" # include "base_cmdline.h"
# include "base_log.h" # include "base_log.h"
@ -36,13 +36,13 @@
# include "base_memory.c" # include "base_memory.c"
# include "base_arena.c" # include "base_arena.c"
# include "base_sync.c" # include "base_sync.c"
# include "base_wave.c"
# include "base_uid.c" # include "base_uid.c"
# include "base_string.c" # include "base_string.c"
# include "base_cmdline.c" # include "base_cmdline.c"
# include "base_uni.c" # include "base_uni.c"
# include "base_buddy.c" # include "base_buddy.c"
# include "base_math.c" # include "base_math.c"
# include "base_wave.c"
# include "base_rand.c" # include "base_rand.c"
# include "base_bitbuff.c" # include "base_bitbuff.c"
# include "base_resource.c" # include "base_resource.c"

View File

@ -1125,6 +1125,16 @@ Vec2I32 SubVec2I32(Vec2I32 a, Vec2I32 b)
return VEC2I32(a.x - b.x, a.y - b.y); return VEC2I32(a.x - b.x, a.y - b.y);
} }
Vec2I32 MulVec2I32Vec2I32(Vec2I32 a, Vec2I32 b)
{
return VEC2I32(a.x * b.x, a.y * b.y);
}
Vec2I32 DivVec2I32Vec2I32(Vec2I32 a, Vec2I32 b)
{
return VEC2I32(a.x / b.x, a.y / b.y);
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Vec4 //~ Vec4
@ -1151,6 +1161,8 @@ u32 U32FromVec4(Vec4 v)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Range //~ Range
//- Rng2
Vec2 DimsFromRng2(Rng2 r) Vec2 DimsFromRng2(Rng2 r)
{ {
Vec2 result = ZI; Vec2 result = ZI;
@ -1185,6 +1197,43 @@ Rng2 DivRng2Vec2(Rng2 r, Vec2 v)
return result; return result;
} }
//- Rng2I32
Vec2I32 DimsFromRng2I32(Rng2I32 r)
{
Vec2I32 result = ZI;
result.x = r.p1.x - r.p0.x;
result.y = r.p1.y - r.p0.y;
return result;
}
Rng2I32 UnionRng2I32(Rng2I32 a, Rng2I32 b)
{
Rng2I32 result = ZI;
result.p0.x = MinF32(a.p0.x, b.p0.x);
result.p0.y = MinF32(a.p0.y, b.p0.y);
result.p1.x = MaxF32(a.p1.x, b.p1.x);
result.p1.y = MaxF32(a.p1.y, b.p1.y);
return result;
}
Rng2I32 AddRng2I32Vec2I32(Rng2I32 r, Vec2I32 v)
{
Rng2I32 result = ZI;
result.p0 = AddVec2I32(result.p0, v);
result.p1 = AddVec2I32(result.p1, v);
return result;
}
Rng2I32 DivRng2I32Vec2I32(Rng2I32 r, Vec2I32 v)
{
Rng2I32 result = ZI;
result.p0 = DivVec2I32Vec2I32(result.p0, v);
result.p1 = DivVec2I32Vec2I32(result.p1, v);
return result;
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Xform //~ Xform

View File

@ -388,12 +388,18 @@ u32 U32FromVec4(Vec4 v);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Range //~ Range
//- Rng2
Vec2 DimsFromRng2(Rng2 r); Vec2 DimsFromRng2(Rng2 r);
Rng2 UnionRng2(Rng2 a, Rng2 b); Rng2 UnionRng2(Rng2 a, Rng2 b);
Rng2 AddRng2Vec2(Rng2 r, Vec2 v); Rng2 AddRng2Vec2(Rng2 r, Vec2 v);
Rng2 DivRng2Vec2(Rng2 a, Vec2 v); Rng2 DivRng2Vec2(Rng2 a, Vec2 v);
//- Rng2I32
Vec2I32 DimsFromRng2I32(Rng2I32 r);
Rng2I32 UnionRng2I32(Rng2I32 a, Rng2I32 b);
Rng2I32 AddRng2I32Vec2I32(Rng2I32 r, Vec2I32 v);
Rng2I32 DivRng2I32Vec2I32(Rng2I32 a, Vec2I32 v);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Xform //~ Xform

View File

@ -108,10 +108,34 @@ void SetWaveLaneDefaultSpin(WaveLaneCtx *lane, u64 n)
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Wave task helpers //~ Task helpers
i32 WaveLaneIdxFromTaskIdx(WaveLaneCtx *lane, u64 task_idx) i32 WaveLaneIdxFromTaskIdx(WaveLaneCtx *lane, u64 task_idx)
{ {
WaveCtx *wave = lane->wave; WaveCtx *wave = lane->wave;
return task_idx % wave->lanes_count; return task_idx % wave->lanes_count;
} }
RngU64 WaveIdxRangeFromCount(WaveLaneCtx *lane, u64 tasks_count)
{
u64 lanes_count = lane->wave->lanes_count;
u64 lane_idx = lane->idx;
u64 tasks_per_lane = tasks_count / lanes_count;
u64 tasks_overflow = tasks_count % lanes_count;
u64 start = lane_idx * tasks_per_lane;
u64 end = start + tasks_per_lane;
if (lane_idx < tasks_overflow)
{
start += lane_idx;
end += lane_idx + 1;
}
else
{
start += tasks_overflow;
end += tasks_overflow;
}
return RNGU64(start, end);
}

View File

@ -46,9 +46,10 @@ void WaveSyncBroadcastEx_(WaveLaneCtx *lane, u32 broadcast_lane_idx, void *broad
void SetWaveLaneDefaultSpin(WaveLaneCtx *lane, u64 n); void SetWaveLaneDefaultSpin(WaveLaneCtx *lane, u64 n);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Wave task helpers //~ Task helpers
i32 WaveLaneIdxFromTaskIdx(WaveLaneCtx *lane, u64 task_idx); i32 WaveLaneIdxFromTaskIdx(WaveLaneCtx *lane, u64 task_idx);
RngU64 WaveIdxRangeFromCount(WaveLaneCtx *lane, u64 tasks_count);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ @hookdecl Dispatch //~ @hookdecl Dispatch

View File

@ -69,8 +69,8 @@
#define FLOOD_DEBUG 0 #define FLOOD_DEBUG 0
#define GPU_DEBUG 0 #define GPU_DEBUG 1
#define GPU_DEBUG_VALIDATION 0 #define GPU_DEBUG_VALIDATION 1
#define GPU_SHADER_PRINT 1 #define GPU_SHADER_PRINT 1
#define GPU_SHADER_PRINT_BUFFER_SIZE Kibi(64); #define GPU_SHADER_PRINT_BUFFER_SIZE Kibi(64);

View File

@ -14,13 +14,14 @@ void GC_Bootstrap(void)
GC_FontKey GC_FontKeyFromResource(ResourceKey resource) GC_FontKey GC_FontKeyFromResource(ResourceKey resource)
{ {
GC_FontKey result = ZI; GC_FontKey result = ZI;
result.v = resource.v; result.r = resource;
return result; return result;
} }
u64 GC_HashFromGlyphDesc(GC_GlyphDesc desc) u64 GC_HashFromGlyphDesc(GC_GlyphDesc desc)
{ {
return RandU64FromSeeds(desc.font.v, ((u64)desc.codepoint << 32) | *(u32 *)&desc.font_size); /* TODO: Lower font-size precision to prevent unique hashes for slightly-different font sizes */
return RandU64FromSeeds(desc.font.r.v, ((u64)desc.codepoint << 32) | *(u32 *)&desc.font_size);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -31,21 +32,33 @@ GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size
{ {
GC_Run result = ZI; GC_Run result = ZI;
TempArena scratch = BeginScratch(arena); TempArena scratch = BeginScratch(arena);
Arena *perm = PermArena();
String32 codepoints = String32FromString(scratch.arena, str); u64 codepoints_count = 0;
u32 *codepoints = 0;
{
String32 str32 = String32FromString(scratch.arena, str);
codepoints_count = str32.len;
codepoints = str32.text;
}
String32 uncached_codepoints = ZI; //////////////////////////////
uncached_codepoints.text = PushStructsNoZero(scratch.arena, u32, codepoints.len); //- Grab glyphs from cache
u64 ready_glyphs_count = 0; u64 ready_glyphs_count = 0;
GC_Glyph **ready_glyphs = PushStructsNoZero(scratch.arena, GC_Glyph *, str.len); GC_Glyph **ready_glyphs = PushStructsNoZero(scratch.arena, GC_Glyph *, codepoints_count);
u32 *uncached_codepoints = PushStructsNoZero(scratch.arena, u32, codepoints_count);
u64 uncached_codepoints_count = 0;
u64 pending_glyphs_count = 0;
{ {
if (codepoints.len > 0) if (codepoints_count > 0)
{ {
Lock lock = LockS(&GC.glyphs_mutex); Lock lock = LockS(&GC.glyphs_mutex);
for (u64 codepoint_idx = 0; codepoint_idx < codepoints.len; ++codepoint_idx) for (u64 codepoint_idx = 0; codepoint_idx < codepoints_count; ++codepoint_idx)
{ {
u32 codepoint = codepoints.text[codepoint_idx]; u32 codepoint = codepoints[codepoint_idx];
GC_GlyphDesc desc = ZI; GC_GlyphDesc desc = ZI;
desc.font = font; desc.font = font;
@ -54,20 +67,20 @@ GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size
u64 hash = GC_HashFromGlyphDesc(desc); u64 hash = GC_HashFromGlyphDesc(desc);
GC_GlyphBin *bin = &GC.glyph_bins[hash % countof(GC.glyph_bins)]; GC_GlyphBin *bin = &GC.glyph_bins[hash % countof(GC.glyph_bins)];
GC_Glyph *glyph = bin->first; GC_Glyph *glyph = bin->first;
for (; glyph; glyph = glyph->next) for (; glyph; glyph = glyph->next)
{ {
if (glyph->hash == hash) if (glyph->hash == hash) break;
{
break;
}
} }
if (glyph == 0) if (glyph == 0)
{ {
uncached_codepoints.text[uncached_codepoints.len] = codepoint; uncached_codepoints[uncached_codepoints_count] = codepoint;
uncached_codepoints.len += 1; uncached_codepoints_count += 1;
}
else if (Atomic32Fetch(&glyph->ready) == 0)
{
pending_glyphs_count += 1;
} }
else else
{ {
@ -79,10 +92,77 @@ GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size
} }
} }
if (uncached_codepoints.len > 0) //////////////////////////////
//- Create cache entries
u64 submit_cmds_count = 0;
GC_Cmd *submit_cmds = PushStructsNoZero(scratch.arena, GC_Cmd, uncached_codepoints_count);
if (uncached_codepoints_count > 0)
{ {
Lock lock = LockE(&GC.glyphs_mutex);
{
for (u64 uncached_codepoint_idx = 0; uncached_codepoint_idx < uncached_codepoints_count; ++uncached_codepoint_idx)
{
GC_GlyphDesc desc = ZI;
desc.font = font;
desc.font_size = font_size;
desc.codepoint = uncached_codepoints[uncached_codepoint_idx];
u64 hash = GC_HashFromGlyphDesc(desc);
GC_GlyphBin *bin = &GC.glyph_bins[hash % countof(GC.glyph_bins)];
GC_Glyph *glyph = bin->first;
for (; glyph; glyph = glyph->next)
{
if (glyph->hash == hash) break;
} }
if (glyph == 0)
{
glyph = PushStruct(perm, GC_Glyph);
glyph->desc = desc;
glyph->hash = hash;
SllStackPush(bin->first, glyph);
/* Create cmd */
{
GC_Cmd *cmd = &submit_cmds[submit_cmds_count];
cmd->glyph = glyph;
++submit_cmds_count;
}
}
}
}
Unlock(&lock);
}
//////////////////////////////
//- Submit cmds
if (submit_cmds_count > 0)
{
Lock lock = LockE(&GC.submit.mutex);
for (u64 cmd_idx = 0; cmd_idx < submit_cmds_count; ++cmd_idx)
{
GC_Cmd *src = &submit_cmds[cmd_idx];
GC_CmdNode *n = GC.submit.first_free;
if (n)
{
SllStackPop(GC.submit.first_free);
ZeroStruct(n);
}
else
{
n = PushStruct(perm, GC_CmdNode);
}
n->cmd = *src;
GC.submit.count += 1;
SllQueuePush(GC.submit.first, GC.submit.last, n);
}
Unlock(&lock);
}
//////////////////////////////
//- Create run from glyphs
f32 baseline_pos = 0; f32 baseline_pos = 0;
result.rects = PushStructs(arena, GC_RunRect, ready_glyphs_count); result.rects = PushStructs(arena, GC_RunRect, ready_glyphs_count);
result.rects_count = ready_glyphs_count; result.rects_count = ready_glyphs_count;
@ -98,8 +178,7 @@ GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size
rect->baseline_pos = baseline_pos; rect->baseline_pos = baseline_pos;
rect->advance = glyph->advance; rect->advance = glyph->advance;
rect->bounds.p0 = glyph->baseline_offset; rect->bounds = glyph->bounds;
rect->bounds.p1 = AddVec2(rect->bounds.p0, DimsFromRng2(glyph->tex_rect));
if (glyph_idx == 0) if (glyph_idx == 0)
{ {
@ -123,7 +202,7 @@ GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size
result.font_cap = glyph->font_cap; result.font_cap = glyph->font_cap;
} }
result.ready = uncached_codepoints.len == 0; result.ready = uncached_codepoints_count == 0 && pending_glyphs_count;
EndScratch(scratch); EndScratch(scratch);
return result; return result;
@ -137,21 +216,154 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
GC_AsyncCtx *async = &GC.async_ctx; GC_AsyncCtx *async = &GC.async_ctx;
////////////////////////////// //////////////////////////////
//- Begin tick //- Collect cmds
/* TODO: Limit cmds processed per-tick */
if (lane->idx == 0) if (lane->idx == 0)
{ {
Lock lock = LockE(&GC.submitted_cmds_mutex); Lock lock = LockE(&GC.submit.mutex);
{ {
async->cmds.count = GC.submitted_cmds_count; /* Pop cmds from submission queue */
async->cmds.v = PushStructsNoZero(tick->arena, GC_Cmd, GC.submitted_cmds_count); async->cmds.count = GC.submit.count;
async->cmds.v = PushStructsNoZero(tick->arena, GC_Cmd, GC.submit.count);
u64 cmd_idx = 0;
for (GC_CmdNode *n = GC.submit.first; n; n = n->next)
{
async->cmds.v[cmd_idx] = n->cmd;
++cmd_idx;
}
/* Reset submission queue */
GC.submit.first_free = GC.submit.first;
GC.submit.count = 0;
GC.submit.first = 0;
GC.submit.last = 0;
} }
Unlock(&lock); Unlock(&lock);
} }
WaveSync(lane); WaveSync(lane);
//////////////////////////////
//- Allocate atlas rects
if (lane->idx == 0)
{
/* TODO: Remove this */
/* Create atlas */
Vec2I32 atlas_size = VEC2I32(8192, 8192);
if (G_IsResourceNil(GC.atlas))
{
G_ArenaHandle gpu_arena = G_PermArena();
GC.atlas = G_PushTexture2D(
gpu_arena,
G_Format_R8G8B8A8_Unorm_Srgb,
atlas_size,
/* FIXME: We may need simultaneous access? */
G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present,
);
}
for (u64 cmd_idx = 0; cmd_idx < async->cmds.count; ++cmd_idx)
{
GC_Cmd *cmd = &async->cmds.v[cmd_idx];
GC_Glyph *glyph = cmd->glyph;
ResourceKey resource = glyph->desc.font.r;
String resource_data = DataFromResource(resource);
String resource_name = NameFromResource(resource);
GC_GlyphDesc desc = glyph->desc;
TTF_GlyphDesc ttf_desc = TTF_GlyphDescFromCodepoint(desc.codepoint, resource, desc.font_size);
glyph->font_size = ttf_desc.font_size;
glyph->font_ascent = ttf_desc.font_ascent;
glyph->font_descent = ttf_desc.font_descent;
glyph->font_cap = ttf_desc.font_cap;
glyph->advance = ttf_desc.advance;
glyph->bounds = ttf_desc.bounds;
Vec2 dims = DimsFromRng2(glyph->bounds);
Vec2I32 atlas_offset = GC.atlas_pos;
GC.atlas_row_height = MaxI32(GC.atlas_row_height, dims.y);
if (atlas_offset.x + dims.x > atlas_size.x);
{
GC.atlas_pos.x = 0;
GC.atlas_pos.y += GC.atlas_row_height;
GC.atlas_row_height = dims.y;
}
GC.atlas_pos.x += dims.x;
Rng2I32 src_slice = ZI;
src_slice.p0.x = 0;
src_slice.p0.y = 0;
src_slice.p1.x = RoundF32ToI32(dims.x);
src_slice.p1.y = RoundF32ToI32(dims.y);
Vec2I32 src_dims = DimsFromRng2I32(src_slice);
if (src_dims.x > 0 && src_dims.y > 0)
{
u64 src_pixels_count = src_dims.x * src_dims.y;
u32 *src_pixels = PushStructsNoZero(tick->arena, u32, src_pixels_count);
TTF_RasterizeGlyph(src_pixels, src_dims, src_slice, ttf_desc);
DEBUGBREAKABLE;
// G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_AsyncCopy);
G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_Direct);
{
G_CopyCpuToTexture(
cl,
GC.atlas, VEC3I32(atlas_offset.x, atlas_offset.y, 0),
src_pixels, VEC3I32(src_dims.x, src_dims.y, 0),
RNG3I32(
VEC3I32(src_slice.p0.x, src_slice.p0.y, 0),
VEC3I32(src_slice.p1.x, src_slice.p1.y, 1)
)
);
}
G_CommitCommandList(cl);
G_SyncCpu(G_QueueMask_All);
}
Atomic32Set(&glyph->ready, 1);
// ResourceKey resource = desc.font.r;
// String resource_data = DataFromResource(resource);
}
}
WaveSync(lane);
//////////////////////////////
//- Process cmds
/* TODO: Process cmds unevenly to account for varying work size */
// if (async->cmds.count > 0)
// {
// RngU64 cmd_idxs = WaveIdxRangeFromCount(lane, async->cmds.count);
// for (u64 cmd_idx = cmd_idxs.min; cmd_idx < cmd_idxs.max; ++cmd_idx)
// {
// GC_Cmd *cmd = &async->cmds.v[cmd_idx];
// GC_Glyph *glyph = cmd->glyph;
// GC_GlyphDesc desc = glyph->desc;
// ResourceKey resource = desc.font.r;
// String resource_data = DataFromResource(resource);
// }
// }
//////////////////////////////
//- End tick
WaveSync(lane);
} }

View File

@ -3,38 +3,12 @@
Struct(GC_FontKey) Struct(GC_FontKey)
{ {
u64 v; ResourceKey r;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Glyph types //~ Glyph types
Struct(GC_Glyph)
{
GC_Glyph *next;
u64 hash;
/* Layout info */
Vec2 baseline_offset;
f32 advance;
/* Atlas info */
G_Texture2DRef tex_ref;
Rng2 tex_uv;
Rng2 tex_rect;
/* Font info */
f32 font_size;
f32 font_ascent;
f32 font_descent;
f32 font_cap;
};
Struct(GC_GlyphBin)
{
GC_Glyph *first;
};
Struct(GC_GlyphDesc) Struct(GC_GlyphDesc)
{ {
GC_FontKey font; GC_FontKey font;
@ -42,6 +16,36 @@ Struct(GC_GlyphDesc)
u32 codepoint; u32 codepoint;
}; };
Struct(GC_Glyph)
{
GC_Glyph *next;
GC_GlyphDesc desc;
u64 hash;
Atomic32 ready;
/* Font info */
f32 font_size;
f32 font_ascent;
f32 font_descent;
f32 font_cap;
/* Layout info */
f32 advance;
Rng2 bounds; /* Bounds relative to baseline position */
/* Atlas info */
G_Texture2DRef tex_ref;
Rng2 tex_uv;
Rng2 tex_rect;
};
Struct(GC_GlyphBin)
{
GC_Glyph *first;
};
// Struct(GC_GlyphDescChunk) // Struct(GC_GlyphDescChunk)
// { // {
// GC_GlyphDescChunk *next; // GC_GlyphDescChunk *next;
@ -94,12 +98,10 @@ Struct(GC_Cmd)
GC_Glyph *glyph; GC_Glyph *glyph;
}; };
Struct(GC_CmdChunk) Struct(GC_CmdNode)
{ {
GC_CmdChunk *next; GC_CmdNode *next;
GC_Cmd cmd;
u64 cmds_count;
GC_Cmd *cmds;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -119,13 +121,25 @@ Struct(GC_Ctx)
Mutex glyphs_mutex; Mutex glyphs_mutex;
GC_GlyphBin glyph_bins[16384]; GC_GlyphBin glyph_bins[16384];
Mutex submitted_cmds_mutex; /* TODO: Dynamic atlases */
u64 submitted_cmds_count; G_ResourceHandle atlas;
GC_CmdChunk *first_submitted_cmd_chunk; G_Texture2DRef atlas_ref;
GC_CmdChunk *last_submitted_cmd_chunk; Vec2I32 atlas_pos;
i32 atlas_row_height;
struct
{
Mutex mutex;
u64 count;
GC_CmdNode *first;
GC_CmdNode *last;
GC_CmdNode *first_free;
} submit;
GC_AsyncCtx async_ctx; GC_AsyncCtx async_ctx;
} extern GC; };
extern GC_Ctx GC;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Bootstrap //~ Bootstrap

View File

@ -249,7 +249,7 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
/* TODO: Don't rely on ui report for draw size since it introduces one frame of delay when resizing */ /* TODO: Don't rely on ui report for draw size since it introduces one frame of delay when resizing */
UI_Report vis_rep = UI_ReportFromKey(vis_box); UI_Report vis_rep = UI_ReportFromKey(vis_box);
draw_size = Vec2I32FromVec(DimsFromRng2(vis_rep.screen_rect)); draw_size = RoundVec2ToVec2I32(DimsFromRng2(vis_rep.screen_rect));
} }
draw_size.x = MaxI32(draw_size.x, 1); draw_size.x = MaxI32(draw_size.x, 1);
draw_size.y = MaxI32(draw_size.y, 1); draw_size.y = MaxI32(draw_size.y, 1);

View File

@ -1,27 +1,27 @@
Struct(TTF_Glyph) ////////////////////////////////////////////////////////////
//~ Glyph types
Struct(TTF_GlyphDesc)
{ {
i32 advance; ResourceKey ttf;
Vec2 baseline_offset; u32 codepoint;
Vec2I32 atlas_p0;
Vec2I32 atlas_p1; f32 advance; /* How far to advance the baseline position */
Rng2 bounds; /* Bounds relative to baseline position */
f32 font_size;
f32 font_ascent;
f32 font_descent;
f32 font_cap;
}; };
Struct(TTF_Decoded) ////////////////////////////////////////////////////////////
{ //~ Bootstrap
TTF_Glyph *glyphs;
u16 glyphs_count;
u16 *cache_indices; /* Array of indices into the `glyphs` array in order of `cache_chars` */
u32 image_width;
u32 image_height;
u32 *image_pixels; /* Array of [width * height] pixels */
/* Metrics */
f32 ascent;
f32 descent;
f32 cap;
};
void TTF_Bootstrap(void); void TTF_Bootstrap(void);
TTF_Decoded TTF_Decode(Arena *arena, String encoded, f32 em_size, u32 *cache_codes, u32 cache_codes_count); ////////////////////////////////////////////////////////////
//~ Decode
TTF_GlyphDesc TTF_GlyphDescFromCodepoint(u32 codepoint, ResourceKey ttf, f32 font_size);
void TTF_RasterizeGlyph(u32 *dst, Vec2I32 dst_size, Rng2I32 dst_slice, TTF_GlyphDesc glyph_desc);

File diff suppressed because it is too large Load Diff

View File

@ -140,12 +140,14 @@ static inline UINT32 IDWriteGdiInterop_Release
EXTERN_C HRESULT DECLSPEC_IMPORT WINAPI DWriteCreateFactory (DWRITE_FACTORY_TYPE factoryType, const GUID* iid, void** factory) WIN_NOEXCEPT; EXTERN_C HRESULT DECLSPEC_IMPORT WINAPI DWriteCreateFactory (DWRITE_FACTORY_TYPE factoryType, const GUID* iid, void** factory) WIN_NOEXCEPT;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ State types //~ Context types
/* TODO: Determine font dpi dynamically */ /* TODO: Determine font dpi dynamically */
#define TTF_DW_Dpi (96.0f) #define TTF_DW_Dpi (96.0f)
Struct(TTF_DW_SharedState) Struct(TTF_DW_Ctx)
{ {
struct IDWriteFactory5 *factory; IDWriteFactory5 *factory;
} extern TTF_DW_shared_state; };
extern TTF_DW_Ctx TTF_DW;