dynamic glyph atlas creation

This commit is contained in:
jacob 2025-12-16 13:25:33 -06:00
parent 9fc666d49d
commit cbeafdb8fe
22 changed files with 277 additions and 159 deletions

View File

@ -428,9 +428,9 @@
#define countof(a) (sizeof(a) / sizeof((a)[0])) #define countof(a) (sizeof(a) / sizeof((a)[0]))
#endif #endif
//- IsArray //- IsFixedArray
#define IsIndexable(a) (sizeof(a[0]) != 0) #define IsIndexable(a) (sizeof(a[0]) != 0)
#define IsArray(a) (IsIndexable(a) && (((void *)&a) == ((void *)a))) #define IsFixedArray(a) (IsIndexable(a) && (((void *)&a) == ((void *)a)))
//- offsetof //- offsetof
#if !IsCompilerMsvc #if !IsCompilerMsvc
@ -619,10 +619,9 @@
#define StringFromStruct(ptr) ((String) { sizeof(*(ptr)), (u8 *)(ptr) }) #define StringFromStruct(ptr) ((String) { sizeof(*(ptr)), (u8 *)(ptr) })
#define StringFromArena(arena) (STRING((arena)->pos, ArenaFirst(arena, u8))) #define StringFromArena(arena) (STRING((arena)->pos, ArenaFirst(arena, u8)))
/* String from static array */ #define StringFromFixedArray(a) \
#define StringFromArray(a) \
( \ ( \
Assert(IsArray(a)), \ Assert(IsFixedArray(a)), \
((String) { .len = sizeof(a), .text = (u8 *)(a) }) \ ((String) { .len = sizeof(a), .text = (u8 *)(a) }) \
) )

View File

@ -18,7 +18,7 @@ Arena *AcquireArena(u64 reserve)
Panic(Lit("Failed to reserve memory")); Panic(Lit("Failed to reserve memory"));
} }
u64 reserved = reserve; u64 reserved = reserve;
AddGstat(MemoryReserved, reserve); AddGstat(ArenaMemoryReserved, reserve);
/* Commit initial block */ /* Commit initial block */
base = CommitMemory(base, ArenaBlockSize); base = CommitMemory(base, ArenaBlockSize);
@ -32,7 +32,7 @@ Arena *AcquireArena(u64 reserve)
StaticAssert(sizeof(Arena) <= ArenaHeaderSize); /* Arena struct must fit in header */ StaticAssert(sizeof(Arena) <= ArenaHeaderSize); /* Arena struct must fit in header */
AsanPoison(base + sizeof(Arena), ArenaBlockSize - sizeof(Arena)); AsanPoison(base + sizeof(Arena), ArenaBlockSize - sizeof(Arena));
AddGstat(MemoryCommitted, ArenaBlockSize); AddGstat(ArenaMemoryCommitted, ArenaBlockSize);
AddGstat(NumArenas, 1); AddGstat(NumArenas, 1);
/* Create & return arena header at beginning of block */ /* Create & return arena header at beginning of block */
@ -46,8 +46,8 @@ Arena *AcquireArena(u64 reserve)
void ReleaseArena(Arena *arena) void ReleaseArena(Arena *arena)
{ {
AsanUnpoison(arena, arena->committed + ArenaHeaderSize); AsanUnpoison(arena, arena->committed + ArenaHeaderSize);
AddGstat(MemoryCommitted, -(i64)(arena->committed - ArenaHeaderSize)); AddGstat(ArenaMemoryCommitted, -(i64)(arena->committed - ArenaHeaderSize));
AddGstat(MemoryReserved, -(i64)(arena->reserved)); AddGstat(ArenaMemoryReserved, -(i64)(arena->reserved));
AddGstat(NumArenas, -1); AddGstat(NumArenas, -1);
ReleaseMemory(arena); ReleaseMemory(arena);
} }
@ -115,7 +115,7 @@ void *PushBytesNoZero(Arena *arena, u64 size, u64 align)
Panic(Lit("Failed to commit new memory block: System may be out of memory")); Panic(Lit("Failed to commit new memory block: System may be out of memory"));
} }
arena->committed += commit_bytes; arena->committed += commit_bytes;
AddGstat(MemoryCommitted, commit_bytes); AddGstat(ArenaMemoryCommitted, commit_bytes);
AsanPoison(commit_address, commit_bytes); AsanPoison(commit_address, commit_bytes);
} }

View File

@ -1,5 +1,5 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Async callback //~ Async types
Struct(AsyncTickCtx); Struct(AsyncTickCtx);
typedef void AsyncTickCallbackFunc(WaveLaneCtx *lane, AsyncTickCtx *tick); typedef void AsyncTickCallbackFunc(WaveLaneCtx *lane, AsyncTickCtx *tick);
@ -15,9 +15,6 @@ Struct(AsyncTickCallbackNode)
AsyncTickCallback callback; AsyncTickCallback callback;
}; };
////////////////////////////////////////////////////////////
//~ Async worker types
Struct(AsyncTickCtx) Struct(AsyncTickCtx)
{ {
Arena *arena; Arena *arena;
@ -30,6 +27,15 @@ Struct(AsyncWorkerCtx)
AsyncTickCallback *callbacks; AsyncTickCallback *callbacks;
}; };
Struct(AsyncCtx)
{
Mutex mutex;
u64 callback_nodes_count;
AsyncTickCallbackNode *first_callback_node;
AsyncTickCallbackNode *last_callback_node;
AsyncWorkerCtx worker_ctx;
};
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Bootstrap //~ Bootstrap

View File

@ -8,9 +8,6 @@ Struct(CommandlineArg)
String value; String value;
}; };
////////////////////////////////////////////////////////////
//~ Lookup types
Struct(CommandlineArgNode) Struct(CommandlineArgNode)
{ {
CommandlineArgNode *next; CommandlineArgNode *next;
@ -18,6 +15,13 @@ Struct(CommandlineArgNode)
CommandlineArg arg; CommandlineArg arg;
}; };
Struct(CmdLineCtx)
{
String *positional_args;
u64 positional_args_count;
CommandlineArgNode *arg_bins[1024];
};
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Bootstrap //~ Bootstrap

View File

@ -1,4 +1,26 @@
/* Application-wide statistics */ /* Application wide statistics */
////////////////////////////////////////////////////////////
//~ Gstat types
Struct(GstatCtx)
{
Atomic64Padded SockBytesSent;
Atomic64Padded SockBytesReceived;
Atomic64Padded DebugSteps;
Atomic64Padded NumArenas;
Atomic64Padded ArenaMemoryCommitted;
Atomic64Padded ArenaMemoryReserved;
Atomic64Padded NumGpuArenas;
Atomic64Padded DedicatedGpuArenaMemoryCommitted;
Atomic64Padded SharedGpuArenaMemoryCommitted;
};
////////////////////////////////////////////////////////////
//~ Gstat ops
#if GstatIsEnabled #if GstatIsEnabled

View File

@ -20,7 +20,7 @@ void SetMemoryReadWrite(void *address, u64 size);
#define MatchBytes(p1, p2, n) (CmpBytes((p1), (p2), (n)) == 0) #define MatchBytes(p1, p2, n) (CmpBytes((p1), (p2), (n)) == 0)
#define MatchStruct(p1, p2) MatchBytes((p1), (p2), sizeof(*p1)) #define MatchStruct(p1, p2) MatchBytes((p1), (p2), sizeof(*p1))
#define ZeroBytes(ptr, count) SetBytes((ptr), 0, (count)) #define ZeroBytes(ptr, count) SetBytes((ptr), 0, (count))
#define ZeroArray(a) Assert(IsArray(a)); ZeroBytes((a), sizeof((a))) #define ZeroFixedArray(a) Assert(IsFixedArray(a)); ZeroBytes((a), sizeof((a)))
#define ZeroStructs(ptr, n) ZeroBytes((ptr), sizeof(*(ptr)) * (n)) #define ZeroStructs(ptr, n) ZeroBytes((ptr), sizeof(*(ptr)) * (n))
#define ZeroStruct(ptr) ZeroStructs((ptr), 1) #define ZeroStruct(ptr) ZeroStructs((ptr), 1)
#define CopyStructs(ptr_dst, ptr_src, n) CopyBytes((ptr_dst), (ptr_src), sizeof(*(ptr_dst)) * (n)) #define CopyStructs(ptr_dst, ptr_src, n) CopyBytes((ptr_dst), (ptr_src), sizeof(*(ptr_dst)) * (n))

View File

@ -1,5 +1,5 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Resource cache types //~ Resource types
Struct(ResourceEntry) Struct(ResourceEntry)
{ {
@ -17,6 +17,14 @@ Struct(ResourceEntryBin)
ResourceEntry *last; ResourceEntry *last;
}; };
Struct(ResourceCtx)
{
u64 entries_count;
ResourceEntry *first_entry;
ResourceEntry *last_entry;
ResourceEntryBin bins[4096];
};
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Bootstrap //~ Bootstrap

View File

@ -3,43 +3,10 @@
Struct(BaseCtx) Struct(BaseCtx)
{ {
/* Command line */ CmdLineCtx cmdline;
struct ResourceCtx resource;
{ GstatCtx gstat;
String *positional_args; AsyncCtx async;
u64 positional_args_count;
CommandlineArgNode *arg_bins[1024];
} cmdline;
/* Resources */
struct
{
u64 entries_count;
ResourceEntry *first_entry;
ResourceEntry *last_entry;
ResourceEntryBin bins[4096];
} resource;
/* Stats */
struct
{
Atomic64Padded SockBytesSent;
Atomic64Padded SockBytesReceived;
Atomic64Padded MemoryCommitted;
Atomic64Padded MemoryReserved;
Atomic64Padded NumArenas;
Atomic64Padded DebugSteps;
} gstat;
/* Async */
struct
{
Mutex mutex;
u64 callback_nodes_count;
AsyncTickCallbackNode *first_callback_node;
AsyncTickCallbackNode *last_callback_node;
AsyncWorkerCtx worker_ctx;
} async;
}; };
extern BaseCtx Base; extern BaseCtx Base;

View File

@ -289,25 +289,25 @@ StringArray SplitString(Arena *arena, String str, String delim)
StringArray pieces = ZI; StringArray pieces = ZI;
pieces.strings = ArenaNext(arena, String); pieces.strings = ArenaNext(arena, String);
i64 piece_start = 0; i64 piece_start = 0;
for (i64 i = 0; i < (i64)str.len - (i64)delim.len; ++i) for (i64 i = 0; i < (i64)str.len - (i64)delim.len;)
{ {
String cmp = ZI; String cmp = ZI;
cmp.text = &str.text[i]; cmp.text = &str.text[i];
cmp.len = MinI64(str.len - i, delim.len); cmp.len = MinI64(str.len - i, delim.len);
b32 is_delimiter = MatchString(cmp, delim); if (MatchString(cmp, delim))
if (is_delimiter)
{ {
String piece = ZI; String piece = ZI;
piece.text = &str.text[piece_start]; piece.text = &str.text[piece_start];
piece.len = i - piece_start; piece.len = i - piece_start;
*PushStructNoZero(arena, String) = piece;
++pieces.count;
i += delim.len; i += delim.len;
piece_start = i; piece_start = i;
if (piece.len > 0) }
{ else
*PushStructNoZero(arena, String) = piece; {
++pieces.count; i += 1;
}
} }
} }
if (piece_start < (i64)str.len) if (piece_start < (i64)str.len)
@ -321,6 +321,44 @@ StringArray SplitString(Arena *arena, String str, String delim)
return pieces; return pieces;
} }
String ReplaceString(Arena *arena, String str, String old_pattern, String new_pattern)
{
String result = ZI;
result.text = ArenaNext(arena, u8);
i64 piece_start = 0;
for (i64 i = 0; i < (i64)str.len - (i64)old_pattern.len;)
{
String cmp = ZI;
cmp.text = &str.text[i];
cmp.len = MinI64(str.len - i, old_pattern.len);
if (MatchString(cmp, old_pattern))
{
String piece = ZI;
piece.text = &str.text[piece_start];
piece.len = i - piece_start;
if (piece.len > 0)
{
result.len += PushString(arena, piece).len;
}
result.len += PushString(arena, new_pattern).len;
i += old_pattern.len;
piece_start = i;
}
else
{
i += 1;
}
}
if (piece_start < (i64)str.len)
{
String piece = ZI;
piece.text = &str.text[piece_start];
piece.len = str.len - piece_start;
result.len += PushString(arena, piece).len;
}
return result;
}
//- Indent //- Indent
/* NOTE: Really slow */ /* NOTE: Really slow */
@ -464,6 +502,17 @@ b32 StringEndsWith(String str, String substring)
return 0; return 0;
} }
String StringFromArray(Arena *arena, StringArray a)
{
String result = ZI;
result.text = ArenaNext(arena, u8);
for (u64 string_idx = 0; string_idx < a.count; ++string_idx)
{
result.len += PushString(arena, a.strings[string_idx]).len;
}
return result;
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ String list helpers //~ String list helpers

View File

@ -94,12 +94,14 @@ String CopyString(String dst, String src);
String RepeatString(Arena *arena, String src, u64 count); String RepeatString(Arena *arena, String src, u64 count);
String CatString(Arena *arena, String str1, String str2); String CatString(Arena *arena, String str1, String str2);
StringArray SplitString(Arena *arena, String str, String delim); StringArray SplitString(Arena *arena, String str, String delim);
String ReplaceString(Arena *arena, String str, String old_pattern, String new_pattern);
String IndentString(Arena *arena, String str, u32 indent); String IndentString(Arena *arena, String str, u32 indent);
String LowerString(Arena *arena, String str); String LowerString(Arena *arena, String str);
b32 MatchString(String str1, String str2); b32 MatchString(String str1, String str2);
b32 StringContains(String str, String substring); b32 StringContains(String str, String substring);
b32 StringBeginsWith(String str, String substring); b32 StringBeginsWith(String str, String substring);
b32 StringEndsWith(String str, String substring); b32 StringEndsWith(String str, String substring);
String StringFromArray(Arena *arena, StringArray a);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Trimming helpers //~ Trimming helpers

View File

@ -64,7 +64,7 @@ b32 Panic(String msg)
{ {
LogPanic(msg); LogPanic(msg);
char msg_cstr[4096]; char msg_cstr[4096];
CstrFromStringToBuff(StringFromArray(msg_cstr), msg); CstrFromStringToBuff(StringFromFixedArray(msg_cstr), msg);
{ {
u32 mb_flags = MB_SETFOREGROUND | MB_ICONERROR; u32 mb_flags = MB_SETFOREGROUND | MB_ICONERROR;
MessageBoxExA(0, msg_cstr, "Fatal error", mb_flags, 0); MessageBoxExA(0, msg_cstr, "Fatal error", mb_flags, 0);

View File

@ -176,7 +176,7 @@ GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size
GC_Glyph *glyph = ready_glyphs[glyph_idx]; GC_Glyph *glyph = ready_glyphs[glyph_idx];
GC_RunRect *rect = &result.rects[glyph_idx]; GC_RunRect *rect = &result.rects[glyph_idx];
rect->tex = glyph->tex_ref; rect->tex = glyph->atlas->tex_ref;
rect->tex_slice = glyph->tex_slice; rect->tex_slice = glyph->tex_slice;
rect->tex_slice_uv = glyph->tex_slice_uv; rect->tex_slice_uv = glyph->tex_slice_uv;
@ -252,9 +252,6 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
WaveSync(lane); WaveSync(lane);
////////////////////////////// //////////////////////////////
//- Rasterize glyphs //- Rasterize glyphs
@ -288,22 +285,6 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
if (lane->idx == 0) if (lane->idx == 0)
{ {
/* FIXME: Dynamic atlases */
/* Create atlas */
Vec2I32 atlas_dims = VEC2I32(8192, 8192);
if (G_IsResourceNil(GC.atlas))
{
G_ArenaHandle gpu_perm = G_PermArena();
GC.atlas = G_PushTexture2D(
gpu_perm,
G_Format_R8G8B8A8_Unorm_Srgb,
atlas_dims,
/* FIXME: Do we need simultaneous access? */
G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present,
);
GC.atlas_ref = G_PushTexture2DRef(gpu_perm, GC.atlas);
}
for (u64 cmd_idx = 0; cmd_idx < async->cmds.count; ++cmd_idx) for (u64 cmd_idx = 0; cmd_idx < async->cmds.count; ++cmd_idx)
{ {
GC_Cmd *cmd = &async->cmds.v[cmd_idx]; GC_Cmd *cmd = &async->cmds.v[cmd_idx];
@ -313,23 +294,59 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
Vec2I32 image_dims = ttf_result.image_dims; Vec2I32 image_dims = ttf_result.image_dims;
Vec2I32 atlas_offset = GC.atlas_pos; /* TODO: Use a more efficient atlas packing algorithm for less wasted space `*/
GC.atlas_row_height = MaxI32(GC.atlas_row_height, image_dims.y); GC_Atlas *atlas = GC.first_atlas;
if (atlas_offset.x + image_dims.x > atlas_dims.x); b32 can_use_atlas = 0;
Vec2I32 pos_in_atlas = ZI;
while (can_use_atlas == 0)
{ {
GC.atlas_pos.x = 0; /* Create atlas */
GC.atlas_pos.y += GC.atlas_row_height; if (!atlas)
GC.atlas_row_height = image_dims.y; {
Arena *perm = PermArena();
atlas = PushStruct(perm, GC_Atlas);
atlas->dims = VEC2I32(1024, 1024);
{
G_ArenaHandle gpu_perm = G_PermArena();
atlas->tex = G_PushTexture2D(
gpu_perm,
G_Format_R8G8B8A8_Unorm_Srgb,
atlas->dims,
G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present,
);
atlas->tex_ref = G_PushTexture2DRef(gpu_perm, atlas->tex);
}
SllStackPush(GC.first_atlas, atlas);
++GC.atlases_count;
}
/* Determine pos in atlas */
pos_in_atlas = atlas->cur_pos;
atlas->cur_row_height = MaxI32(atlas->cur_row_height, image_dims.y);
if (pos_in_atlas.x + image_dims.x > atlas->dims.x);
{
atlas->cur_pos.x = 0;
atlas->cur_pos.y += atlas->cur_row_height;
atlas->cur_row_height = image_dims.y;
}
atlas->cur_pos.x += image_dims.x;
if (atlas->cur_pos.x < atlas->dims.x && atlas->cur_pos.y < atlas->dims.y)
{
can_use_atlas = 1;
}
else
{
atlas = 0;
}
} }
GC.atlas_pos.x += image_dims.x;
/* Atlas info */ /* Atlas info */
glyph->tex_ref = GC.atlas_ref; glyph->atlas = atlas;
glyph->tex_slice = RNG2I32(atlas_offset, AddVec2I32(atlas_offset, image_dims)); glyph->tex_slice = RNG2I32(pos_in_atlas, AddVec2I32(pos_in_atlas, image_dims));
glyph->tex_slice_uv.p0.x = (f32)glyph->tex_slice.p0.x / (f32)atlas_dims.x; glyph->tex_slice_uv.p0.x = (f32)glyph->tex_slice.p0.x / (f32)atlas->dims.x;
glyph->tex_slice_uv.p0.y = (f32)glyph->tex_slice.p0.y / (f32)atlas_dims.x; glyph->tex_slice_uv.p0.y = (f32)glyph->tex_slice.p0.y / (f32)atlas->dims.x;
glyph->tex_slice_uv.p1.x = (f32)glyph->tex_slice.p1.x / (f32)atlas_dims.x; glyph->tex_slice_uv.p1.x = (f32)glyph->tex_slice.p1.x / (f32)atlas->dims.x;
glyph->tex_slice_uv.p1.y = (f32)glyph->tex_slice.p1.y / (f32)atlas_dims.x; glyph->tex_slice_uv.p1.y = (f32)glyph->tex_slice.p1.y / (f32)atlas->dims.x;
} }
} }
@ -346,7 +363,7 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
GC_Glyph *glyph = cmd->glyph; GC_Glyph *glyph = cmd->glyph;
ResourceKey resource = glyph->desc.font.r; ResourceKey resource = glyph->desc.font.r;
GC_GlyphDesc desc = glyph->desc; GC_GlyphDesc desc = glyph->desc;
TTF_GlyphResult ttf_result = TTF_RasterizeGlyphFromCodepoint(tick->arena, desc.codepoint, resource, desc.font_size);; TTF_GlyphResult ttf_result = TTF_RasterizeGlyphFromCodepoint(tick->arena, desc.codepoint, resource, desc.font_size);
u32 *image_pixels = ttf_result.image_pixels; u32 *image_pixels = ttf_result.image_pixels;
Vec2I32 image_dims = ttf_result.image_dims; Vec2I32 image_dims = ttf_result.image_dims;
@ -359,7 +376,7 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
G_CopyCpuToTexture( G_CopyCpuToTexture(
cl, cl,
GC.atlas, VEC3I32(glyph->tex_slice.p0.x, glyph->tex_slice.p0.y, 0), glyph->atlas->tex, VEC3I32(glyph->tex_slice.p0.x, glyph->tex_slice.p0.y, 0),
image_pixels, VEC3I32(image_dims.x, image_dims.y, 1), image_pixels, VEC3I32(image_dims.x, image_dims.y, 1),
RNG3I32( RNG3I32(
VEC3I32(0, 0, 0), VEC3I32(0, 0, 0),

View File

@ -6,6 +6,20 @@ Struct(GC_FontKey)
ResourceKey r; ResourceKey r;
}; };
////////////////////////////////////////////////////////////
//~ Atlas types
Struct(GC_Atlas)
{
GC_Atlas *next;
Vec2I32 dims;
G_ResourceHandle tex;
G_Texture2DRef tex_ref;
Vec2I32 cur_pos;
i32 cur_row_height;
};
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Glyph types //~ Glyph types
@ -35,7 +49,7 @@ Struct(GC_Glyph)
Rng2 bounds; Rng2 bounds;
/* Atlas info */ /* Atlas info */
G_Texture2DRef tex_ref; GC_Atlas *atlas;
Rng2I32 tex_slice; Rng2I32 tex_slice;
Rng2 tex_slice_uv; Rng2 tex_slice_uv;
}; };
@ -45,13 +59,6 @@ Struct(GC_GlyphBin)
GC_Glyph *first; GC_Glyph *first;
}; };
// Struct(GC_GlyphDescChunk)
// {
// GC_GlyphDescChunk *next;
// u64 descs_count;
// GC_GlyphDesc *descs;
// };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Run types //~ Run types
@ -123,11 +130,8 @@ Struct(GC_Ctx)
Mutex glyphs_mutex; Mutex glyphs_mutex;
GC_GlyphBin glyph_bins[16384]; GC_GlyphBin glyph_bins[16384];
/* TODO: Dynamic atlases */ u64 atlases_count;
G_ResourceHandle atlas; GC_Atlas *first_atlas;
G_Texture2DRef atlas_ref;
Vec2I32 atlas_pos;
i32 atlas_row_height;
struct struct
{ {

View File

@ -764,6 +764,8 @@ G_ArenaHandle G_AcquireArena(void)
gpu_arena->resource_heaps[heap_idx].kind = (G_D12_ResourceHeapKind)heap_idx; gpu_arena->resource_heaps[heap_idx].kind = (G_D12_ResourceHeapKind)heap_idx;
} }
AddGstat(NumGpuArenas, 1);
return G_D12_MakeHandle(G_ArenaHandle, gpu_arena); return G_D12_MakeHandle(G_ArenaHandle, gpu_arena);
} }
@ -772,6 +774,8 @@ void G_ReleaseArena(G_ArenaHandle arena)
/* TODO */ /* TODO */
/* TODO: Unmap heaps */ /* TODO: Unmap heaps */
/* TODO: Update gstats */
} }
void G_ResetArena(G_CommandListHandle cl_handle, G_ArenaHandle arena_handle) void G_ResetArena(G_CommandListHandle cl_handle, G_ArenaHandle arena_handle)
@ -788,51 +792,37 @@ void G_D12_ResetArena(G_D12_CmdList *cl, G_D12_Arena *gpu_arena)
{ {
/* TODO */ /* TODO */
/* FIXME: Move descriptors into committed lists */
/* FIXME: Release id3d12 resource com object references */
// for (u64 heap_idx = 0; heap_idx < countof(gpu_arena->resource_heaps); ++heap_idx)
// {
// G_D12_ResourceHeap *heap = &gpu_arena->resource_heaps[heap_idx];
// heap->pos = 0;
// if (heap->first_reset_resource)
// {
// heap->last_reset_resource->next = heap->first_resource;
// }
// else
// {
// heap->first_reset_resource = heap->first_resource;
// }
// heap->last_reset_resource = heap->last_resource;
// heap->reset_resources_count += heap->resources_count;
// heap->resources_count = 0;
// heap->first_resource = 0;
// heap->last_resource = 0;
// }
for (u64 heap_idx = 0; heap_idx < countof(gpu_arena->resource_heaps); ++heap_idx) for (u64 heap_idx = 0; heap_idx < countof(gpu_arena->resource_heaps); ++heap_idx)
{ {
G_D12_ResourceHeap *heap = &gpu_arena->resource_heaps[heap_idx]; G_D12_ResourceHeap *heap = &gpu_arena->resource_heaps[heap_idx];
heap->pos = 0; heap->pos = 0;
/* FIXME: Free list if this actually works */ if (heap->resources.first)
for (G_D12_Resource *resource = heap->resources.first; resource; resource = resource->next)
{ {
ID3D12Resource_Release(resource->d3d_resource); for (G_D12_Resource *resource = heap->resources.first; resource; resource = resource->next)
{
ID3D12Resource_Release(resource->d3d_resource);
}
if (gpu_arena->free_resources.last)
{
gpu_arena->free_resources.last->next = heap->resources.first;
}
else
{
gpu_arena->free_resources.first = heap->resources.first;
}
gpu_arena->free_resources.last = heap->resources.last;
gpu_arena->free_resources.count += heap->resources.count;
heap->resources.count = 0;
heap->resources.first = 0;
heap->resources.last = 0;
} }
heap->resources.count = 0;
heap->resources.first = 0;
heap->resources.last = 0;
} }
/* Push descriptors to cl reset list */ /* Push descriptors to cl reset list */
if (gpu_arena->descriptors.first)
{ {
if (cl->reset_descriptors.last) if (cl->reset_descriptors.last)
{ {
@ -922,6 +912,14 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_ResourceDesc desc)
d3d_desc.Flags |= D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES; /* TODO: Remove this and support tier 1 resource heaps */ d3d_desc.Flags |= D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES; /* TODO: Remove this and support tier 1 resource heaps */
hr = ID3D12Device_CreateHeap(g->device, &d3d_desc, &IID_ID3D12Heap, (void **)&heap->d3d_heap); hr = ID3D12Device_CreateHeap(g->device, &d3d_desc, &IID_ID3D12Heap, (void **)&heap->d3d_heap);
heap->size = d3d_desc.SizeInBytes; heap->size = d3d_desc.SizeInBytes;
if (d3d_desc.Properties.Type == D3D12_HEAP_TYPE_DEFAULT)
{
AddGstat(DedicatedGpuArenaMemoryCommitted, heap->size);
}
else
{
AddGstat(SharedGpuArenaMemoryCommitted, heap->size);
}
} }
/* Map heap resource */ /* Map heap resource */
@ -1074,6 +1072,14 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_ResourceDesc desc)
// } // }
u64 pos_in_heap = 0; u64 pos_in_heap = 0;
ID3D12Resource *d3d_resource = 0; ID3D12Resource *d3d_resource = 0;
resource = gpu_arena->free_resources.first;
if (resource)
{
SllQueuePop(gpu_arena->free_resources.first, gpu_arena->free_resources.last);
--gpu_arena->free_resources.count;
ZeroStruct(resource);
}
else
{ {
resource = PushStruct(gpu_arena->arena, G_D12_Resource); resource = PushStruct(gpu_arena->arena, G_D12_Resource);
} }

View File

@ -185,6 +185,8 @@ Struct(G_D12_Arena)
G_D12_DescriptorList descriptors; G_D12_DescriptorList descriptors;
G_D12_DescriptorList reset_descriptors_by_heap[G_D12_DescriptorHeapKind_Count]; G_D12_DescriptorList reset_descriptors_by_heap[G_D12_DescriptorHeapKind_Count];
G_D12_ResourceList free_resources;
G_D12_ResourceHeap resource_heaps[G_D12_ResourceHeapKind_Count]; G_D12_ResourceHeap resource_heaps[G_D12_ResourceHeapKind_Count];
}; };

View File

@ -867,7 +867,7 @@ void N_EndUpdate(N_Host *host)
{ {
u8 packet_flags = 0; u8 packet_flags = 0;
N_SndPacket *packet = N_PushSndPacket(channel, 0); N_SndPacket *packet = N_PushSndPacket(channel, 0);
BB_Buff bb = BB_BuffFromString(StringFromArray(packet->data)); BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data));
BB_Writer bw = BB_WriterFromBuff(&bb); BB_Writer bw = BB_WriterFromBuff(&bb);
BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */ BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */
BB_WriteIBits(&bw, N_PacketKind_TryConnect, 8); BB_WriteIBits(&bw, N_PacketKind_TryConnect, 8);
@ -880,7 +880,7 @@ void N_EndUpdate(N_Host *host)
{ {
u8 packet_flags = 0; u8 packet_flags = 0;
N_SndPacket *packet = N_PushSndPacket(channel, 0); N_SndPacket *packet = N_PushSndPacket(channel, 0);
BB_Buff bb = BB_BuffFromString(StringFromArray(packet->data)); BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data));
BB_Writer bw = BB_WriterFromBuff(&bb); BB_Writer bw = BB_WriterFromBuff(&bb);
BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */ BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */
BB_WriteIBits(&bw, N_PacketKind_ConnectSuccess, 8); BB_WriteIBits(&bw, N_PacketKind_ConnectSuccess, 8);
@ -893,7 +893,7 @@ void N_EndUpdate(N_Host *host)
{ {
u8 packet_flags = 0; u8 packet_flags = 0;
N_SndPacket *packet = N_PushSndPacket(channel, 0); N_SndPacket *packet = N_PushSndPacket(channel, 0);
BB_Buff bb = BB_BuffFromString(StringFromArray(packet->data)); BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data));
BB_Writer bw = BB_WriterFromBuff(&bb); BB_Writer bw = BB_WriterFromBuff(&bb);
BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */ BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */
BB_WriteIBits(&bw, N_PacketKind_Disconnect, 8); BB_WriteIBits(&bw, N_PacketKind_Disconnect, 8);
@ -906,7 +906,7 @@ void N_EndUpdate(N_Host *host)
{ {
u8 packet_flags = 0; u8 packet_flags = 0;
N_SndPacket *packet = N_PushSndPacket(channel, 0); N_SndPacket *packet = N_PushSndPacket(channel, 0);
BB_Buff bb = BB_BuffFromString(StringFromArray(packet->data)); BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data));
BB_Writer bw = BB_WriterFromBuff(&bb); BB_Writer bw = BB_WriterFromBuff(&bb);
BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */ BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */
BB_WriteIBits(&bw, N_PacketKind_Heartbeat, 8); BB_WriteIBits(&bw, N_PacketKind_Heartbeat, 8);
@ -944,7 +944,7 @@ void N_EndUpdate(N_Host *host)
} }
} }
N_SndPacket *packet = N_PushSndPacket(channel, is_reliable); N_SndPacket *packet = N_PushSndPacket(channel, is_reliable);
BB_Buff bb = BB_BuffFromString(StringFromArray(packet->data)); BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data));
BB_Writer bw = BB_WriterFromBuff(&bb); BB_Writer bw = BB_WriterFromBuff(&bb);
BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */ BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */
BB_WriteIBits(&bw, N_PacketKind_MsgChunk, 8); BB_WriteIBits(&bw, N_PacketKind_MsgChunk, 8);

View File

@ -552,6 +552,7 @@ void S_TickForever(WaveLaneCtx *lane)
LockTicketMutex(&shared->output_back_tm); LockTicketMutex(&shared->output_back_tm);
{ {
S_OutputState *output = &shared->output_states[shared->output_back_idx]; S_OutputState *output = &shared->output_states[shared->output_back_idx];
ResetArena(output->arena);
S_SnapshotNode *snapshot_node = PushStruct(output->arena, S_SnapshotNode); S_SnapshotNode *snapshot_node = PushStruct(output->arena, S_SnapshotNode);
S_Snapshot *snapshot = &snapshot_node->snapshot; S_Snapshot *snapshot = &snapshot_node->snapshot;
SllQueuePush(output->first_snapshot_node, output->last_snapshot_node, snapshot_node); SllQueuePush(output->first_snapshot_node, output->last_snapshot_node, snapshot_node);

View File

@ -409,6 +409,37 @@ void V_TickForever(WaveLaneCtx *lane)
V_BuildConsoleWidget(minimized); V_BuildConsoleWidget(minimized);
} }
//////////////////////////////
//- Build debug info
if (persist.show_console)
{
UI_PushCP(UI_BuildColumn());
{
{
{
UI_Push(FontSize, 32);
UI_BuildLabelF("CPU:");
UI_Pop(FontSize);
}
UI_BuildLabelF(" Arenas: %F", FmtSint(GetGstat(NumArenas)));
UI_BuildLabelF(" Arena memory committed: %F MiB", FmtFloat((f64)GetGstat(ArenaMemoryCommitted) / 1024 / 1024));
UI_BuildLabelF(" Arena memory reserved: %F TiB", FmtFloat((f64)GetGstat(ArenaMemoryReserved) / 1024 / 1024 / 1024 / 1024));
}
{
{
UI_Push(FontSize, 32);
UI_BuildLabelF("GPU:");
UI_Pop(FontSize);
}
UI_BuildLabelF(" Arenas: %F", FmtSint(GetGstat(NumGpuArenas)));
UI_BuildLabelF(" Dedicated arena memory committed: %F MiB", FmtFloat((f64)GetGstat(DedicatedGpuArenaMemoryCommitted) / 1024 / 1024));
UI_BuildLabelF(" Shared arena memory committed: %F MiB", FmtFloat((f64)GetGstat(SharedGpuArenaMemoryCommitted) / 1024 / 1024));
}
}
UI_PopCP(UI_TopCP());
}
////////////////////////////// //////////////////////////////
//- Process vis commands //- Process vis commands

View File

@ -5,11 +5,11 @@ V_WidgetTheme V_GetWidgetTheme(void)
{ {
V_WidgetTheme theme = ZI; V_WidgetTheme theme = ZI;
// theme.font = GC_FontKeyFromResource(ResourceKeyFromStore(&V_Resources, Lit("font/fixedsys.ttf")));
// theme.font_size = 16;
theme.font = GC_FontKeyFromResource(ResourceKeyFromStore(&V_Resources, Lit("font/fixedsys.ttf"))); theme.font = GC_FontKeyFromResource(ResourceKeyFromStore(&V_Resources, Lit("font/fixedsys.ttf")));
theme.font_size = 64; theme.font_size = 16;
// theme.font = GC_FontKeyFromResource(ResourceKeyFromStore(&V_Resources, Lit("font/fixedsys.ttf")));
// theme.font_size = 64;
// theme.font = GC_FontKeyFromResource(ResourceKeyFromStore(&V_Resources, Lit("font/roboto-med.ttf"))); // theme.font = GC_FontKeyFromResource(ResourceKeyFromStore(&V_Resources, Lit("font/roboto-med.ttf")));
// theme.font_size = 100; // theme.font_size = 100;

View File

@ -29,7 +29,7 @@ TAR_Archive TAR_ArchiveFromString(Arena *arena, String data, String prefix)
TAR_Header header = ZI; TAR_Header header = ZI;
BB_ReadBytes(&br, StringFromStruct(&header)); BB_ReadBytes(&br, StringFromStruct(&header));
if (!MatchString(StringFromArray(header.ustar_indicator), Lit("ustar\0"))) if (!MatchString(StringFromFixedArray(header.ustar_indicator), Lit("ustar\0")))
{ {
/* Invalid header */ /* Invalid header */
Assert(0); Assert(0);

View File

@ -367,7 +367,7 @@ UI_Style UI_PopStyle(UI_StyleDesc desc)
{ {
UI_StyleNode *n = stack->style_tops[kind]; UI_StyleNode *n = stack->style_tops[kind];
result = n->style; result = n->style;
if (desc.use && n->pop_when_used) if (desc.force_pop || (desc.use && n->pop_when_used))
{ {
stack->style_tops[kind] = n->next; stack->style_tops[kind] = n->next;
n->next = frame->first_free_style_node; n->next = frame->first_free_style_node;

View File

@ -9,7 +9,7 @@ void WND_Bootstrap(void)
//- Initialize btn table //- Initialize btn table
{ {
ZeroArray(g->vk_to_button); ZeroFixedArray(g->vk_to_button);
for (u32 i = 'A', j = Button_A; i <= 'Z'; ++i, ++j) for (u32 i = 'A', j = Button_A; i <= 'Z'; ++i, ++j)
{ {
g->vk_to_button[i] = (Button)j; g->vk_to_button[i] = (Button)j;