glyph cache progress
This commit is contained in:
parent
5fd73b7911
commit
c8a9970438
@ -93,12 +93,12 @@ void *PushBytesNoZero(Arena *arena, u64 size, u64 align)
|
||||
Assert(align > 0);
|
||||
|
||||
u8 *base = ArenaFirst(arena, u8);
|
||||
|
||||
u64 start_pos = AlignU64(arena->pos, align);
|
||||
u64 end_pos = start_pos + size;
|
||||
void *result = base + start_pos;
|
||||
|
||||
/* 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 commit_bytes = blocks_needed * ArenaBlockSize;
|
||||
@ -119,8 +119,7 @@ void *PushBytesNoZero(Arena *arena, u64 size, u64 align)
|
||||
AsanPoison(commit_address, commit_bytes);
|
||||
}
|
||||
|
||||
void *result = base + start_pos;
|
||||
AsanUnpoison(result, end_pos - start_pos);
|
||||
AsanUnpoison(result, size);
|
||||
arena->pos = end_pos;
|
||||
|
||||
return result;
|
||||
|
||||
@ -10,10 +10,10 @@
|
||||
# include "base_arena.h"
|
||||
# include "base_futex.h"
|
||||
# include "base_sync.h"
|
||||
# include "base_wave.h"
|
||||
# include "base_time.h"
|
||||
# include "base_uid.h"
|
||||
# include "base_math.h"
|
||||
# include "base_wave.h"
|
||||
# include "base_string.h"
|
||||
# include "base_cmdline.h"
|
||||
# include "base_log.h"
|
||||
@ -36,13 +36,13 @@
|
||||
# include "base_memory.c"
|
||||
# include "base_arena.c"
|
||||
# include "base_sync.c"
|
||||
# include "base_wave.c"
|
||||
# include "base_uid.c"
|
||||
# include "base_string.c"
|
||||
# include "base_cmdline.c"
|
||||
# include "base_uni.c"
|
||||
# include "base_buddy.c"
|
||||
# include "base_math.c"
|
||||
# include "base_wave.c"
|
||||
# include "base_rand.c"
|
||||
# include "base_bitbuff.c"
|
||||
# include "base_resource.c"
|
||||
|
||||
@ -1125,6 +1125,16 @@ Vec2I32 SubVec2I32(Vec2I32 a, Vec2I32 b)
|
||||
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
|
||||
|
||||
@ -1151,6 +1161,8 @@ u32 U32FromVec4(Vec4 v)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Range
|
||||
|
||||
//- Rng2
|
||||
|
||||
Vec2 DimsFromRng2(Rng2 r)
|
||||
{
|
||||
Vec2 result = ZI;
|
||||
@ -1185,6 +1197,43 @@ Rng2 DivRng2Vec2(Rng2 r, Vec2 v)
|
||||
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
|
||||
|
||||
|
||||
@ -388,12 +388,18 @@ u32 U32FromVec4(Vec4 v);
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Range
|
||||
|
||||
//- Rng2
|
||||
Vec2 DimsFromRng2(Rng2 r);
|
||||
Rng2 UnionRng2(Rng2 a, Rng2 b);
|
||||
|
||||
Rng2 AddRng2Vec2(Rng2 r, 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
|
||||
|
||||
|
||||
@ -108,10 +108,34 @@ void SetWaveLaneDefaultSpin(WaveLaneCtx *lane, u64 n)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Wave task helpers
|
||||
//~ Task helpers
|
||||
|
||||
i32 WaveLaneIdxFromTaskIdx(WaveLaneCtx *lane, u64 task_idx)
|
||||
{
|
||||
WaveCtx *wave = lane->wave;
|
||||
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);
|
||||
}
|
||||
|
||||
@ -46,9 +46,10 @@ void WaveSyncBroadcastEx_(WaveLaneCtx *lane, u32 broadcast_lane_idx, void *broad
|
||||
void SetWaveLaneDefaultSpin(WaveLaneCtx *lane, u64 n);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Wave task helpers
|
||||
//~ Task helpers
|
||||
|
||||
i32 WaveLaneIdxFromTaskIdx(WaveLaneCtx *lane, u64 task_idx);
|
||||
RngU64 WaveIdxRangeFromCount(WaveLaneCtx *lane, u64 tasks_count);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @hookdecl Dispatch
|
||||
|
||||
@ -69,8 +69,8 @@
|
||||
|
||||
#define FLOOD_DEBUG 0
|
||||
|
||||
#define GPU_DEBUG 0
|
||||
#define GPU_DEBUG_VALIDATION 0
|
||||
#define GPU_DEBUG 1
|
||||
#define GPU_DEBUG_VALIDATION 1
|
||||
|
||||
#define GPU_SHADER_PRINT 1
|
||||
#define GPU_SHADER_PRINT_BUFFER_SIZE Kibi(64);
|
||||
|
||||
@ -14,13 +14,14 @@ void GC_Bootstrap(void)
|
||||
GC_FontKey GC_FontKeyFromResource(ResourceKey resource)
|
||||
{
|
||||
GC_FontKey result = ZI;
|
||||
result.v = resource.v;
|
||||
result.r = resource;
|
||||
return result;
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
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);
|
||||
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;
|
||||
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);
|
||||
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->hash == hash) break;
|
||||
}
|
||||
|
||||
if (glyph == 0)
|
||||
{
|
||||
uncached_codepoints.text[uncached_codepoints.len] = codepoint;
|
||||
uncached_codepoints.len += 1;
|
||||
uncached_codepoints[uncached_codepoints_count] = codepoint;
|
||||
uncached_codepoints_count += 1;
|
||||
}
|
||||
else if (Atomic32Fetch(&glyph->ready) == 0)
|
||||
{
|
||||
pending_glyphs_count += 1;
|
||||
}
|
||||
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;
|
||||
result.rects = PushStructs(arena, GC_RunRect, 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->advance = glyph->advance;
|
||||
|
||||
rect->bounds.p0 = glyph->baseline_offset;
|
||||
rect->bounds.p1 = AddVec2(rect->bounds.p0, DimsFromRng2(glyph->tex_rect));
|
||||
rect->bounds = glyph->bounds;
|
||||
|
||||
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.ready = uncached_codepoints.len == 0;
|
||||
result.ready = uncached_codepoints_count == 0 && pending_glyphs_count;
|
||||
|
||||
EndScratch(scratch);
|
||||
return result;
|
||||
@ -137,21 +216,154 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
|
||||
GC_AsyncCtx *async = &GC.async_ctx;
|
||||
|
||||
//////////////////////////////
|
||||
//- Begin tick
|
||||
//- Collect cmds
|
||||
|
||||
/* TODO: Limit cmds processed per-tick */
|
||||
|
||||
if (lane->idx == 0)
|
||||
{
|
||||
Lock lock = LockE(&GC.submitted_cmds_mutex);
|
||||
Lock lock = LockE(&GC.submit.mutex);
|
||||
{
|
||||
async->cmds.count = GC.submitted_cmds_count;
|
||||
async->cmds.v = PushStructsNoZero(tick->arena, GC_Cmd, GC.submitted_cmds_count);
|
||||
/* Pop cmds from submission queue */
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -3,38 +3,12 @@
|
||||
|
||||
Struct(GC_FontKey)
|
||||
{
|
||||
u64 v;
|
||||
ResourceKey r;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ 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)
|
||||
{
|
||||
GC_FontKey font;
|
||||
@ -42,6 +16,36 @@ Struct(GC_GlyphDesc)
|
||||
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)
|
||||
// {
|
||||
// GC_GlyphDescChunk *next;
|
||||
@ -94,12 +98,10 @@ Struct(GC_Cmd)
|
||||
GC_Glyph *glyph;
|
||||
};
|
||||
|
||||
Struct(GC_CmdChunk)
|
||||
Struct(GC_CmdNode)
|
||||
{
|
||||
GC_CmdChunk *next;
|
||||
|
||||
u64 cmds_count;
|
||||
GC_Cmd *cmds;
|
||||
GC_CmdNode *next;
|
||||
GC_Cmd cmd;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -119,13 +121,25 @@ Struct(GC_Ctx)
|
||||
Mutex glyphs_mutex;
|
||||
GC_GlyphBin glyph_bins[16384];
|
||||
|
||||
Mutex submitted_cmds_mutex;
|
||||
u64 submitted_cmds_count;
|
||||
GC_CmdChunk *first_submitted_cmd_chunk;
|
||||
GC_CmdChunk *last_submitted_cmd_chunk;
|
||||
/* TODO: Dynamic atlases */
|
||||
G_ResourceHandle atlas;
|
||||
G_Texture2DRef atlas_ref;
|
||||
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;
|
||||
} extern GC;
|
||||
};
|
||||
|
||||
extern GC_Ctx GC;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Bootstrap
|
||||
|
||||
@ -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 */
|
||||
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.y = MaxI32(draw_size.y, 1);
|
||||
|
||||
@ -1,27 +1,27 @@
|
||||
Struct(TTF_Glyph)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Glyph types
|
||||
|
||||
Struct(TTF_GlyphDesc)
|
||||
{
|
||||
i32 advance;
|
||||
Vec2 baseline_offset;
|
||||
Vec2I32 atlas_p0;
|
||||
Vec2I32 atlas_p1;
|
||||
ResourceKey ttf;
|
||||
u32 codepoint;
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
};
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Bootstrap
|
||||
|
||||
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
@ -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;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ State types
|
||||
//~ Context types
|
||||
|
||||
/* TODO: Determine font dpi dynamically */
|
||||
#define TTF_DW_Dpi (96.0f)
|
||||
|
||||
Struct(TTF_DW_SharedState)
|
||||
Struct(TTF_DW_Ctx)
|
||||
{
|
||||
struct IDWriteFactory5 *factory;
|
||||
} extern TTF_DW_shared_state;
|
||||
IDWriteFactory5 *factory;
|
||||
};
|
||||
|
||||
extern TTF_DW_Ctx TTF_DW;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user