ui gpu refactor progress

This commit is contained in:
jacob 2025-12-07 13:07:24 -06:00
parent 0559ba8cba
commit ed74c5cea5
31 changed files with 935 additions and 1264 deletions

View File

@ -1,203 +0,0 @@
/* TODO: Remove this entire layer */
AC_SharedState AC_shared_state = ZI;
////////////////////////////////////////////////////////////
//~ Startup
void AC_Startup(void)
{
AC_SharedState *g = &AC_shared_state;
g->store_arena = AcquireArena(Gibi(64));
}
////////////////////////////////////////////////////////////
//~ Hash
u64 AC_HashFromKey(String key)
{
/* TODO: Better hash */
return HashFnv64(Fnv64Basis, key);
}
////////////////////////////////////////////////////////////
//~ Cache
void AC_RefreshDebugTable(void)
{
#if IsRtcEnabled
AC_SharedState *g = &AC_shared_state;
Lock lock = LockE(&g->dbg_table_mutex);
ZeroArray(g->dbg_table);
g->dbg_table_count = 0;
for (u64 i = 0; i < countof(g->lookup); ++i)
{
AC_Asset *asset = &g->lookup[i];
if (asset->hash != 0)
{
g->dbg_table[g->dbg_table_count++] = asset;
}
}
Unlock(&lock);
#endif
}
/* Returns first matching slot or first empty slot if not found.
* Check returned slot->hash != 0 for presence. */
AC_Asset *AC_GetAssetCacheSlotLocked(Lock *lock, String key, u64 hash)
{
AC_SharedState *g = &AC_shared_state;
AssertLockedES(lock, &g->lookup_mutex);
u64 index = hash % countof(g->lookup);
for (;;)
{
AC_Asset *slot = &g->lookup[index];
if (slot->hash)
{
/* Occupied */
if (hash == slot->hash && MatchString(key, slot->key))
{
/* Matched slot */
return slot;
}
else
{
++index;
if (index >= countof(g->lookup))
{
index = 0;
}
}
}
else
{
/* Empty slot */
return slot;
}
}
}
/* `key` text is copied by this function
*
* Returns existing asset entry or inserts a new one.
*
* If is_first_touch (out parameter) is set to 1, then the caller has
* inserted the asset into the cache.
*
* */
AC_Asset *AC_TouchCache(String key, u64 hash, b32 *is_first_touch)
{
AC_Asset *asset = 0;
AC_SharedState *g = &AC_shared_state;
/* Lookup */
{
Lock lock = LockS(&g->lookup_mutex);
asset = AC_GetAssetCacheSlotLocked(&lock, key, hash);
Unlock(&lock);
}
/* Insert if not found */
if (asset->hash)
{
if (is_first_touch)
{
*is_first_touch = 0;
}
}
else
{
Lock lock = LockE(&g->lookup_mutex);
/* Re-check asset presence in case it was inserted since lock */
asset = AC_GetAssetCacheSlotLocked(&lock, key, hash);
if (!asset->hash)
{
if (g->num_assets >= AC_MaxAssets)
{
Panic(Lit("Max assets reached"));
}
String key_stored = ZI;
{
/* Copy key to store */
AC_Store store = AC_OpenStore();
key_stored = PushString(store.arena, key);
AC_CloseStore(&store);
}
/* Initialize asset data */
LogInfoF("Inserting asset cache entry for \"%F\"", FmtString(key));
*asset = (AC_Asset) {
.status = ASSET_STATUS_UNINITIALIZED,
.hash = hash,
.key = key_stored
};
if (is_first_touch)
{
*is_first_touch = 1;
}
++g->num_assets;
AC_RefreshDebugTable();
}
Unlock(&lock);
}
return asset;
}
////////////////////////////////////////////////////////////
//~ Status
/* Call this once asset job has been created */
void AC_MarkLoading(AC_Asset *asset)
{
asset->status = ASSET_STATUS_LOADING;
}
/* Call this once asset job has finished */
void AC_MarkReady(AC_Asset *asset, void *store_data)
{
asset->store_data = store_data;
asset->status = ASSET_STATUS_READY;
SetFence(&asset->ready_fence, 1);
}
void AC_YieldOnAssetReady(AC_Asset *asset)
{
YieldOnFence(&asset->ready_fence, 1);
}
////////////////////////////////////////////////////////////
//~ Store
void *AC_DataFromStore(AC_Asset *asset)
{
if (asset->status == ASSET_STATUS_READY)
{
return asset->store_data;
}
else
{
return 0;
}
}
/* Asset store should be opened to allocate memory to the store arena */
AC_Store AC_OpenStore(void)
{
AC_SharedState *g = &AC_shared_state;
Lock lock = LockE(&g->store_mutex);
AC_Store store = {
.lock = lock,
.arena = g->store_arena
};
return store;
}
void AC_CloseStore(AC_Store *store)
{
Unlock(&store->lock);
}

View File

@ -1,93 +0,0 @@
/* TODO: Remove this entire layer */
////////////////////////////////////////////////////////////
//~ Asset types
Enum(AC_Status)
{
ASSET_STATUS_NONE,
ASSET_STATUS_UNINITIALIZED,
ASSET_STATUS_LOADING,
ASSET_STATUS_READY
};
Struct(AC_Asset)
{
/* Managed via AC_TouchCache */
u64 hash;
String key;
/* Asset is ready when fence >= 1 */
Fence ready_fence;
/* Managed via asset_cache_mark_x functions */
AC_Status status;
/* Accessed via asset_cache_get_data */
void *store_data;
};
////////////////////////////////////////////////////////////
//~ Asset store types
Struct(AC_Store)
{
Arena *arena;
/* internal */
Lock lock;
};
////////////////////////////////////////////////////////////
//~ State types
#define AC_MaxAssets 1024
#define AC_AssetLookupTableCapacity (AC_MaxAssets * 4)
Struct(AC_SharedState)
{
Mutex lookup_mutex;
AC_Asset lookup[AC_AssetLookupTableCapacity];
u64 num_assets;
Mutex store_mutex;
Arena *store_arena;
#if IsRtcEnabled
/* Array of len `num_assets` pointing into populated entries of `lookup`. */
AC_Asset *dbg_table[AC_AssetLookupTableCapacity];
u64 dbg_table_count;
Mutex dbg_table_mutex;
#endif
} extern AC_shared_state;
////////////////////////////////////////////////////////////
//~ Startup
void AC_Startup(void);
////////////////////////////////////////////////////////////
//~ Hash
u64 AC_HashFromKey(String key);
////////////////////////////////////////////////////////////
//~ Cache operations
void AC_RefreshDebugTable(void);
AC_Asset *AC_GetAssetCacheSlotLocked(Lock *lock, String key, u64 hash);
AC_Asset *AC_TouchCache(String key, u64 hash, b32 *is_first_touch);
////////////////////////////////////////////////////////////
//~ Status operations
void AC_MarkLoading(AC_Asset *asset);
void AC_MarkReady(AC_Asset *asset, void *store_data);
void AC_YieldOnAssetReady(AC_Asset *asset);
////////////////////////////////////////////////////////////
//~ Store operations
void *AC_DataFromStore(AC_Asset *asset);
AC_Store AC_OpenStore(void);
void AC_CloseStore(AC_Store *store);

View File

@ -1,13 +0,0 @@
@Layer asset_cache
//- Dependencies
@Dep platform
//- Api
@IncludeC asset_cache.h
//- Impl
@IncludeC asset_cache.c
//- Startup
@Startup AC_Startup

View File

@ -684,12 +684,12 @@
Struct(ResourceStore) Struct(ResourceStore)
{ {
u64 hash; u64 v;
}; };
Struct(ResourceKey) Struct(ResourceKey)
{ {
u64 hash; u64 v;
}; };
#endif #endif

View File

@ -46,13 +46,13 @@ void InitResourceSystem(u64 archive_strings_count, String *archive_strings)
b32 IsResourceNil(ResourceKey resource) b32 IsResourceNil(ResourceKey resource)
{ {
return resource.hash == 0; return resource.v == 0;
} }
ResourceKey ResourceKeyFromStore(ResourceStore *store, String name) ResourceKey ResourceKeyFromStore(ResourceStore *store, String name)
{ {
ResourceKey result = ZI; ResourceKey result = ZI;
result.hash = HashFnv64(store->hash, name); result.v = HashFnv64(store->v, name);
return result; return result;
} }
@ -81,7 +81,7 @@ ResourceEntry *ResourceEntryFromHash(u64 hash)
String DataFromResource(ResourceKey resource) String DataFromResource(ResourceKey resource)
{ {
String result = ZI; String result = ZI;
ResourceEntry *entry = ResourceEntryFromHash(resource.hash); ResourceEntry *entry = ResourceEntryFromHash(resource.v);
if (entry) if (entry)
{ {
result = entry->data; result = entry->data;
@ -92,7 +92,7 @@ String DataFromResource(ResourceKey resource)
String NameFromResource(ResourceKey resource) String NameFromResource(ResourceKey resource)
{ {
String result = ZI; String result = ZI;
ResourceEntry *entry = ResourceEntryFromHash(resource.hash); ResourceEntry *entry = ResourceEntryFromHash(resource.v);
if (entry) if (entry)
{ {
result = entry->name; result = entry->name;

View File

@ -1,247 +0,0 @@
////////////////////////////////////////////////////////////
//~ Font load job
JobImpl(F_Load, sig, _)
{
TempArena scratch = BeginScratchNoConflict();
PERSIST Readonly u32 font_codes[] = {
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,
0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,
0x3C,0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,
0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,0x60,0x61,0x62,0x63,0x64,0x65,
0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,0x70,0x71,0x72,0x73,
0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,0x80,0x81,
0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,
0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,
0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,
0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,
0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,
0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,
0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,
0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
};
ResourceKey resource = sig->resource;
String name = NameFromResource(resource);
f32 font_size = sig->size;
f32 em_size = font_size * (3.0 / 4.0);
AC_Asset *asset = sig->asset;
LogInfoF("Loading font \"%F\" (font size: %F, em size: %F)", FmtString(name), FmtFloat((f64)font_size), FmtFloat((f64)em_size));
i64 start_ns = TimeNs();
Assert(StringEndsWith(name, Lit(".ttf")));
Assert(countof(font_codes) < F_LookupTableSize);
/* Decode */
String resource_data = DataFromResource(resource);
if (resource_data.len == 0)
{
/* FIME: Load baked font instead of panicking */
Panic(StringF(scratch.arena,
"Font \"%F\" not found",
FmtString(name)));
}
TTF_Decoded decoded = TTF_Decode(scratch.arena, resource_data, em_size, font_codes, countof(font_codes));
/* Upload texture to GPU */
Fence completion_fence = ZI;
{
GPU_CommandList *cl = GPU_BeginCommandList(GPU_QueueKind_BackgroundCopy);
GPU_Arena *gpu_temp = GPU_AcquireArena();
{
GpuTexture gpu_texture = ZI;
{
GPU_Arena *gpu_perm = GPU_Perm();
GPU_ResourceDesc desc = ZI;
desc.texture.format = GPU_Format_R8G8B8A8_Unorm_Srgb;
desc.texture.size = VEC3I32(decoded.image_width, decoded.image_height, 1);
gpu_texture = GPU_PushTexture(gpu_perm, GPU_TextureKind_2D, desc);
}
texture->gpu_texture = gpu_texture;
texture->width = decoded.width;
texture->height = decoded.height;
GpuBuffer src_buff = GPU_PushBuffer(gpu_temp, GPU_GetFootprintSize(gpu_texture), GPU_BufferFlag_CpuWritable);
GpuAddress src_addr = ZI;
{
u32 *p = GPU_PushStructsNoZero(src_buff, u32, decoded.width * decoded.height);
CopyStructs(p, decoded.pixels, decoded.width * decoded.heigth);
GPU_TransitionBufferToCopySrc(src_buff);
GPU_TransitionTextureToCopyDst(gpu_texture);
GPU_CopyBytesToFootprint(gpu_texture, src_buff, src_addr, decoded.width * decoded.height * 4);
GPU_TransitionTextureToReadonly(gpu_texture);
}
GPU_SetFence(&completion_fence, 1);
}
GPU_ReleaseArena(gpu_temp);
GPU_EndCommandList(cl);
}
/* Acquire store memory */
F_Font *font = 0;
{
AC_Store store = AC_OpenStore();
font = PushStruct(store.arena, F_Font);
font->glyphs = PushStructsNoZero(store.arena, F_Glyph, decoded.glyphs_count);
font->lookup = PushStructs(store.arena, u16, F_LookupTableSize);
AC_CloseStore(&store);
}
/* Set font data */
font->texture = texture;
font->image_width = decoded.image_width;
font->image_height = decoded.image_height;
font->glyphs_count = decoded.glyphs_count;
font->size = font_size;
font->ascent = decoded.ascent;
font->descent = decoded.descent;
font->cap = decoded.cap;
/* FIXME: Load baked font instead of panicking */
if (font->glyphs_count <= 0)
{
Panic(StringF(scratch.arena,
"Parsed 0 glyphs from font \"%F\"!",
FmtString(name)));
}
/* Copy glyphs from decode decoded */
/* NOTE: Font glyph size must match TTF glyph size for memcpy */
StaticAssert(sizeof(*font->glyphs) == sizeof(*decoded.glyphs));
CopyBytes(font->glyphs, decoded.glyphs, sizeof(*font->glyphs) * decoded.glyphs_count);
/* Build lookup table */
for (u64 i = 0; i < countof(font_codes); ++i)
{
u32 codepoint = font_codes[i];
font->lookup[codepoint] = decoded.cache_indices[i];
}
YieldOnFence(&completion_fence, 1);
LogSuccessF("Loaded font \"%F\" (font size: %F, em size: %F) in %F seconds", FmtString(name), FmtFloat((f64)font_size), FmtFloat((f64)em_size), FmtFloat(SecondsFromNs(TimeNs() - start_ns)));
AC_MarkReady(asset, font);
EndScratch(scratch);
}
////////////////////////////////////////////////////////////
//~ Font load operations
/* Returns the asset from the asset cache */
AC_Asset *F_LoadAsset(ResourceKey resource, f32 size, b32 wait)
{
TempArena scratch = BeginScratchNoConflict();
String name = NameFromResource(resource);
/* Concatenate size to name for key */
String key = StringF(scratch.arena,
"%F%F_font",
FmtString(name),
FmtFloatP((f64)size, 1));
u64 hash = AC_HashFromKey(key);
b32 is_first_touch;
AC_Asset *asset = AC_TouchCache(key, hash, &is_first_touch);
if (is_first_touch)
{
AC_MarkLoading(asset);
{
Job *job = OpenJob(F_Load, AsyncPool());
F_Load_Sig *sig = PushStruct(job->arena, F_Load_Sig);
job->sig = sig;
sig->asset = asset;
sig->resource = resource;
sig->size = size;
CloseJob(job);
}
if (wait)
{
AC_YieldOnAssetReady(asset);
}
}
EndScratch(scratch);
return asset;
}
F_Font *F_LoadFontAsync(ResourceKey resource, f32 point_size)
{
AC_Asset *asset = F_LoadAsset(resource, point_size, 0);
F_Font *f = (F_Font *)AC_DataFromStore(asset);
return f;
}
F_Font *F_LoadFontWait(ResourceKey resource, f32 point_size)
{
AC_Asset *asset = F_LoadAsset(resource, point_size, 1);
AC_YieldOnAssetReady(asset);
F_Font *f = (F_Font *)AC_DataFromStore(asset);
return f;
}
////////////////////////////////////////////////////////////
//~ Font data operations
F_Glyph F_GlyphFromCodepoint(F_Font *font, u32 codepoint)
{
if (codepoint < F_LookupTableSize)
{
u16 index = font->lookup[codepoint];
if (index < font->glyphs_count)
{
return font->glyphs[index];
}
}
if (codepoint == '?')
{
return font->glyphs[font->lookup[0]];
}
else
{
return font->glyphs[font->lookup['?']];
}
}
F_Run F_RunFromString(Arena *arena, F_Font *font, String str)
{
F_Run result = ZI;
result.rects = ArenaNext(arena, F_RunRect);
f32 baseline_length = 0;
for (CodepointIter it = InitCodepointIter(str); NextCodepoint(&it);)
{
u32 codepoint = it.codepoint;
if (font->glyphs_count <= codepoint)
{
codepoint = '?';
}
if (codepoint < font->glyphs_count)
{
u16 index = font->lookup[codepoint];
F_Glyph glyph = font->glyphs[index];
F_RunRect *rect = PushStruct(arena, F_RunRect);
++result.count;
rect->atlas_p0 = glyph.atlas_p0;
rect->atlas_p1 = glyph.atlas_p1;
Vec2I32 size = SubVec2I32(glyph.atlas_p1, glyph.atlas_p0);
rect->pos = baseline_length;
rect->offset = glyph.baseline_offset;
rect->advance = glyph.advance;
result.p0.x = MinF32(result.p0.x, rect->offset.x + rect->pos); /* Left run bounds */
result.p1.x = MaxF32(result.p1.x, rect->offset.x + rect->pos + size.x); /* Right run bounds */
result.p0.y = MinF32(result.p0.y, rect->offset.y); /* Top run bounds */
result.p1.y = MaxF32(result.p1.y, rect->offset.y + size.y); /* Bottom run bounds */
baseline_length += rect->advance;
}
}
return result;
}

View File

@ -1,66 +0,0 @@
////////////////////////////////////////////////////////////
//~ Font types
#define F_LookupTableSize (256)
Struct(F_Glyph)
{
i32 advance;
Vec2 baseline_offset;
Vec2I32 atlas_p0;
Vec2I32 atlas_p1;
};
Struct(F_Font)
{
GPU_Resource *texture;
u32 image_width;
u32 image_height;
u16 glyphs_count;
F_Glyph *glyphs;
u16 *lookup;
/* Metrics */
f32 size;
f32 ascent;
f32 descent;
f32 cap;
};
////////////////////////////////////////////////////////////
//~ Run types
Struct(F_RunRect)
{
Vec2 offset; /* Vector from baseline offset to top left of glyph rect */
f32 pos; /* Horizontal distance from start of baseline */
f32 advance;
Vec2I32 atlas_p0;
Vec2I32 atlas_p1;
};
Struct(F_Run)
{
Vec2 p0; /* Start of baseline to top-left-most rect */
Vec2 p1; /* Start of baseline to bottom-right-most rect corner */
u32 count;
F_RunRect *rects;
};
////////////////////////////////////////////////////////////
//~ Font load job
JobDecl(F_Load, { AC_Asset *asset; f32 size; ResourceKey resource; });
////////////////////////////////////////////////////////////
//~ Font load operations
AC_Asset *F_LoadAsset(ResourceKey resource, f32 size, b32 wait);
F_Font *F_LoadFontAsync(ResourceKey resource, f32 size);
F_Font *F_LoadFontWait(ResourceKey resource, f32 size);
////////////////////////////////////////////////////////////
//~ Run operations
F_Glyph F_GlyphFromCodepoint(F_Font *font, u32 codepoint);
F_Run F_RunFromString(Arena *arena, F_Font *font, String str);

View File

@ -1,12 +0,0 @@
@Layer font
//- Dependencies
@Dep ttf
@Dep gpu
@Dep asset_cache
//- Api
@IncludeC font.h
//- Impl
@IncludeC font.c

View File

@ -0,0 +1,297 @@
/* TODO: Use default font texture handle */
Readonly GC_RunRect GC_NilRunRect = {
0
};
Readonly GC_Run GC_NilRun = {
.count = 1,
.rects = &GC_NilRunRect
};
////////////////////////////////////////////////////////////
//~ Key helpers
GC_FontKey GC_FontKeyFromResource(ResourceKey resource)
{
GC_FontKey result = ZI;
result.v = resource.v;
return result;
}
////////////////////////////////////////////////////////////
//~ Run
GC_Run *GC_RunFromString(Arena *arena, GC_FontKey key, String str)
{
/* TODO */
GC_Run *result = 0;
GC_RunRect *rr = PushStruct(arena, GC_RunRect);
rr->advance = 1;
result->rects = rr;
result->count = 1;
return result;
}
// ////////////////////////////////////////////////////////////
// //~ Font load job
// JobImpl(F_Load, sig, _)
// {
// TempArena scratch = BeginScratchNoConflict();
// PERSIST Readonly u32 font_codes[] = {
// 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,
// 0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,
// 0x3C,0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,
// 0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
// 0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,0x60,0x61,0x62,0x63,0x64,0x65,
// 0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,0x70,0x71,0x72,0x73,
// 0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,0x80,0x81,
// 0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
// 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,
// 0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,
// 0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,
// 0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,
// 0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,
// 0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,
// 0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,
// 0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
// };
// ResourceKey resource = sig->resource;
// String name = NameFromResource(resource);
// f32 font_size = sig->size;
// f32 em_size = font_size * (3.0 / 4.0);
// AC_Asset *asset = sig->asset;
// LogInfoF("Loading font \"%F\" (font size: %F, em size: %F)", FmtString(name), FmtFloat((f64)font_size), FmtFloat((f64)em_size));
// i64 start_ns = TimeNs();
// Assert(StringEndsWith(name, Lit(".ttf")));
// Assert(countof(font_codes) < F_LookupTableSize);
// /* Decode */
// String resource_data = DataFromResource(resource);
// if (resource_data.len == 0)
// {
// /* FIME: Load baked font instead of panicking */
// Panic(StringF(scratch.arena,
// "Font \"%F\" not found",
// FmtString(name)));
// }
// TTF_Decoded decoded = TTF_Decode(scratch.arena, resource_data, em_size, font_codes, countof(font_codes));
// /* Upload texture to GPU */
// Fence completion_fence = ZI;
// {
// GPU_CommandList *cl = GPU_BeginCommandList(GPU_QueueKind_BackgroundCopy);
// GPU_Arena *gpu_temp = GPU_AcquireArena();
// {
// GpuTexture gpu_texture = ZI;
// {
// GPU_Arena *gpu_perm = GPU_Perm();
// GPU_ResourceDesc desc = ZI;
// desc.texture.format = GPU_Format_R8G8B8A8_Unorm_Srgb;
// desc.texture.size = VEC3I32(decoded.image_width, decoded.image_height, 1);
// gpu_texture = GPU_PushTexture(gpu_perm, GPU_TextureKind_2D, desc);
// }
// texture->gpu_texture = gpu_texture;
// texture->width = decoded.width;
// texture->height = decoded.height;
// GpuBuffer src_buff = GPU_PushBuffer(gpu_temp, GPU_GetFootprintSize(gpu_texture), GPU_BufferFlag_CpuWritable);
// GpuAddress src_addr = ZI;
// {
// u32 *p = GPU_PushStructsNoZero(src_buff, u32, decoded.width * decoded.height);
// CopyStructs(p, decoded.pixels, decoded.width * decoded.heigth);
// GPU_TransitionBufferToCopySrc(src_buff);
// GPU_TransitionTextureToCopyDst(gpu_texture);
// GPU_CopyBytesToFootprint(gpu_texture, src_buff, src_addr, decoded.width * decoded.height * 4);
// GPU_TransitionTextureToReadonly(gpu_texture);
// }
// GPU_SetFence(&completion_fence, 1);
// }
// GPU_ReleaseArena(gpu_temp);
// GPU_EndCommandList(cl);
// }
// /* Acquire store memory */
// F_Font *font = 0;
// {
// AC_Store store = AC_OpenStore();
// font = PushStruct(store.arena, F_Font);
// font->glyphs = PushStructsNoZero(store.arena, F_Glyph, decoded.glyphs_count);
// font->lookup = PushStructs(store.arena, u16, F_LookupTableSize);
// AC_CloseStore(&store);
// }
// /* Set font data */
// font->texture = texture;
// font->image_width = decoded.image_width;
// font->image_height = decoded.image_height;
// font->glyphs_count = decoded.glyphs_count;
// font->size = font_size;
// font->ascent = decoded.ascent;
// font->descent = decoded.descent;
// font->cap = decoded.cap;
// /* FIXME: Load baked font instead of panicking */
// if (font->glyphs_count <= 0)
// {
// Panic(StringF(scratch.arena,
// "Parsed 0 glyphs from font \"%F\"!",
// FmtString(name)));
// }
// /* Copy glyphs from decode decoded */
// /* NOTE: Font glyph size must match TTF glyph size for memcpy */
// StaticAssert(sizeof(*font->glyphs) == sizeof(*decoded.glyphs));
// CopyBytes(font->glyphs, decoded.glyphs, sizeof(*font->glyphs) * decoded.glyphs_count);
// /* Build lookup table */
// for (u64 i = 0; i < countof(font_codes); ++i)
// {
// u32 codepoint = font_codes[i];
// font->lookup[codepoint] = decoded.cache_indices[i];
// }
// YieldOnFence(&completion_fence, 1);
// LogSuccessF("Loaded font \"%F\" (font size: %F, em size: %F) in %F seconds", FmtString(name), FmtFloat((f64)font_size), FmtFloat((f64)em_size), FmtFloat(SecondsFromNs(TimeNs() - start_ns)));
// AC_MarkReady(asset, font);
// EndScratch(scratch);
// }
// ////////////////////////////////////////////////////////////
// //~ Font load operations
// /* Returns the asset from the asset cache */
// AC_Asset *F_LoadAsset(ResourceKey resource, f32 size, b32 wait)
// {
// TempArena scratch = BeginScratchNoConflict();
// String name = NameFromResource(resource);
// /* Concatenate size to name for key */
// String key = StringF(scratch.arena,
// "%F%F_font",
// FmtString(name),
// FmtFloatP((f64)size, 1));
// u64 hash = AC_HashFromKey(key);
// b32 is_first_touch;
// AC_Asset *asset = AC_TouchCache(key, hash, &is_first_touch);
// if (is_first_touch)
// {
// AC_MarkLoading(asset);
// {
// Job *job = OpenJob(F_Load, AsyncPool());
// F_Load_Sig *sig = PushStruct(job->arena, F_Load_Sig);
// job->sig = sig;
// sig->asset = asset;
// sig->resource = resource;
// sig->size = size;
// CloseJob(job);
// }
// if (wait)
// {
// AC_YieldOnAssetReady(asset);
// }
// }
// EndScratch(scratch);
// return asset;
// }
// F_Font *F_LoadFontAsync(ResourceKey resource, f32 point_size)
// {
// AC_Asset *asset = F_LoadAsset(resource, point_size, 0);
// F_Font *f = (F_Font *)AC_DataFromStore(asset);
// return f;
// }
// F_Font *F_LoadFontWait(ResourceKey resource, f32 point_size)
// {
// AC_Asset *asset = F_LoadAsset(resource, point_size, 1);
// AC_YieldOnAssetReady(asset);
// F_Font *f = (F_Font *)AC_DataFromStore(asset);
// return f;
// }
// ////////////////////////////////////////////////////////////
// //~ Font data operations
// F_Glyph F_GlyphFromCodepoint(F_Font *font, u32 codepoint)
// {
// if (codepoint < F_LookupTableSize)
// {
// u16 index = font->lookup[codepoint];
// if (index < font->glyphs_count)
// {
// return font->glyphs[index];
// }
// }
// if (codepoint == '?')
// {
// return font->glyphs[font->lookup[0]];
// }
// else
// {
// return font->glyphs[font->lookup['?']];
// }
// }
// F_Run F_RunFromString(Arena *arena, F_Font *font, String str)
// {
// F_Run result = ZI;
// result.rects = ArenaNext(arena, F_RunRect);
// f32 baseline_length = 0;
// for (CodepointIter it = InitCodepointIter(str); NextCodepoint(&it);)
// {
// u32 codepoint = it.codepoint;
// if (font->glyphs_count <= codepoint)
// {
// codepoint = '?';
// }
// if (codepoint < font->glyphs_count)
// {
// u16 index = font->lookup[codepoint];
// F_Glyph glyph = font->glyphs[index];
// F_RunRect *rect = PushStruct(arena, F_RunRect);
// ++result.count;
// rect->atlas_p0 = glyph.atlas_p0;
// rect->atlas_p1 = glyph.atlas_p1;
// Vec2I32 size = SubVec2I32(glyph.atlas_p1, glyph.atlas_p0);
// rect->pos = baseline_length;
// rect->offset = glyph.baseline_offset;
// rect->advance = glyph.advance;
// result.p0.x = MinF32(result.p0.x, rect->offset.x + rect->pos); /* Left run bounds */
// result.p1.x = MaxF32(result.p1.x, rect->offset.x + rect->pos + size.x); /* Right run bounds */
// result.p0.y = MinF32(result.p0.y, rect->offset.y); /* Top run bounds */
// result.p1.y = MaxF32(result.p1.y, rect->offset.y + size.y); /* Bottom run bounds */
// baseline_length += rect->advance;
// }
// }
// return result;
// }

View File

@ -0,0 +1,140 @@
////////////////////////////////////////////////////////////
//~ Key types
Struct(GC_FontKey)
{
u64 v;
};
////////////////////////////////////////////////////////////
//~ Run types
Struct(GC_RunRect)
{
Vec2 offset; /* Vector from baseline offset to top left of glyph rect */
f32 pos; /* Horizontal distance from start of baseline */
f32 advance;
Vec2 size;
Texture2DHandle tex;
Rng2 uv;
};
Struct(GC_Run)
{
/* Run data */
Vec2 p0; /* Start of baseline to top-left-most rect */
Vec2 p1; /* Start of baseline to bottom-right-most rect corner */
u32 count;
GC_RunRect *rects;
/* Font stats */
f32 size;
f32 ascent;
f32 descent;
f32 cap;
b32 loaded;
};
extern Readonly GC_RunRect GC_NilRunRect;
extern Readonly GC_Run GC_NilRun;
////////////////////////////////////////////////////////////
//~ Key helpers
GC_FontKey GC_FontKeyFromResource(ResourceKey resource);
////////////////////////////////////////////////////////////
//~ Run
GC_Run *GC_RunFromString(Arena *arena, GC_FontKey key, String str);
// ////////////////////////////////////////////////////////////
// //~ Font types
// Struct(GC_FontKey)
// {
// u64 v;
// };
// Struct(GC_Glyph)
// {
// i32 advance;
// Vec2 baseline_offset;
// Vec2I32 atlas_p0;
// Vec2I32 atlas_p1;
// };
// Struct(GC_Font)
// {
// GPU_Resource *texture;
// u32 image_width;
// u32 image_height;
// u16 glyphs_count;
// F_Glyph *glyphs;
// u16 *lookup;
// /* Metrics */
// f32 size;
// f32 ascent;
// f32 descent;
// f32 cap;
// };
// ////////////////////////////////////////////////////////////
// //~ Run types
// Struct(F_RunRect)
// {
// Vec2 offset; /* Vector from baseline offset to top left of glyph rect */
// f32 pos; /* Horizontal distance from start of baseline */
// f32 advance;
// Vec2I32 atlas_p0;
// Vec2I32 atlas_p1;
// };
// Struct(F_Run)
// {
// Vec2 p0; /* Start of baseline to top-left-most rect */
// Vec2 p1; /* Start of baseline to bottom-right-most rect corner */
// u32 count;
// F_RunRect *rects;
// };
// ////////////////////////////////////////////////////////////
// //~ Font load job
// JobDecl(F_Load, { AC_Asset *asset; f32 size; ResourceKey resource; });
// ////////////////////////////////////////////////////////////
// //~ Font load operations
// AC_Asset *F_LoadAsset(ResourceKey resource, f32 size, b32 wait);
// F_Font *F_LoadFontAsync(ResourceKey resource, f32 size);
// F_Font *F_LoadFontWait(ResourceKey resource, f32 size);
// ////////////////////////////////////////////////////////////
// //~ Run operations
// F_Glyph F_GlyphFromCodepoint(F_Font *font, u32 codepoint);
// F_Run F_RunFromString(Arena *arena, F_Font *font, String str);

View File

@ -0,0 +1,11 @@
@Layer glyph_cache
//- Dependencies
@Dep ttf
@Dep gpu
//- Api
@IncludeC glyph_cache.h
//- Impl
@IncludeC glyph_cache.c

View File

@ -1,7 +1,6 @@
@Layer gpu @Layer gpu
//- Dependencies //- Dependencies
@Dep window
@Dep platform @Dep platform
//- Api //- Api

View File

@ -50,47 +50,12 @@ void GPU_StartupCommon(void)
GPU_CommitCommandList(cl); GPU_CommitCommandList(cl);
GPU_SyncAllQueues(GPU_QueueKind_Direct); GPU_SyncAllQueues(GPU_QueueKind_Direct);
// GPU_CommandListHandle cl = GPU_PrepareCommandList();
// {
// /* Init noise texture */
// String noise_data = DataFromResource(ResourceKeyFromStore(&GPU_Resources, Lit("noise_128x128x64_16.dat")));
// Vec3I32 noise_dims = VEC3I32(128, 128, 64);
// GPU_ResourceHandle noise_tex = ZI;
// {
// if (noise_data.len != noise_dims.x * noise_dims.y * noise_dims.z * 2)
// {
// Panic(Lit("Unexpected noise texture size"));
// }
// noise_tex = GPU_PushTexture3D(gpu_perm, noise_dims, GPU_Format_R16_Uint, GPU_AccessKind_CopyWrite);
// GPU_CopyResourceFromCpu(cl, noise_tex, noise_data);
// }
// /* Init quad index buffer */
// GPU_ResourceHandle quad_indices = ZI;
// {
// u16 quad_data[6] = { 0, 1, 2, 0, 2, 3 };
// quad_indices = GPU_PushBuffer(gpu_perm, u16, GPU_AccessKind_CopyWrite);
// GPU_CopyResourceFromCpu(cl, quad_indices, StringFromArray(quad_data));
// }
// g->noise_tex = GPU_PushTexture3DPtr(gpu_perm, noise_tex);
// g->quad_indices = GPU_PushIndexBufferPtr(gpu_perm, quad_indices, u16);
// /* FIXME: Block other queues until common startup finishes here */
// GPU_SyncAccess(cl, noise_tex, GPU_AccessKind_AnyRead);
// GPU_SyncAccess(cl, quad_indices, GPU_AccessKind_AnyRead);
// }
// GPU_CommitCommandList(cl, GPU_QueueKind_Direct);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Arena helpers //~ Helpers
//- Arena
GPU_ArenaHandle GPU_PermArena(void) GPU_ArenaHandle GPU_PermArena(void)
{ {
@ -103,28 +68,49 @@ GPU_ArenaHandle GPU_PermArena(void)
return perm; return perm;
} }
//////////////////////////////////////////////////////////// //- Cpu -> Gpu copy
//~ Cpu -> Gpu copy helpers
void GPU_CopyResourceFromCpu(GPU_CommandListHandle cl, GPU_ResourceHandle dst, String src) StructuredBufferHandle GPU_PushStructuredBufferFromCpu_(GPU_ArenaHandle gpu_arena, GPU_CommandListHandle cl, void *src, u32 element_size, u32 element_count)
{ {
/* TODO */ u64 size = (u64)element_size * (u64)element_count;
GPU_ResourceHandle buffer = GPU_PushBufferEx(gpu_arena, (GPU_BufferDesc) { .size = size });
GPU_CopyCpuToBuffer(cl, buffer, 0, src, RNGU64(0, size));
StructuredBufferHandle structured_buffer = GPU_PushStructuredBufferHandleEx(gpu_arena, buffer, element_size, RNGU32(0, element_count));
GPU_MemorySync(
cl, buffer,
GPU_Stage_None, GPU_Access_None,
GPU_Stage_AllShading, GPU_Access_ShaderRead
);
return structured_buffer;
} }
//////////////////////////////////////////////////////////// //- Viewport / scissor
//~ Common resource helpers
SamplerStateHandle GPU_GetCommonPointSampler(void) Rng3 GPU_ViewportFromTexture(GPU_ResourceHandle texture)
{
Vec2I32 dims = GPU_Count2D(texture);
return RNG3(VEC3(0, 0, 0), VEC3(dims.x, dims.y, 1));
}
Rng2 GPU_ScissorFromTexture(GPU_ResourceHandle texture)
{
Vec2I32 dims = GPU_Count2D(texture);
return RNG2(VEC2(0, 0), VEC2(dims.x, dims.y));
}
//- Shared resources
SamplerStateHandle GPU_GetSharedPointSampler(void)
{ {
return GPU_shared_util_state.pt_sampler; return GPU_shared_util_state.pt_sampler;
} }
GPU_IndexBufferDesc GPU_GetCommonQuadIndices(void) GPU_IndexBufferDesc GPU_GetSharedQuadIndices(void)
{ {
return GPU_shared_util_state.quad_indices; return GPU_shared_util_state.quad_indices;
} }
Texture3DHandle GPU_GetCommonNoise(void) Texture3DHandle GPU_GetSharedNoise(void)
{ {
return GPU_shared_util_state.noise_tex; return GPU_shared_util_state.noise_tex;
} }

View File

@ -17,18 +17,25 @@ extern ThreadLocal GPU_ArenaHandle GPU_t_perm_arena;
void GPU_StartupCommon(void); void GPU_StartupCommon(void);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Arena helpers //~ Helpers
//- Arena
GPU_ArenaHandle GPU_PermArena(void); GPU_ArenaHandle GPU_PermArena(void);
//////////////////////////////////////////////////////////// //- Cpu -> Gpu copy
//~ Cpu -> Gpu copy helpers
void GPU_CopyResourceFromCpu(GPU_CommandListHandle cl, GPU_ResourceHandle dst, String src); StructuredBufferHandle GPU_PushStructuredBufferFromCpu_(GPU_ArenaHandle gpu_arena, GPU_CommandListHandle cl, void *src, u32 element_size, u32 element_count);
#define GPU_PushStructuredBufferFromCpu(gpu_arena, cl, ptr, count) \
GPU_PushStructuredBufferFromCpu_((gpu_arena), (cl), (ptr), sizeof(*ptr), count);
//////////////////////////////////////////////////////////// //- Viewport / scissor
//~ Common resource helpers
SamplerStateHandle GPU_GetCommonPointSampler(void); Rng3 GPU_ViewportFromTexture(GPU_ResourceHandle texture);
GPU_IndexBufferDesc GPU_GetCommonQuadIndices(void); Rng2 GPU_ScissorFromTexture(GPU_ResourceHandle texture);
Texture3DHandle GPU_GetCommonNoise(void);
//- Shared resources
SamplerStateHandle GPU_GetSharedPointSampler(void);
GPU_IndexBufferDesc GPU_GetSharedQuadIndices(void);
Texture3DHandle GPU_GetSharedNoise(void);

View File

@ -2,13 +2,15 @@
//~ Handle types //~ Handle types
Struct(GPU_ArenaHandle) { u64 v; }; Struct(GPU_ArenaHandle) { u64 v; };
Struct(GPU_CommandListHandle) { u64 v; }; Struct(GPU_CommandListHandle) { u64 v; };
Struct(GPU_ResourceHandle) { u64 v; }; Struct(GPU_ResourceHandle) { u64 v; };
Struct(GPU_SwapchainHandle) { u64 v; }; Struct(GPU_SwapchainHandle) { u64 v; };
#define GPU_IsArenaNil(h) ((h).v == 0)
#define GPU_IsCommandListNil(h) ((h).v == 0)
#define GPU_IsResourceNil(h) ((h).v == 0)
#define GPU_IsSwapchainNil(h) ((h).v == 0)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Queue types //~ Queue types
@ -493,7 +495,8 @@ void GPU_Startup(void);
GPU_ArenaHandle GPU_AcquireArena(void); GPU_ArenaHandle GPU_AcquireArena(void);
void GPU_ReleaseArena(GPU_ArenaHandle arena); void GPU_ReleaseArena(GPU_ArenaHandle arena);
b32 GPU_IsArenaNil(GPU_ArenaHandle handle); void GPU_ResetArena(GPU_CommandListHandle cl, GPU_ArenaHandle arena);
void GPU_ResetArenaFromQueue(GPU_QueueKind queue, GPU_ArenaHandle arena);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ @hookdecl Resource //~ @hookdecl Resource
@ -504,8 +507,6 @@ GPU_ResourceHandle GPU_PushBufferEx(GPU_ArenaHandle arena, GPU_BufferDesc desc);
GPU_ResourceHandle GPU_PushTextureEx(GPU_ArenaHandle arena, GPU_TextureDesc desc); GPU_ResourceHandle GPU_PushTextureEx(GPU_ArenaHandle arena, GPU_TextureDesc desc);
GPU_ResourceHandle GPU_PushSampler(GPU_ArenaHandle arena, GPU_SamplerDesc desc); GPU_ResourceHandle GPU_PushSampler(GPU_ArenaHandle arena, GPU_SamplerDesc desc);
b32 GPU_IsResourceNil(GPU_ResourceHandle handle);
#define GPU_PushBuffer(arena, type, count, ...) GPU_PushBufferEx((arena), \ #define GPU_PushBuffer(arena, type, count, ...) GPU_PushBufferEx((arena), \
(GPU_BufferDesc) { \ (GPU_BufferDesc) { \
.size = sizeof(type) * (count), \ .size = sizeof(type) * (count), \
@ -580,21 +581,17 @@ void GPU_CommitCommandListEx(GPU_CommandListHandle cl, u64 fence_ops_count, GPU_
#define GPU_CommitCommandList(cl) GPU_CommitCommandListEx((cl), 0, 0) #define GPU_CommitCommandList(cl) GPU_CommitCommandListEx((cl), 0, 0)
//- Arena
void GPU_ResetArena(GPU_CommandListHandle cl, GPU_ArenaHandle arena);
//- Cpu -> Gpu copy //- Cpu -> Gpu copy
void GPU_CopyCpuToBuffer(GPU_CommandListHandle cl_handle, GPU_ResourceHandle dst_handle, u64 dst_offset, void *src, RngU64 src_copy_range); void GPU_CopyCpuToBuffer(GPU_CommandListHandle cl, GPU_ResourceHandle dst, u64 dst_offset, void *src, RngU64 src_copy_range);
void GPU_CopyCpuToTexture(GPU_CommandListHandle cl_handle, GPU_ResourceHandle dst_handle, Vec3I32 dst_offset, void *src, Vec3I32 src_dims, Rng3I32 src_copy_range); void GPU_CopyCpuToTexture(GPU_CommandListHandle cl, GPU_ResourceHandle dst, Vec3I32 dst_offset, void *src, Vec3I32 src_dims, Rng3I32 src_copy_range);
//- Gpu <-> Gpu copy //- Gpu <-> Gpu copy
void GPU_CopyBufferToBuffer(GPU_CommandListHandle cl_handle, GPU_ResourceHandle dst_handle, u64 dst_offset, GPU_ResourceHandle src_handle, RngU64 src_copy_range); void GPU_CopyBufferToBuffer(GPU_CommandListHandle cl, GPU_ResourceHandle dst, u64 dst_offset, GPU_ResourceHandle src, RngU64 src_copy_range);
void GPU_CopyBufferToTexture(GPU_CommandListHandle cl_handle, GPU_ResourceHandle dst_handle, Vec3I32 dst_offset, GPU_ResourceHandle src_handle, Vec3I32 src_dims, Rng3I32 src_copy_range); void GPU_CopyBufferToTexture(GPU_CommandListHandle cl, GPU_ResourceHandle dst, Vec3I32 dst_offset, GPU_ResourceHandle src, Vec3I32 src_dims, Rng3I32 src_copy_range);
void GPU_CopyTextureToTexture(GPU_CommandListHandle cl_handle, GPU_ResourceHandle dst_handle, Vec3I32 dst_offset, GPU_ResourceHandle src_handle, Rng3I32 src_copy_range); void GPU_CopyTextureToTexture(GPU_CommandListHandle cl, GPU_ResourceHandle dst, Vec3I32 dst_offset, GPU_ResourceHandle src, Rng3I32 src_copy_range);
void GPU_CopyTextureToBuffer(GPU_CommandListHandle cl_handle, GPU_ResourceHandle dst_handle, Vec3I32 dst_offset, GPU_ResourceHandle src_handle, Rng3I32 src_copy_range); void GPU_CopyTextureToBuffer(GPU_CommandListHandle cl, GPU_ResourceHandle dst, Vec3I32 dst_offset, GPU_ResourceHandle src, Rng3I32 src_copy_range);
//- Constant //- Constant
@ -614,8 +611,8 @@ void GPU_BarrierEx(GPU_CommandListHandle cl, GPU_BarrierDesc desc);
GPU_BarrierEx((_cl), (GPU_BarrierDesc) { \ GPU_BarrierEx((_cl), (GPU_BarrierDesc) { \
.resource = (_resource), \ .resource = (_resource), \
.sync_prev = _sync_prev, \ .sync_prev = _sync_prev, \
.sync_next = _sync_next, \
.access_prev = _access_prev, \ .access_prev = _access_prev, \
.sync_next = _sync_next, \
.access_next = _access_next, \ .access_next = _access_next, \
}) })
@ -623,8 +620,8 @@ void GPU_BarrierEx(GPU_CommandListHandle cl, GPU_BarrierDesc desc);
GPU_BarrierEx((_cl), (GPU_BarrierDesc) { \ GPU_BarrierEx((_cl), (GPU_BarrierDesc) { \
.resource = (_resource), \ .resource = (_resource), \
.sync_prev = _sync_prev, \ .sync_prev = _sync_prev, \
.sync_next = _sync_next, \
.access_prev = _access_prev, \ .access_prev = _access_prev, \
.sync_next = _sync_next, \
.access_next = _access_next, \ .access_next = _access_next, \
.layout = _layout, \ .layout = _layout, \
}) })
@ -633,8 +630,8 @@ void GPU_BarrierEx(GPU_CommandListHandle cl, GPU_BarrierDesc desc);
GPU_BarrierEx((_cl), (GPU_BarrierDesc) { \ GPU_BarrierEx((_cl), (GPU_BarrierDesc) { \
.is_global = 1, \ .is_global = 1, \
.sync_prev = _sync_prev, \ .sync_prev = _sync_prev, \
.sync_next = _sync_next, \
.access_prev = _access_prev, \ .access_prev = _access_prev, \
.sync_next = _sync_next, \
.access_next = _access_next, \ .access_next = _access_next, \
}) })
@ -653,30 +650,13 @@ void GPU_Compute(GPU_CommandListHandle cl, ComputeShader cs, Vec3I32 groups);
//- Rasterize //- Rasterize
void GPU_RasterizeEx(GPU_CommandListHandle cl, void GPU_Rasterize(GPU_CommandListHandle cl,
VertexShader vs, PixelShader ps, VertexShader vs, PixelShader ps,
u32 instances_count, GPU_IndexBufferDesc index_buffer, u32 instances_count, GPU_IndexBufferDesc index_buffer,
u32 render_targets_count, GPU_ResourceHandle *render_targets, u32 render_targets_count, GPU_ResourceHandle *render_targets,
Rng3 viewport, Rng2 scissor, Rng3 viewport, Rng2 scissor,
GPU_RasterMode mode); GPU_RasterMode mode);
#define GPU_Rasterize(cl, vs, ps, instances_count, index_buffer, render_target, mode) \
GPU_RasterizeEx( \
(cl), \
(vs), (ps), \
(instances_count), (index_buffer), \
1, &(render_target), \
RNG3( \
VEC3(0, 0, 0), \
VEC3(GPU_CountWidth(render_target), GPU_CountHeight(render_target), 1) \
), \
RNG2( \
VEC2(0, 0), \
Vec2FromVec(GPU_Count2D(render_target)) \
), \
(mode) \
)
//- Clear //- Clear
void GPU_ClearRenderTarget(GPU_CommandListHandle cl, GPU_ResourceHandle render_target, Vec4 color); void GPU_ClearRenderTarget(GPU_CommandListHandle cl, GPU_ResourceHandle render_target, Vec4 color);
@ -698,7 +678,7 @@ GPU_Stats GPU_QueryStats(void);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ @hookdecl Swapchain //~ @hookdecl Swapchain
GPU_SwapchainHandle GPU_AcquireSwapchain(WND_Handle window); GPU_SwapchainHandle GPU_AcquireSwapchain(u64 os_window_handle);
void GPU_ReleaseSwapchain(GPU_SwapchainHandle swapchain); void GPU_ReleaseSwapchain(GPU_SwapchainHandle swapchain);
/* Waits until a new backbuffer is ready from the swapchain. /* Waits until a new backbuffer is ready from the swapchain.

View File

@ -761,9 +761,25 @@ void GPU_ReleaseArena(GPU_ArenaHandle arena)
/* TODO */ /* TODO */
} }
b32 GPU_IsArenaNil(GPU_ArenaHandle handle) void GPU_ResetArena(GPU_CommandListHandle cl_handle, GPU_ArenaHandle arena_handle)
{ {
return handle.v == 0; GPU_D12_Arena *gpu_arena = GPU_D12_ArenaFromHandle(arena_handle);
/* TODO */
/* FIXME: Move descriptors into committed lists */
/* FIXME: Release id3d12 resource com object references */
gpu_arena->heap_pos = 0;
}
void GPU_ResetArenaFromQueue(GPU_QueueKind queue_kind, GPU_ArenaHandle arena_handle)
{
GPU_D12_Arena *gpu_arena = GPU_D12_ArenaFromHandle(arena_handle);
/* TODO */
gpu_arena->heap_pos = 0;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -1042,11 +1058,6 @@ GPU_ResourceHandle GPU_PushSampler(GPU_ArenaHandle arena_handle, GPU_SamplerDesc
return GPU_D12_MakeHandle(GPU_ResourceHandle, resource); return GPU_D12_MakeHandle(GPU_ResourceHandle, resource);
} }
b32 GPU_IsResourceNil(GPU_ResourceHandle handle)
{
return handle.v == 0;
}
//- Pointer creation //- Pointer creation
StructuredBufferHandle GPU_PushStructuredBufferHandleEx(GPU_ArenaHandle arena_handle, GPU_ResourceHandle resource_handle, u32 element_size, RngU32 element_range) StructuredBufferHandle GPU_PushStructuredBufferHandleEx(GPU_ArenaHandle arena_handle, GPU_ResourceHandle resource_handle, u32 element_size, RngU32 element_range)
@ -1529,7 +1540,7 @@ void GPU_CommitCommandListEx(GPU_CommandListHandle cl_handle, u64 fence_ops_coun
u64 slotted_constants[MaxShaderConstants]; u64 slotted_constants[MaxShaderConstants];
u64 bound_compute_constants[MaxShaderConstants]; u64 bound_compute_constants[MaxShaderConstants];
u64 bound_graphics_constants[MaxShaderConstants]; u64 bound_graphics_constants[MaxShaderConstants];
for (i32 i = 0; i < countof(slotted_constants); ++i) { slotted_constants[i] = U64Max; } for (i32 i = 0; i < countof(slotted_constants); ++i) { slotted_constants[i] = 0; } /* Zero initialze all constant slots */
for (i32 i = 0; i < countof(bound_compute_constants); ++i) { bound_compute_constants[i] = U64Max; } for (i32 i = 0; i < countof(bound_compute_constants); ++i) { bound_compute_constants[i] = U64Max; }
for (i32 i = 0; i < countof(bound_graphics_constants); ++i) { bound_graphics_constants[i] = U64Max; } for (i32 i = 0; i < countof(bound_graphics_constants); ++i) { bound_graphics_constants[i] = U64Max; }
@ -2117,20 +2128,6 @@ void GPU_CommitCommandListEx(GPU_CommandListHandle cl_handle, u64 fence_ops_coun
EndScratch(scratch); EndScratch(scratch);
} }
//- Arena
void GPU_ResetArena(GPU_CommandListHandle cl_handle, GPU_ArenaHandle arena_handle)
{
GPU_D12_Arena *gpu_arena = GPU_D12_ArenaFromHandle(arena_handle);
/* TODO */
/* FIXME: Move descriptors into committed lists */
/* FIXME: Release id3d12 resource com object references */
gpu_arena->heap_pos = 0;
}
//- Cpu -> Gpu copy //- Cpu -> Gpu copy
void GPU_CopyCpuToBuffer(GPU_CommandListHandle cl_handle, GPU_ResourceHandle dst_handle, u64 dst_offset, void *src, RngU64 src_copy_range) void GPU_CopyCpuToBuffer(GPU_CommandListHandle cl_handle, GPU_ResourceHandle dst_handle, u64 dst_offset, void *src, RngU64 src_copy_range)
@ -2331,7 +2328,7 @@ void GPU_Compute(GPU_CommandListHandle cl_handle, ComputeShader cs, Vec3I32 grou
//- Rasterize //- Rasterize
void GPU_RasterizeEx(GPU_CommandListHandle cl_handle, void GPU_Rasterize(GPU_CommandListHandle cl_handle,
VertexShader vs, PixelShader ps, VertexShader vs, PixelShader ps,
u32 instances_count, GPU_IndexBufferDesc index_buffer, u32 instances_count, GPU_IndexBufferDesc index_buffer,
u32 render_targets_count, GPU_ResourceHandle *render_targets, u32 render_targets_count, GPU_ResourceHandle *render_targets,
@ -2500,14 +2497,14 @@ GPU_Stats GPU_QueryStats(void)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ @hookimpl Swapchain //~ @hookimpl Swapchain
GPU_SwapchainHandle GPU_AcquireSwapchain(WND_Handle window) GPU_SwapchainHandle GPU_AcquireSwapchain(u64 os_window_handle)
{ {
GPU_D12_Swapchain *swapchain = 0; GPU_D12_Swapchain *swapchain = 0;
{ {
Arena *perm = PermArena(); Arena *perm = PermArena();
swapchain = PushStruct(perm, GPU_D12_Swapchain); swapchain = PushStruct(perm, GPU_D12_Swapchain);
} }
swapchain->window_hwnd = (HWND)WND_OsHandleFromWindow(window); swapchain->window_hwnd = (HWND)os_window_handle;
return GPU_D12_MakeHandle(GPU_SwapchainHandle, swapchain); return GPU_D12_MakeHandle(GPU_SwapchainHandle, swapchain);
} }

View File

@ -2,7 +2,6 @@
//- Dependencies //- Dependencies
@Dep gpu @Dep gpu
@Dep sprite
@Dep font @Dep font
@Dep platform @Dep platform
@Dep window @Dep window

View File

@ -198,8 +198,8 @@ JobImpl(V_VisWorker, _, __)
Vec4 swapchain_color = V_GetWidgetTheme().window_background_color; Vec4 swapchain_color = V_GetWidgetTheme().window_background_color;
ui_frame_flags |= UI_FrameFlag_Debug * !!persist.ui_debug; ui_frame_flags |= UI_FrameFlag_Debug * !!persist.ui_debug;
ui_frame_flags |= UI_FrameFlag_Vsync * !!VSYNC; ui_frame_flags |= UI_FrameFlag_Vsync * !!VSYNC;
UI_Frame ui_frame = UI_BeginFrame(ui_frame_flags, swapchain_color); UI_Frame *ui_frame = UI_BeginFrame(ui_frame_flags, swapchain_color);
WND_Frame window_frame = ui_frame.window_frame; WND_Frame window_frame = ui_frame->window_frame;
/* Restore window */ /* Restore window */
{ {
@ -296,7 +296,7 @@ JobImpl(V_VisWorker, _, __)
} }
/* Cursors */ /* Cursors */
Vec2 ui_cursor = ui_frame.cursor_pos; Vec2 ui_cursor = ui_frame->cursor_pos;
Vec2 draw_cursor = MulXformV2(ui_to_draw_xf, ui_cursor); Vec2 draw_cursor = MulXformV2(ui_to_draw_xf, ui_cursor);
Vec2 world_cursor = MulXformV2(ui_to_world_xf, ui_cursor); Vec2 world_cursor = MulXformV2(ui_to_world_xf, ui_cursor);
@ -576,7 +576,7 @@ JobImpl(V_VisWorker, _, __)
{ {
GPU_SetConstantPtr(cl, V_DrawConst_Params, draw_params); GPU_SetConstantPtr(cl, V_DrawConst_Params, draw_params);
GPU_SetConstantPtr(cl, V_DrawConst_FinalTarget, draw_target); GPU_SetConstantPtr(cl, V_DrawConst_FinalTarget, draw_target);
GPU_SetConstantPtr(cl, V_DrawConst_Sampler, GPU_GetCommonPointSampler()); GPU_SetConstantPtr(cl, V_DrawConst_Sampler, GPU_GetSharedPointSampler());
GPU_SetConstantPtr(cl, V_DrawConst_DVerts, dverts); GPU_SetConstantPtr(cl, V_DrawConst_DVerts, dverts);
/* Backdrop pass */ /* Backdrop pass */

View File

@ -2,12 +2,9 @@ void PT_RunForever(WaveLaneCtx *lane)
{ {
GPU_ArenaHandle gpu_frame_arena = GPU_AcquireArena(); GPU_ArenaHandle gpu_frame_arena = GPU_AcquireArena();
b32 swapchain_initialized = 0;
GPU_SwapchainHandle swapchain = ZI;
for (;;) for (;;)
{ {
WND_Frame window_frame = WND_BeginFrame(); WND_Frame window_frame = WND_BeginFrame(GPU_Format_R16G16B16A16_Float, WND_BackbufferSizeMode_MatchWindow);
for (u64 cev_idx = 0; cev_idx < window_frame.controller_events.count; ++cev_idx) for (u64 cev_idx = 0; cev_idx < window_frame.controller_events.count; ++cev_idx)
{ {
ControllerEvent *cev = &window_frame.controller_events.events[cev_idx]; ControllerEvent *cev = &window_frame.controller_events.events[cev_idx];
@ -19,13 +16,6 @@ void PT_RunForever(WaveLaneCtx *lane)
} }
{ {
if (!swapchain_initialized)
{
swapchain_initialized = 1;
swapchain = GPU_AcquireSwapchain(window_frame.window);
}
GPU_ResourceHandle backbuffer = GPU_PrepareBackbuffer(swapchain, GPU_Format_R16G16B16A16_Float, window_frame.draw_size);
{ {
GPU_CommandListHandle cl = GPU_PrepareCommandList(GPU_QueueKind_Direct); GPU_CommandListHandle cl = GPU_PrepareCommandList(GPU_QueueKind_Direct);
{ {
@ -45,9 +35,9 @@ void PT_RunForever(WaveLaneCtx *lane)
{ {
GPU_SetConstant(cl, PT_ShaderConst_TestTarget, final_target_rwhandle); GPU_SetConstant(cl, PT_ShaderConst_TestTarget, final_target_rwhandle);
GPU_SetConstant(cl, PT_ShaderConst_TestConst, 3.123); GPU_SetConstant(cl, PT_ShaderConst_TestConst, 3.123);
GPU_SetConstant(cl, PT_ShaderConst_BlitSampler, GPU_GetCommonPointSampler()); GPU_SetConstant(cl, PT_ShaderConst_BlitSampler, GPU_GetSharedPointSampler());
GPU_SetConstant(cl, PT_ShaderConst_BlitSrc, final_target_rhandle); GPU_SetConstant(cl, PT_ShaderConst_BlitSrc, final_target_rhandle);
GPU_SetConstant(cl, PT_ShaderConst_NoiseTex, GPU_GetCommonNoise()); GPU_SetConstant(cl, PT_ShaderConst_NoiseTex, GPU_GetSharedNoise());
} }
/* Test pass */ /* Test pass */
@ -59,20 +49,22 @@ void PT_RunForever(WaveLaneCtx *lane)
/* Prep blit pass */ /* Prep blit pass */
{ {
GPU_DumbMemoryLayoutSync(cl, final_target, GPU_Layout_DirectQueue_ShaderRead); GPU_DumbMemoryLayoutSync(cl, final_target, GPU_Layout_DirectQueue_ShaderRead);
GPU_DumbMemoryLayoutSync(cl, backbuffer, GPU_Layout_DirectQueue_RenderTargetWrite); GPU_DumbMemoryLayoutSync(cl, window_frame.backbuffer, GPU_Layout_DirectQueue_RenderTargetWrite);
} }
/* Blit pass */ /* Blit pass */
{ {
GPU_Rasterize(cl, GPU_Rasterize(cl,
PT_BlitVS, PT_BlitPS, PT_BlitVS, PT_BlitPS,
1, GPU_GetCommonQuadIndices(), 1, GPU_GetSharedQuadIndices(),
backbuffer, GPU_RasterMode_TriangleList); 1, &window_frame.backbuffer,
GPU_ViewportFromTexture(window_frame.backbuffer), GPU_ScissorFromTexture(window_frame.backbuffer),
GPU_RasterMode_TriangleList);
} }
/* Finalize backbuffer layout */ /* Finalize backbuffer layout */
{ {
GPU_DumbMemoryLayoutSync(cl, backbuffer, GPU_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present); GPU_DumbMemoryLayoutSync(cl, window_frame.backbuffer, GPU_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present);
} }
/* Reset */ /* Reset */
@ -82,9 +74,8 @@ void PT_RunForever(WaveLaneCtx *lane)
} }
GPU_CommitCommandList(cl); GPU_CommitCommandList(cl);
} }
GPU_CommitBackbuffer(backbuffer, VSYNC);
} }
WND_EndFrame(window_frame); WND_EndFrame(window_frame, VSYNC);
} }
} }

View File

@ -3,6 +3,7 @@
//- Dependencies //- Dependencies
@Dep gpu @Dep gpu
@Dep window @Dep window
@Dep ui
//- Api //- Api
@IncludeC proto_shaders.h @IncludeC proto_shaders.h

View File

@ -2,19 +2,19 @@
//- Dependencies //- Dependencies
@Dep gpu @Dep gpu
@Dep font @Dep glyph_cache
@Dep window @Dep window
//- Api //- Api
@IncludeC ui_core.h @IncludeC ui_core.h
@IncludeC ui_common.h @IncludeC ui_common.h
@IncludeC ui_gpu.h @IncludeC ui_shaders.h
@IncludeGpu ui_gpu.h @IncludeGpu ui_shaders.h
//- Impl //- Impl
@IncludeC ui_core.c @IncludeC ui_core.c
@IncludeC ui_common.c @IncludeC ui_common.c
@IncludeGpu ui_gpu.hlsl @IncludeGpu ui_shaders.hlsl
//- Shaders //- Shaders
@VertexShader UI_DRectVS @VertexShader UI_DRectVS

View File

@ -4,7 +4,7 @@
UI_Key UI_BuildLabel(String text) UI_Key UI_BuildLabel(String text)
{ {
UI_Key parent = UI_UseTop(Parent); UI_Key parent = UI_UseTop(Parent);
ResourceKey font = UI_UseTop(Font); GC_FontKey font = UI_UseTop(Font);
f32 font_size = UI_UseTop(FontSize); f32 font_size = UI_UseTop(FontSize);
Vec4 tint = UI_UseTop(Tint); Vec4 tint = UI_UseTop(Tint);
UI_Alignment alignment = UI_UseTop(ChildAlignment); UI_Alignment alignment = UI_UseTop(ChildAlignment);

View File

@ -5,17 +5,14 @@ UI_State UI_state = ZI;
void UI_Startup(void) void UI_Startup(void)
{ {
/* Prefetch default font */
ResourceKey default_font = UI_GetDefaultFontResource();
F_LoadFontAsync(default_font, 16);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Font helpers //~ Font helpers
ResourceKey UI_GetDefaultFontResource(void) GC_FontKey UI_GetDefaultFont(void)
{ {
return ResourceKeyFromStore(&UI_Resources, Lit("font/proggy.ttf")); return GC_FontKeyFromResource(ResourceKeyFromStore(&UI_Resources, Lit("font/proggy.ttf")));
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -46,8 +43,8 @@ UI_Key UI_KeyF_(String fmt, ...)
UI_Key UI_TransKey(void) UI_Key UI_TransKey(void)
{ {
UI_State *g = &UI_state; UI_Frame *frame = UI_CurrentFrame();
u64 seed = ++g->bframe.transient_key_seed; u64 seed = ++frame->transient_key_seed;
UI_Key key = ZI; UI_Key key = ZI;
key.hash = RandU64FromSeed(seed); key.hash = RandU64FromSeed(seed);
return key; return key;
@ -77,10 +74,10 @@ UI_Box *UI_BoxFromKey(UI_Key key)
String UI_StringF_(String fmt, ...) String UI_StringF_(String fmt, ...)
{ {
UI_State *g = &UI_state; UI_Frame *frame = UI_CurrentFrame();
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
String str = FormatStringV(g->bframe.cmds_arena, fmt, args); String str = FormatStringV(frame->arena, fmt, args);
va_end(args); va_end(args);
return str; return str;
} }
@ -90,8 +87,8 @@ String UI_StringF_(String fmt, ...)
UI_Checkpoint UI_PushCP(UI_Key parent) UI_Checkpoint UI_PushCP(UI_Key parent)
{ {
UI_State *g = &UI_state; UI_Frame *frame = UI_CurrentFrame();
UI_Stack *stack = g->bframe.top_stack; UI_Stack *stack = frame->top_stack;
stack->top_checkpoint.v += 1; stack->top_checkpoint.v += 1;
if (parent.hash != 0) if (parent.hash != 0)
{ {
@ -102,16 +99,16 @@ UI_Checkpoint UI_PushCP(UI_Key parent)
void UI_PopCP(UI_Checkpoint cp) void UI_PopCP(UI_Checkpoint cp)
{ {
UI_State *g = &UI_state; UI_Frame *frame = UI_CurrentFrame();
UI_Stack *stack = g->bframe.top_stack; UI_Stack *stack = frame->top_stack;
for (UI_StyleKind kind = UI_StyleKind_None; kind < UI_StyleKind_Count; ++kind) for (UI_StyleKind kind = UI_StyleKind_None; kind < UI_StyleKind_Count; ++kind)
{ {
UI_StyleNode *n = stack->style_tops[kind]; UI_StyleNode *n = stack->style_tops[kind];
while (n && n->checkpoint.v >= cp.v) while (n && n->checkpoint.v >= cp.v)
{ {
UI_StyleNode *next = n->next; UI_StyleNode *next = n->next;
n->next = g->bframe.first_free_style_node; n->next = frame->first_free_style_node;
g->bframe.first_free_style_node = n; frame->first_free_style_node = n;
stack->style_tops[kind] = next; stack->style_tops[kind] = next;
n = next; n = next;
} }
@ -121,8 +118,8 @@ void UI_PopCP(UI_Checkpoint cp)
UI_Checkpoint UI_TopCP(void) UI_Checkpoint UI_TopCP(void)
{ {
UI_State *g = &UI_state; UI_Frame *frame = UI_CurrentFrame();
UI_Stack *stack = g->bframe.top_stack; UI_Stack *stack = frame->top_stack;
return stack->top_checkpoint; return stack->top_checkpoint;
} }
@ -131,8 +128,8 @@ UI_Checkpoint UI_TopCP(void)
void UI_PushDefaults(void) void UI_PushDefaults(void)
{ {
UI_State *g = &UI_state; UI_Frame *frame = UI_CurrentFrame();
UI_Stack *stack = g->bframe.top_stack; UI_Stack *stack = frame->top_stack;
UI_Checkpoint checkpoint = stack->top_checkpoint; UI_Checkpoint checkpoint = stack->top_checkpoint;
{ {
for (UI_StyleKind kind = UI_StyleKind_None; kind < UI_StyleKind_Count; ++kind) for (UI_StyleKind kind = UI_StyleKind_None; kind < UI_StyleKind_Count; ++kind)
@ -144,8 +141,14 @@ void UI_PushDefaults(void)
default: break; default: break;
case UI_StyleKind_Parent: { desc.style.Parent = UI_RootKey; } break; case UI_StyleKind_Parent: { desc.style.Parent = UI_RootKey; } break;
case UI_StyleKind_Width: { desc.style.Width = UI_GROW(1, 0); } break; case UI_StyleKind_Width: { desc.style.Width = UI_GROW(1, 0); } break;
case UI_StyleKind_Height: { desc.style.Height = UI_GROW(1, 0); } break; case UI_StyleKind_Height: { desc.style.Height = UI_GROW(1, 0); }
case UI_StyleKind_Font: { desc.style.Font = UI_GetDefaultFontResource(); } break; case UI_StyleKind_Font: { desc.style.Font = UI_GetDefaultFont(); } break;
u8 prefetch[127] = ZI;
for (u64 i = 0; i < countof(prefetch); ++i)
{
prefetch[i] = i;
}
case UI_StyleKind_FontSize: { desc.style.FontSize = 16.0f; } break; case UI_StyleKind_FontSize: { desc.style.FontSize = 16.0f; } break;
case UI_StyleKind_Tint: { desc.style.Tint = Color_White; } break; case UI_StyleKind_Tint: { desc.style.Tint = Color_White; } break;
case UI_StyleKind_Tag: { desc.style.Tag = HashFnv64(Fnv64Basis, Lit("root")); } break; case UI_StyleKind_Tag: { desc.style.Tag = HashFnv64(Fnv64Basis, Lit("root")); } break;
@ -159,8 +162,8 @@ void UI_PushDefaults(void)
void UI_PushStyle(UI_StyleDesc desc) void UI_PushStyle(UI_StyleDesc desc)
{ {
UI_State *g = &UI_state; UI_Frame *frame = UI_CurrentFrame();
UI_Stack *stack = g->bframe.top_stack; UI_Stack *stack = frame->top_stack;
UI_StyleKind kind = desc.style.kind; UI_StyleKind kind = desc.style.kind;
if (kind >= UI_StyleKind_BeginVirtualStyles_) if (kind >= UI_StyleKind_BeginVirtualStyles_)
{ {
@ -246,15 +249,15 @@ void UI_PushStyle(UI_StyleDesc desc)
} }
else else
{ {
n = g->bframe.first_free_style_node; n = frame->first_free_style_node;
if (n) if (n)
{ {
g->bframe.first_free_style_node = n->next; frame->first_free_style_node = n->next;
ZeroStruct(n); ZeroStruct(n);
} }
else else
{ {
n = PushStruct(g->bframe.cmds_arena, UI_StyleNode); n = PushStruct(frame->arena, UI_StyleNode);
} }
n->next = stack->style_tops[kind]; n->next = stack->style_tops[kind];
stack->style_tops[kind] = n; stack->style_tops[kind] = n;
@ -272,7 +275,7 @@ void UI_PushStyle(UI_StyleDesc desc)
case UI_StyleKind_Text: case UI_StyleKind_Text:
{ {
n->style.Text = PushString(g->bframe.cmds_arena, desc.style.Text); n->style.Text = PushString(frame->arena, desc.style.Text);
} break; } break;
case UI_StyleKind_Tag: case UI_StyleKind_Tag:
@ -289,8 +292,8 @@ void UI_PushStyle(UI_StyleDesc desc)
UI_Style UI_PopStyle(UI_StyleDesc desc) UI_Style UI_PopStyle(UI_StyleDesc desc)
{ {
UI_State *g = &UI_state; UI_Frame *frame = UI_CurrentFrame();
UI_Stack *stack = g->bframe.top_stack; UI_Stack *stack = frame->top_stack;
UI_Style result = ZI; UI_Style result = ZI;
UI_StyleKind kind = desc.style.kind; UI_StyleKind kind = desc.style.kind;
result.kind = kind; result.kind = kind;
@ -362,8 +365,8 @@ UI_Style UI_PopStyle(UI_StyleDesc desc)
if (desc.use && n->pop_when_used) if (desc.use && n->pop_when_used)
{ {
stack->style_tops[kind] = n->next; stack->style_tops[kind] = n->next;
n->next = g->bframe.first_free_style_node; n->next = frame->first_free_style_node;
g->bframe.first_free_style_node = n; frame->first_free_style_node = n;
} }
} }
return result; return result;
@ -374,8 +377,8 @@ UI_Style UI_PopStyle(UI_StyleDesc desc)
UI_Key UI_BuildBoxEx(UI_Key key) UI_Key UI_BuildBoxEx(UI_Key key)
{ {
UI_State *g = &UI_state; UI_Frame *frame = UI_CurrentFrame();
UI_CmdNode *n = PushStruct(g->bframe.cmds_arena, UI_CmdNode); UI_CmdNode *n = PushStruct(frame->arena, UI_CmdNode);
n->cmd.kind = UI_CmdKind_BuildBox; n->cmd.kind = UI_CmdKind_BuildBox;
{ {
n->cmd.box.key = key; n->cmd.box.key = key;
@ -391,31 +394,31 @@ UI_Key UI_BuildBoxEx(UI_Key key)
n->cmd.box.debug_color = UI_UseTop(DebugColor); n->cmd.box.debug_color = UI_UseTop(DebugColor);
n->cmd.box.tint = UI_UseTop(Tint); n->cmd.box.tint = UI_UseTop(Tint);
n->cmd.box.border = UI_UseTop(Border); n->cmd.box.border = UI_UseTop(Border);
n->cmd.box.font_resource = UI_UseTop(Font); n->cmd.box.font = UI_UseTop(Font);
n->cmd.box.font_size = UI_UseTop(FontSize); n->cmd.box.font_size = UI_UseTop(FontSize);
n->cmd.box.rounding = UI_UseTop(Rounding); n->cmd.box.rounding = UI_UseTop(Rounding);
n->cmd.box.text = UI_UseTop(Text); n->cmd.box.text = UI_UseTop(Text);
n->cmd.box.floating_pos = UI_UseTop(FloatingPos); n->cmd.box.floating_pos = UI_UseTop(FloatingPos);
} }
++g->bframe.cmds_count; ++frame->cmds_count;
SllQueuePush(g->bframe.first_cmd_node, g->bframe.last_cmd_node, n); SllQueuePush(frame->first_cmd_node, frame->last_cmd_node, n);
return key; return key;
} }
void UI_SetRawTexture(UI_Key key, GPU_Resource *texture, Vec2 uv0, Vec2 uv1) void UI_SetRawTexture(UI_Key key, Texture2DHandle tex, Vec2 uv0, Vec2 uv1)
{ {
UI_State *g = &UI_state; UI_Frame *frame = UI_CurrentFrame();
UI_CmdNode *n = PushStruct(g->bframe.cmds_arena, UI_CmdNode); UI_CmdNode *n = PushStruct(frame->arena, UI_CmdNode);
n->cmd.kind = UI_CmdKind_SetRawTexture; n->cmd.kind = UI_CmdKind_SetRawTexture;
{ {
n->cmd.set_raw_texture.key = key; n->cmd.set_raw_texture.key = key;
n->cmd.set_raw_texture.texture = texture; n->cmd.set_raw_texture.tex = tex;
n->cmd.set_raw_texture.uv0 = uv0; n->cmd.set_raw_texture.uv0 = uv0;
n->cmd.set_raw_texture.uv1 = uv1; n->cmd.set_raw_texture.uv1 = uv1;
} }
++g->bframe.cmds_count; ++frame->cmds_count;
SllQueuePush(g->bframe.first_cmd_node, g->bframe.last_cmd_node, n); SllQueuePush(frame->first_cmd_node, frame->last_cmd_node, n);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -438,19 +441,9 @@ UI_Report UI_ReportFromKey(UI_Key key)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Begin frame //~ Begin frame
UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color) UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
{ {
UI_State *g = &UI_state; UI_State *g = &UI_state;
UI_Frame result = ZI;
UI_BFrameState old_bframe = g->bframe;
//////////////////////////////
//- Wait on swapchain
if (g->eframe.swapchain)
{
GPU_YieldOnSwapchain(g->eframe.swapchain);
}
////////////////////////////// //////////////////////////////
//- Init persistent state //- Init persistent state
@ -459,59 +452,76 @@ UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
{ {
g->box_arena = AcquireArena(Gibi(64)); g->box_arena = AcquireArena(Gibi(64));
g->box_bins = PushStructs(g->box_arena, UI_BoxBin, UI_NumBoxLookupBins); g->box_bins = PushStructs(g->box_arena, UI_BoxBin, UI_NumBoxLookupBins);
for (u64 i = 0; i < countof(g->frames); ++i)
{
UI_Frame *frame = &g->frames[i];
frame->arena = AcquireArena(Gibi(64));
} }
}
//////////////////////////////
//- Begin frame
u64 last_frame_idx = g->current_frame_idx;
u64 frame_idx = last_frame_idx + 1;
if (frame_idx > countof(g->frames))
{
frame_idx = 0;
}
UI_Frame *last_frame = &g->frames[last_frame_idx];
UI_Frame *frame = &g->frames[frame_idx];
frame->window_frame = WND_BeginFrame(GPU_Format_R16G16B16A16_Float, WND_BackbufferSizeMode_MatchMonitor);
////////////////////////////// //////////////////////////////
//- Reset state //- Reset state
/* Zero frame data */ /* Reset frame data */
{ {
ZeroStruct(&g->bframe); Arena *old_arena = frame->arena;
g->bframe.cmds_arena = old_bframe.cmds_arena; Arena *old_rects_arena = frame->arena;
g->bframe.transient_key_seed; GPU_ArenaHandle old_gpu_arena = frame->gpu_arena;
} ZeroStruct(frame);
if (!g->bframe.cmds_arena) frame->arena = old_arena;
{ frame->rects_arena = old_rects_arena;
g->bframe.cmds_arena = AcquireArena(Gibi(64)); frame->gpu_arena = old_gpu_arena;
} }
ResetArena(frame->arena);
ResetArena(frame->rects_arena);
GPU_ResetArenaFromQueue(GPU_QueueKind_Direct, frame->gpu_arena);
{ {
i64 now_ns = TimeNs(); i64 now_ns = TimeNs();
i64 dt_ns = now_ns - old_bframe.time_ns; i64 dt_ns = now_ns - last_frame->time_ns;
g->bframe.time_ns = now_ns; frame->time_ns = now_ns;
g->bframe.dt_ns = dt_ns; frame->dt_ns = dt_ns;
g->bframe.tick = old_bframe.tick + 1; frame->tick = last_frame->tick + 1;
} }
ResetArena(g->bframe.cmds_arena);
/* Init style stack */ /* Init style stack */
{ {
g->bframe.top_stack = PushStruct(g->bframe.cmds_arena, UI_Stack); frame->top_stack = PushStruct(frame->arena, UI_Stack);
UI_PushDefaults(); UI_PushDefaults();
} }
g->bframe.frame_flags = frame_flags; frame->frame_flags = frame_flags;
g->bframe.swapchain_color = swapchain_color; frame->swapchain_color = swapchain_color;
//////////////////////////////
//- Begin window frame
g->bframe.window_frame = WND_BeginFrame();
////////////////////////////// //////////////////////////////
//- Process controller events //- Process controller events
if (g->eframe.boxes_pre != 0) if (last_frame->boxes_pre != 0)
{ {
ControllerEventsArray controller_events = g->bframe.window_frame.controller_events; ControllerEventsArray controller_events = frame->window_frame.controller_events;
g->bframe.cursor_pos = old_bframe.cursor_pos; frame->cursor_pos = last_frame->cursor_pos;
f64 dt = SecondsFromNs(g->bframe.dt_ns); f64 dt = SecondsFromNs(frame->dt_ns);
f64 inv_dt = 1.0 / dt; f64 inv_dt = 1.0 / dt;
/* Locate boxes */ /* Locate boxes */
UI_Box *hovered_box = 0; UI_Box *hovered_box = 0;
UI_Box *active_box = UI_BoxFromKey(old_bframe.active_box); UI_Box *active_box = UI_BoxFromKey(last_frame->active_box);
/* Update cursor pos */ /* Update cursor pos */
for (u64 cev_index = 0; cev_index < controller_events.count; ++cev_index) for (u64 cev_index = 0; cev_index < controller_events.count; ++cev_index)
@ -519,14 +529,14 @@ UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
ControllerEvent cev = controller_events.events[cev_index]; ControllerEvent cev = controller_events.events[cev_index];
if (cev.kind == ControllerEventKind_CursorMove) if (cev.kind == ControllerEventKind_CursorMove)
{ {
g->bframe.cursor_pos = Vec2FromFields(cev.cursor_pos); frame->cursor_pos = Vec2FromVec(cev.cursor_pos);
} }
} }
/* Init box reports */ /* Init box reports */
for (u64 pre_index = g->boxes_count; pre_index-- > 0;) for (u64 pre_index = g->boxes_count; pre_index-- > 0;)
{ {
UI_Box *box = g->eframe.boxes_pre[pre_index]; UI_Box *box = last_frame->boxes_pre[pre_index];
if (hovered_box == 0 && box->desc.flags & UI_BoxFlag_Interactable) if (hovered_box == 0 && box->desc.flags & UI_BoxFlag_Interactable)
{ {
b32 is_cursor_in_box = 0; b32 is_cursor_in_box = 0;
@ -534,7 +544,7 @@ UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
/* TODO: More efficient test. This logic is just copied from the renderer's SDF function for now. */ /* TODO: More efficient test. This logic is just copied from the renderer's SDF function for now. */
Vec2 p0 = box->p0; Vec2 p0 = box->p0;
Vec2 p1 = box->p1; Vec2 p1 = box->p1;
Vec2 point = g->bframe.cursor_pos; Vec2 point = frame->cursor_pos;
b32 is_corner = 0; b32 is_corner = 0;
f32 non_corner_edge_dist = MinF32(MinF32(point.x - p0.x, p1.x - point.x), MinF32(point.y - p0.y, p1.y - point.y)); f32 non_corner_edge_dist = MinF32(MinF32(point.x - p0.x, p1.x - point.x), MinF32(point.y - p0.y, p1.y - point.y));
f32 corner_edge_dist = non_corner_edge_dist; f32 corner_edge_dist = non_corner_edge_dist;
@ -582,7 +592,7 @@ UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
{ {
++hovered_box->report.m1_downs; ++hovered_box->report.m1_downs;
hovered_box->report.m1_held = 1; hovered_box->report.m1_held = 1;
hovered_box->report.last_m1_offset = SubVec2(g->bframe.cursor_pos, hovered_box->p0); hovered_box->report.last_m1_offset = SubVec2(frame->cursor_pos, hovered_box->p0);
active_box = hovered_box; active_box = hovered_box;
} }
} }
@ -615,7 +625,7 @@ UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
/* Update box hot & active states */ /* Update box hot & active states */
for (u64 pre_index = 0; pre_index < g->boxes_count; ++pre_index) for (u64 pre_index = 0; pre_index < g->boxes_count; ++pre_index)
{ {
UI_Box *box = g->eframe.boxes_pre[pre_index]; UI_Box *box = last_frame->boxes_pre[pre_index];
UI_Report *report = &box->report; UI_Report *report = &box->report;
f32 target_hot = box == active_box || (box == hovered_box && (box == active_box || active_box == 0)); f32 target_hot = box == active_box || (box == hovered_box && (box == active_box || active_box == 0));
f32 target_active = box == active_box; f32 target_active = box == active_box;
@ -631,86 +641,62 @@ UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
report->screen_p1 = box->p1; report->screen_p1 = box->p1;
} }
g->bframe.hovered_box = hovered_box ? hovered_box->key : UI_NilKey; frame->hovered_box = hovered_box ? hovered_box->key : UI_NilKey;
g->bframe.active_box = active_box ? active_box->key : UI_NilKey; frame->active_box = active_box ? active_box->key : UI_NilKey;
} }
////////////////////////////// //////////////////////////////
//- Build root box //- Build root box
{ {
UI_SetNext(Width, UI_PIX(g->bframe.window_frame.draw_size.x, 1)); UI_SetNext(Width, UI_PIX(frame->window_frame.draw_size.x, 1));
UI_SetNext(Height, UI_PIX(g->bframe.window_frame.draw_size.y, 1)); UI_SetNext(Height, UI_PIX(frame->window_frame.draw_size.y, 1));
UI_SetNext(Parent, UI_NilKey); UI_SetNext(Parent, UI_NilKey);
UI_BuildBoxEx(UI_RootKey); UI_BuildBoxEx(UI_RootKey);
} }
result.window_frame = g->bframe.window_frame; return frame;
result.cursor_pos = g->bframe.cursor_pos;
result.hovered_box = g->bframe.hovered_box;
result.active_box = g->bframe.hovered_box;
return result;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Frame helpers //~ Frame helpers
Arena *UI_FrameArena(void) UI_Frame *UI_CurrentFrame(void)
{ {
UI_State *g = &UI_state; UI_State *g = &UI_state;
return g->bframe.cmds_arena; return &g->frames[g->current_frame_idx];
};
Arena *UI_FrameArena(void)
{
return UI_CurrentFrame()->arena;
} }
Vec2 UI_CursorPos(void) Vec2 UI_CursorPos(void)
{ {
UI_State *g = &UI_state; return UI_CurrentFrame()->cursor_pos;
return g->bframe.cursor_pos;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ End frame //~ End frame
i64 UI_EndFrame(UI_Frame frame) void UI_EndFrame(UI_Frame *frame)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
UI_State *g = &UI_state; UI_State *g = &UI_state;
UI_EFrameState old_eframe = g->eframe;
Vec2I32 monitor_size = frame.window_frame.monitor_size; Vec2I32 monitor_size = frame->window_frame.monitor_size;
Vec2I32 draw_size = frame.window_frame.draw_size; Vec2I32 draw_size = frame->window_frame.draw_size;
Rng2 draw_viewport = ZI; Rng3 draw_viewport = RNG3(VEC3(0, 0, 0), VEC3(draw_size.x, draw_size.y, 1));
draw_viewport.p1 = Vec2FromFields(draw_size); Rng2 draw_scissor = RNG2(VEC2(0, 0), VEC2(draw_size.x, draw_size.y));
//////////////////////////////
//- Reset state
{
ZeroStruct(&g->eframe);
g->eframe.layout_arena = old_eframe.layout_arena;
g->eframe.drects_gpu_arena = old_eframe.drects_gpu_arena;
g->eframe.draw_target = old_eframe.draw_target;
g->eframe.swapchain = old_eframe.swapchain;
g->eframe.gpu_submit_fence_target = old_eframe.gpu_submit_fence_target;
g->eframe.tick = old_eframe.tick;
}
if (!g->eframe.layout_arena)
{
g->eframe.layout_arena = AcquireArena(Gibi(64));
g->eframe.tex_gpu_arena = GPU_AcquireTextureArena();
g->eframe.frame_gpu_arena = GPU_AcquireArena(Mebi(16));
g->eframe.drects_gpu_arena = GPU_AcquireArena(Mebi(16));
}
ResetArena(g->eframe.layout_arena);
////////////////////////////// //////////////////////////////
//- Process commands //- Process commands
/* FIXME: Reset raw texture data */
g->boxes_count = 0; g->boxes_count = 0;
for (UI_CmdNode *cmd_node = g->bframe.first_cmd_node; cmd_node; cmd_node = cmd_node->next) for (UI_CmdNode *cmd_node = frame->first_cmd_node; cmd_node; cmd_node = cmd_node->next)
{ {
UI_Cmd cmd = cmd_node->cmd; UI_Cmd cmd = cmd_node->cmd;
@ -724,14 +710,14 @@ i64 UI_EndFrame(UI_Frame frame)
key = UI_TransKey(); key = UI_TransKey();
} }
b32 is_root = g->eframe.root_box == 0; b32 is_root = frame->root_box == 0;
UI_Box *parent = 0; UI_Box *parent = 0;
if (!is_root) if (!is_root)
{ {
parent = UI_BoxFromKey(cmd.box.parent); parent = UI_BoxFromKey(cmd.box.parent);
if (!parent) if (!parent)
{ {
parent = g->eframe.root_box; parent = frame->root_box;
} }
} }
@ -781,7 +767,7 @@ i64 UI_EndFrame(UI_Frame frame)
box->report = old_box.report; box->report = old_box.report;
} }
box->key = key; box->key = key;
box->last_updated_tick = g->eframe.tick; box->last_updated_tick = frame->tick;
/* Update box */ /* Update box */
{ {
@ -795,20 +781,17 @@ i64 UI_EndFrame(UI_Frame frame)
++parent->count; ++parent->count;
} }
/* Prefetch font */ /* Fetch run */
box->glyph_run = &GC_NilRun;
if (box->desc.text.len > 0) if (box->desc.text.len > 0)
{ {
box->font = F_LoadFontAsync(box->desc.font_resource, box->desc.font_size); box->glyph_run = GC_RunFromString(frame->arena, box->desc.font, box->desc.text);
if (box->font)
{
box->glyph_run = F_RunFromString(g->eframe.layout_arena, box->font, box->desc.text);
}
} }
} }
if (is_root) if (is_root)
{ {
g->eframe.root_box = box; frame->root_box = box;
} }
} break; } break;
@ -818,7 +801,7 @@ i64 UI_EndFrame(UI_Frame frame)
UI_Box *box = UI_BoxFromKey(key); UI_Box *box = UI_BoxFromKey(key);
if (box) if (box)
{ {
box->raw_texture = cmd.set_raw_texture.texture; box->raw_texture = cmd.set_raw_texture.tex;
box->raw_texture_uv0 = cmd.set_raw_texture.uv0; box->raw_texture_uv0 = cmd.set_raw_texture.uv0;
box->raw_texture_uv1 = cmd.set_raw_texture.uv1; box->raw_texture_uv1 = cmd.set_raw_texture.uv1;
} }
@ -831,7 +814,7 @@ i64 UI_EndFrame(UI_Frame frame)
//- Prune boxes //- Prune boxes
// { // {
// u64 cur_tick = g->eframe.tick; // u64 cur_tick = frame->tick;
// UI_BoxIter it = UI_ITER(g->root_box); // UI_BoxIter it = UI_ITER(g->root_box);
// UI_Box *box = UI_NextBox(&it); // UI_Box *box = UI_NextBox(&it);
// while (box != 0) // while (box != 0)
@ -846,10 +829,10 @@ i64 UI_EndFrame(UI_Frame frame)
/* Build pre-order & post-order box arrays */ /* Build pre-order & post-order box arrays */
u64 boxes_count = g->boxes_count; u64 boxes_count = g->boxes_count;
UI_Box **boxes_pre = PushStructsNoZero(g->eframe.layout_arena, UI_Box *, boxes_count); UI_Box **boxes_pre = PushStructsNoZero(frame->arena, UI_Box *, boxes_count);
UI_Box **boxes_post = PushStructsNoZero(g->eframe.layout_arena, UI_Box *, boxes_count); UI_Box **boxes_post = PushStructsNoZero(frame->arena, UI_Box *, boxes_count);
g->eframe.boxes_pre = boxes_pre; frame->boxes_pre = boxes_pre;
g->eframe.boxes_post = boxes_post; frame->boxes_post = boxes_post;
{ {
Struct(BoxNode) { BoxNode *next; b32 visited; UI_Box *box; }; Struct(BoxNode) { BoxNode *next; b32 visited; UI_Box *box; };
BoxNode *first_dfs = 0; BoxNode *first_dfs = 0;
@ -857,7 +840,7 @@ i64 UI_EndFrame(UI_Frame frame)
u64 post_index = 0; u64 post_index = 0;
{ {
BoxNode *n = PushStruct(scratch.arena, BoxNode); BoxNode *n = PushStruct(scratch.arena, BoxNode);
n->box = g->eframe.root_box; n->box = frame->root_box;
SllStackPush(first_dfs, n); SllStackPush(first_dfs, n);
} }
while (first_dfs) while (first_dfs)
@ -916,21 +899,15 @@ i64 UI_EndFrame(UI_Frame frame)
{ {
/* TODO: Distinguish between baseline alignment & visual alignment */ /* TODO: Distinguish between baseline alignment & visual alignment */
f32 text_size = 0; f32 text_size = 0;
if (box->font)
{
if (axis == Axis_X) if (axis == Axis_X)
{ {
if (box->glyph_run.count > 0) GC_RunRect rr = box->glyph_run->rects[box->glyph_run->count - 1];
{
F_RunRect rr = box->glyph_run.rects[box->glyph_run.count - 1];
f32 baseline_length = rr.pos + rr.advance; f32 baseline_length = rr.pos + rr.advance;
text_size = baseline_length; text_size = baseline_length;
} }
}
else else
{ {
text_size = box->font->ascent + box->font->descent; text_size = box->glyph_run->ascent + box->glyph_run->descent;
}
} }
box->solved_dims[axis] = text_size + (pref_size.v * 2); box->solved_dims[axis] = text_size + (pref_size.v * 2);
} }
@ -1231,29 +1208,11 @@ i64 UI_EndFrame(UI_Frame frame)
////////////////////////////// //////////////////////////////
//- Render //- Render
GPU_CommandList *cl = GPU_OpenCommandList(GPU_QueueKind_Direct); GPU_CommandListHandle cl = GPU_PrepareCommandList(GPU_QueueKind_Direct);
{ {
////////////////////////////// //////////////////////////////
//- Build render data //- Build render data
/* Acquire render target */
if (!g->eframe.draw_target || !MatchVec2I32(monitor_size, GPU_Count2D(g->eframe.draw_target)))
{
YieldOnFence(submit_fence, g->eframe.gpu_submit_fence_target);
GPU_ReleaseResource(g->eframe.draw_target, GPU_ReleaseFlag_None);
g->eframe.draw_target = 0;
}
if (!g->eframe.draw_target)
{
GPU_ResourceDesc desc = ZI;
desc.kind = GPU_ResourceKind_Texture2D;
desc.flags = GPU_ResourceFlag_Renderable | GPU_ResourceFlag_Writable;
// desc.texture.format = GPU_Format_R8G8B8A8_Unorm;
desc.texture.format = GPU_Format_R16G16B16A16_Float;
desc.texture.size = VEC3I32(monitor_size.x, monitor_size.y, 1);
g->eframe.draw_target = GPU_AcquireResource(desc);
}
/* Build rect instance data */ /* Build rect instance data */
for (u64 pre_index = 0; pre_index < boxes_count; ++pre_index) for (u64 pre_index = 0; pre_index < boxes_count; ++pre_index)
{ {
@ -1262,12 +1221,12 @@ i64 UI_EndFrame(UI_Frame frame)
is_visible = is_visible && (box->desc.tint.w != 0); is_visible = is_visible && (box->desc.tint.w != 0);
is_visible = is_visible && (box->p1.x > box->p0.x); is_visible = is_visible && (box->p1.x > box->p0.x);
is_visible = is_visible && (box->p1.y > box->p0.y); is_visible = is_visible && (box->p1.y > box->p0.y);
if (is_visible || AnyBit(g->bframe.frame_flags, UI_FrameFlag_Debug)) if (is_visible || AnyBit(frame->frame_flags, UI_FrameFlag_Debug))
{ {
/* Box rect */ /* Box rect */
{ {
UI_DRect *rect = PushStruct(g->eframe.rects_arena, UI_DRect); UI_DRect *rect = PushStruct(frame->rects_arena, UI_DRect);
rect->flags |= UI_DRectFlag_DrawTexture * !(IsGpuPointerNil(box->raw_texture));
rect->p0 = box->p0; rect->p0 = box->p0;
rect->p1 = box->p1; rect->p1 = box->p1;
rect->tex_uv0 = VEC2(0, 0); rect->tex_uv0 = VEC2(0, 0);
@ -1281,62 +1240,55 @@ i64 UI_EndFrame(UI_Frame frame)
rect->tr_rounding = box->rounding_tr; rect->tr_rounding = box->rounding_tr;
rect->br_rounding = box->rounding_br; rect->br_rounding = box->rounding_br;
rect->bl_rounding = box->rounding_bl; rect->bl_rounding = box->rounding_bl;
/* Texture */
if (!IsGpuPointerNil(box->raw_texture))
{
rect->tex = box->raw_texture; rect->tex = box->raw_texture;
rect->tex_uv0 = box->raw_texture_uv0; rect->tex_uv0 = box->raw_texture_uv0;
rect->tex_uv1 = box->raw_texture_uv1; rect->tex_uv1 = box->raw_texture_uv1;
} }
}
/* Text rects */ /* Text rects */
if (AnyBit(box->desc.flags, UI_BoxFlag_DrawText) && box->glyph_run.count > 0 && box->font) GC_Run *raw_run = box->glyph_run;
if (AnyBit(box->desc.flags, UI_BoxFlag_DrawText) && raw_run->loaded)
{ {
Texture2DRid tex_rid = GPU_Texture2DRidFromResource(box->font->texture);
Vec2 inv_font_image_size = VEC2(1.0f / (f32)box->font->image_width, 1.0f / (f32)box->font->image_height);
F_Run run = box->glyph_run;
f32 max_baseline = box->p1.x - box->p0.x; f32 max_baseline = box->p1.x - box->p0.x;
b32 should_truncate = run.count > 0 && (run.rects[run.count - 1].pos + run.rects[run.count - 1].advance) > max_baseline; b32 should_truncate = raw_run->count > 0 && (raw_run->rects[raw_run->count - 1].pos + raw_run->rects[raw_run->count - 1].advance) > max_baseline;
/* Truncate run */ /* Truncate run */
GC_RunRect *truncated_rects = raw_run->rects;
u32 truncated_rects_count = raw_run->count;
if (should_truncate && !AnyBit(box->desc.flags, UI_BoxFlag_NoTextTruncation)) if (should_truncate && !AnyBit(box->desc.flags, UI_BoxFlag_NoTextTruncation))
{ {
/* Get elipses run */ /* Get elipses run */
F_Run trunc_run = F_RunFromString(scratch.arena, box->font, Lit("...")); GC_Run *elipses_run = GC_RunFromString(scratch.arena, box->desc.font, Lit("..."));
if (trunc_run.count > 0) if (elipses_run->count > 0)
{ {
max_baseline -= trunc_run.rects[trunc_run.count - 1].pos + trunc_run.rects[trunc_run.count - 1].advance; max_baseline -= elipses_run->rects[elipses_run->count - 1].pos + elipses_run->rects[elipses_run->count - 1].advance;
} }
/* Subtract glyphs */ /* Subtract glyphs */
while (run.count > 0) while (truncated_rects_count > 0)
{ {
F_RunRect rr = run.rects[run.count - 1]; GC_RunRect rr = raw_run->rects[truncated_rects_count - 1];
if (rr.pos + rr.advance <= max_baseline) if (rr.pos + rr.advance <= max_baseline)
{ {
break; break;
} }
--run.count; --truncated_rects_count;
} }
/* Merge trunc rects */ /* Merge trunc rects */
F_RunRect *new_rects = 0; /* FIXME: Verify this stil works as expected */
{ {
new_rects = PushStructsNoZero(scratch.arena, F_RunRect, run.count + trunc_run.count); truncated_rects_count += elipses_run->count;
CopyStructs(new_rects, run.rects, run.count); truncated_rects = PushStructsNoZero(scratch.arena, GC_RunRect, truncated_rects_count + elipses_run->count);
f32 trunc_offset = run.count > 0 ? (run.rects[run.count - 1].pos + run.rects[run.count - 1].advance) : 0; CopyStructs(truncated_rects, raw_run->rects, raw_run->count);
for (u32 i = 0; i < trunc_run.count; ++i) f32 elipses_offset = truncated_rects_count > 0 ? (truncated_rects[truncated_rects_count - 1].pos + truncated_rects[truncated_rects_count - 1].advance) : 0;
for (u32 i = 0; i < elipses_run->count; ++i)
{ {
F_RunRect *rr = &new_rects[i + run.count]; GC_RunRect *rr = &truncated_rects[i + truncated_rects_count];
*rr = trunc_run.rects[i]; *rr = elipses_run->rects[i];
rr->pos += trunc_offset; rr->pos += elipses_offset;
} }
} }
run.count += trunc_run.count;
run.rects = new_rects;
} }
UI_AxisAlignment x_alignment = box->desc.child_alignment[Axis_X]; UI_AxisAlignment x_alignment = box->desc.child_alignment[Axis_X];
@ -1347,10 +1299,10 @@ i64 UI_EndFrame(UI_Frame frame)
} }
/* Calculate baseline */ /* Calculate baseline */
f32 ascent = box->font->ascent; f32 ascent = raw_run->ascent;
f32 descent = box->font->descent; f32 descent = raw_run->descent;
f32 cap = box->font->cap; f32 cap = raw_run->cap;
f32 baseline_width = run.count > 0 ? (run.rects[run.count - 1].pos + run.rects[run.count - 1].advance) : 0; f32 baseline_width = truncated_rects_count > 0 ? (truncated_rects[truncated_rects_count - 1].pos + truncated_rects[truncated_rects_count - 1].advance) : 0;
f32 baseline_height = ascent + descent; f32 baseline_height = ascent + descent;
f32 box_width = box->p1.x - box->p0.x; f32 box_width = box->p1.x - box->p0.x;
f32 box_height = box->p1.y - box->p0.y; f32 box_height = box->p1.y - box->p0.y;
@ -1394,113 +1346,90 @@ i64 UI_EndFrame(UI_Frame frame)
baseline = CeilVec2(baseline); baseline = CeilVec2(baseline);
/* Push text rects */ /* Push text rects */
for (u64 i = 0; i < run.count; ++i) for (u64 i = 0; i < truncated_rects_count; ++i)
{ {
F_RunRect rr = run.rects[i]; GC_RunRect rr = truncated_rects[i];
Vec2 atlas_p0 = Vec2FromFields(rr.atlas_p0); Vec2 glyph_size = rr.size;
Vec2 atlas_p1 = Vec2FromFields(rr.atlas_p1);
Vec2 glyph_size = SubVec2(atlas_p1, atlas_p0);
if (glyph_size.x != 0 || glyph_size.y != 0) if (glyph_size.x != 0 || glyph_size.y != 0)
{ {
UI_DRect *rect = PushStruct(g->eframe.rects_arena, UI_DRect); UI_DRect *rect = PushStruct(frame->rects_arena, UI_DRect);
rect->flags |= UI_DRectFlag_DrawTexture;
rect->p0 = AddVec2(baseline, VEC2(rr.pos, 0)); rect->p0 = AddVec2(baseline, VEC2(rr.pos, 0));
rect->p0 = AddVec2(rect->p0, rr.offset); rect->p0 = AddVec2(rect->p0, rr.offset);
rect->p1 = AddVec2(rect->p0, glyph_size); rect->p1 = AddVec2(rect->p0, glyph_size);
rect->debug_lin = LinearFromSrgb(box->desc.debug_color); rect->debug_lin = LinearFromSrgb(box->desc.debug_color);
rect->tint_lin = LinearFromSrgb(box->desc.tint); rect->tint_lin = LinearFromSrgb(box->desc.tint);
rect->tex_uv0 = MulVec2Vec2(atlas_p0, inv_font_image_size); rect->tex = rr.tex;
rect->tex_uv1 = MulVec2Vec2(atlas_p1, inv_font_image_size); rect->tex_uv0 = rr.uv.p0;
rect->tex = tex_rid; rect->tex_uv1 = rr.uv.p1;
} }
} }
} }
} }
} }
//////////////////////////////
//- Push data to GPU
u32 rects_count = ArenaCount(frame->rects_arena, UI_DRect);
UI_DRect *rects = ArenaFirst(frame->rects_arena, UI_DRect);
GPU_ResourceHandle draw_target = GPU_PushTexture2D(
frame->gpu_arena,
GPU_Format_R16G16B16A16_Float,
monitor_size,
GPU_Layout_DirectQueue_RenderTargetWrite,
.flags = GPU_ResourceFlag_AllowRenderTarget
);
StructuredBufferHandle rects_sb = GPU_PushStructuredBufferFromCpu(frame->gpu_arena, cl, rects, rects_count);
GPU_SetConstant(cl, UI_ShaderConst_TargetWidth, draw_size.x);
GPU_SetConstant(cl, UI_ShaderConst_TargetHeight, draw_size.y);
GPU_SetConstant(cl, UI_ShaderConst_Rects, rects_sb);
GPU_SetConstant(cl, UI_ShaderConst_Sampler, GPU_GetSharedPointSampler());
////////////////////////////// //////////////////////////////
//- Dispatch shaders //- Dispatch shaders
/* Upload transient buffers */
GPU_Resource *draw_rects_buffer = GPU_UploadTransientBufferFromArena(&g->eframe.draw_rects_tbuff, g->eframe.rects_arena);
u32 draw_rects_count = GPU_GetBufferCount(draw_rects_buffer);
{ {
//- Prep rect pass //- Prep rect pass
{ {
GPU_TransitionToRenderable(cl, g->eframe.draw_target, 0); GPU_DumbMemoryLayoutSync(cl, draw_target, GPU_Layout_DirectQueue_RenderTargetWrite);
GPU_ClearRenderable(cl, g->eframe.draw_target); GPU_ClearRenderTarget(cl, draw_target, VEC4(0, 0, 0, 0));
} }
//- Rect pass //- Rect pass
if (draw_rects_count > 0) if (rects_count > 0)
{ {
GPU_Viewport viewport = GPU_ViewportFromRect(draw_viewport);
GPU_Scissor scissor = GPU_ScissorFromRect(draw_viewport);
/* Render rects */ /* Render rects */
{
UI_DRectSig sig = ZI;
sig.target_size = draw_size;
sig.sampler = GPU_SamplerStateRidFromResource(GPU_GetCommonPointSampler());
sig.rects = GPU_StructuredBufferRidFromResource(draw_rects_buffer);
GPU_Rasterize(cl, GPU_Rasterize(cl,
&sig,
UI_DRectVS, UI_DRectPS, UI_DRectVS, UI_DRectPS,
1, 1, GPU_GetSharedQuadIndices(),
viewport, 1, &draw_target,
scissor, draw_viewport, draw_scissor,
draw_rects_count, GPU_RasterMode_TriangleList);
GPU_GetCommonQuadIndices(),
GPU_RasterizeMode_TriangleList);
}
/* Render rect wireframes */ /* Render rect wireframes */
if (AnyBit(g->bframe.frame_flags, UI_FrameFlag_Debug)) if (AnyBit(frame->frame_flags, UI_FrameFlag_Debug))
{ {
UI_DRectSig sig = ZI; GPU_SetConstant(cl, UI_ShaderConst_DebugDraw, 1);
sig.target_size = draw_size;
sig.sampler = GPU_SamplerStateRidFromResource(GPU_GetCommonPointSampler());
sig.rects = GPU_StructuredBufferRidFromResource(draw_rects_buffer);
sig.debug_enabled = 1;
GPU_Rasterize(cl, GPU_Rasterize(cl,
&sig,
UI_DRectVS, UI_DRectPS, UI_DRectVS, UI_DRectPS,
1, 1, GPU_GetSharedQuadIndices(),
viewport, 1, &draw_target,
scissor, draw_viewport, draw_scissor,
draw_rects_count, GPU_RasterMode_WireTriangleList);
GPU_GetCommonQuadIndices(),
GPU_RasterizeMode_WireTriangleList);
} }
} }
} }
/* Reset */
GPU_ResetArena(cl, g->eframe.frame_gpu_arena);
GPU_ResetArena(cl, g->eframe.drects_gpu_arena);
} }
GPU_CloseCommandList(cl); GPU_CommitCommandList(cl);
////////////////////////////// //////////////////////////////
//- Present & end frame //- End frame
{ WND_EndFrame(frame->window_frame, VSYNC);
Vec2I32 backbuffer_size = monitor_size;
if (!g->eframe.swapchain)
{
g->eframe.swapchain = GPU_AcquireSwapchain(frame.window_frame.window_handle, GPU_Format_R16G16B16A16_Float, backbuffer_size);
}
Vec2I32 dst_p0 = VEC2I32(0, 0);
Vec2I32 dst_p1 = VEC2I32(0, 0);
Vec2I32 src_p0 = VEC2I32(0, 0);
Vec2I32 src_p1 = draw_size;
GPU_PresentSwapchain(g->eframe.swapchain, g->eframe.draw_target, AnyBit(g->bframe.frame_flags, UI_FrameFlag_Vsync), backbuffer_size, dst_p0, dst_p1, src_p0, src_p1, LinearFromSrgb(g->bframe.swapchain_color));
}
WND_EndFrame(frame.window_frame);
++g->eframe.tick;
EndScratch(scratch); EndScratch(scratch);
} }

View File

@ -106,10 +106,10 @@ Enum(UI_BoxFlag)
X(Border, f32) \ X(Border, f32) \
X(FloatingPos, Vec2) \ X(FloatingPos, Vec2) \
X(Rounding, UI_Round) \ X(Rounding, UI_Round) \
X(Font, ResourceKey) \ X(Font, GC_FontKey) \
X(FontSize, u32) \ X(FontSize, u32) \
X(Text, String) \ X(Text, String) \
X(BackgroundTexture, GpuPointer) \ X(BackgroundTexture, Texture2DHandle) \
X(BackgroundTextureUv0, Vec2) \ X(BackgroundTextureUv0, Vec2) \
X(BackgroundTextureUv1, Vec2) \ X(BackgroundTextureUv1, Vec2) \
/* --------------------------------------- */ \ /* --------------------------------------- */ \
@ -217,7 +217,7 @@ Struct(UI_BoxDesc)
f32 border; f32 border;
Vec2 floating_pos; Vec2 floating_pos;
String text; String text;
ResourceKey font_resource; GC_FontKey font;
f32 font_size; f32 font_size;
Axis child_layout_axis; Axis child_layout_axis;
UI_AxisAlignment child_alignment[Axis_CountXY]; UI_AxisAlignment child_alignment[Axis_CountXY];
@ -232,7 +232,7 @@ Struct(UI_Cmd)
struct struct
{ {
UI_Key key; UI_Key key;
GPU_Resource *texture; Texture2DHandle tex;
Vec2 uv0; Vec2 uv0;
Vec2 uv1; Vec2 uv1;
} set_raw_texture; } set_raw_texture;
@ -268,7 +268,7 @@ Struct(UI_Box)
//- Cmd data //- Cmd data
UI_BoxDesc desc; UI_BoxDesc desc;
GpuPointer raw_texture; Texture2DHandle raw_texture;
Vec2 raw_texture_uv0; Vec2 raw_texture_uv0;
Vec2 raw_texture_uv1; Vec2 raw_texture_uv1;
@ -277,8 +277,7 @@ Struct(UI_Box)
u64 post_index; u64 post_index;
//- Layout data //- Layout data
F_Run glyph_run; GC_Run *glyph_run;
F_Font *font;
f32 layout_cursor; f32 layout_cursor;
f32 solved_dims[Axis_CountXY]; f32 solved_dims[Axis_CountXY];
f32 final_children_size_accum[Axis_CountXY]; f32 final_children_size_accum[Axis_CountXY];
@ -299,7 +298,9 @@ Struct(UI_BoxBin)
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Frame types //~ State types
#define UI_NumBoxLookupBins 16384
Enum(UI_FrameFlag) Enum(UI_FrameFlag)
{ {
@ -310,37 +311,12 @@ Enum(UI_FrameFlag)
Struct(UI_Frame) Struct(UI_Frame)
{ {
Arena *arena;
Arena *rects_arena;
GPU_ArenaHandle gpu_arena;
WND_Frame window_frame; WND_Frame window_frame;
Vec2 cursor_pos; GPU_ResourceHandle backbuffer;
UI_Key hovered_box;
UI_Key active_box;
};
////////////////////////////////////////////////////////////
//~ State types
#define UI_NumBoxLookupBins 16384
Struct(UI_BFrameState);
Struct(UI_EFrameState);
Struct(UI_State)
{
//////////////////////////////
//- Persistent sate
Arena *box_arena;
UI_BoxBin *box_bins;
u64 boxes_count;
UI_Box *first_free_box;
//////////////////////////////
//- Frame-begin state
struct UI_BFrameState
{
Arena *cmds_arena;
WND_Frame window_frame;
u64 transient_key_seed; u64 transient_key_seed;
@ -364,28 +340,22 @@ Struct(UI_State)
/* Style stack */ /* Style stack */
UI_Stack *top_stack; UI_Stack *top_stack;
UI_StyleNode *first_free_style_node; UI_StyleNode *first_free_style_node;
} bframe;
//////////////////////////////
//- Frame-end state
struct UI_EFrameState
{
Arena *layout_arena;
GPU_Arena *frame_gpu_arena;
GPU_Arena *drects_gpu_arena;
u64 tick;
/* Render */
GpuPointer draw_target;
GPU_Swapchain *swapchain;
i64 gpu_submit_fence_target;
/* Layout */ /* Layout */
UI_Box *root_box; UI_Box *root_box;
UI_Box **boxes_pre; UI_Box **boxes_pre;
UI_Box **boxes_post; UI_Box **boxes_post;
} eframe; };
Struct(UI_State)
{
Arena *box_arena;
UI_BoxBin *box_bins;
u64 boxes_count;
UI_Box *first_free_box;
u64 current_frame_idx;
UI_Frame frames[2];
} extern UI_state; } extern UI_state;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -396,7 +366,7 @@ void UI_Startup(void);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Font helpers //~ Font helpers
ResourceKey UI_GetDefaultFontResource(void); GC_FontKey UI_GetDefaultFont(void);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Key helpers //~ Key helpers
@ -472,7 +442,7 @@ UI_Style UI_PopStyle(UI_StyleDesc desc);
UI_Key UI_BuildBoxEx(UI_Key key); UI_Key UI_BuildBoxEx(UI_Key key);
#define UI_BuildBox() UI_BuildBoxEx(UI_TransKey()) #define UI_BuildBox() UI_BuildBoxEx(UI_TransKey())
void UI_SetRawTexture(UI_Key key, GPU_Resource *texture, Vec2 uv0, Vec2 uv1); void UI_SetRawTexture(UI_Key key, Texture2DHandle tex, Vec2 uv0, Vec2 uv1);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Report //~ Report
@ -482,15 +452,16 @@ UI_Report UI_ReportFromKey(UI_Key key);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Begin frame //~ Begin frame
UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color); UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Frame helpers //~ Frame helpers
UI_Frame *UI_CurrentFrame(void);
Arena *UI_FrameArena(void); Arena *UI_FrameArena(void);
Vec2 UI_CursorPos(void); Vec2 UI_CursorPos(void);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ End frame //~ End frame
void UI_EndFrame(UI_Frame frame); void UI_EndFrame(UI_Frame *frame);

View File

@ -1,43 +0,0 @@
////////////////////////////////////////////////////////////
//~ Rect shader types
Struct(UI_DRectSig)
{
/* ----------------------------------------------------- */
Vec2I32 target_size; /* 02 consts */
StructuredBufferRid rects; /* 01 consts */
SamplerStateRid sampler; /* 01 consts */
/* ----------------------------------------------------- */
b32 debug_enabled; /* 01 consts */
u32 _pad0; /* 01 consts (padding) */
u32 _pad1; /* 01 consts (padding) */
u32 _pad2; /* 01 consts (padding) */
/* ----------------------------------------------------- */
};
AssertRootConst(UI_DRectSig, 8);
Enum(UI_DRectFlag)
{
UI_DRectFlag_None = 0,
UI_DRectFlag_DrawTexture = (1 << 0),
};
Struct(UI_DRect)
{
UI_DRectFlag flags;
Vec2 p0;
Vec2 p1;
Vec4 tint_lin;
Vec4 background_lin;
Vec4 border_lin;
Vec4 debug_lin;
f32 border;
Vec2 tex_uv0;
Vec2 tex_uv1;
Texture2DRid tex;
f32 tl_rounding;
f32 tr_rounding;
f32 br_rounding;
f32 bl_rounding;
};

27
src/ui/ui_shaders.h Normal file
View File

@ -0,0 +1,27 @@
////////////////////////////////////////////////////////////
//~ Rect types
ShaderConstant(i32, UI_ShaderConst_TargetWidth, 0);
ShaderConstant(i32, UI_ShaderConst_TargetHeight, 1);
ShaderConstant(StructuredBufferHandle, UI_ShaderConst_Rects, 2);
ShaderConstant(SamplerStateHandle, UI_ShaderConst_Sampler, 3);
ShaderConstant(b32, UI_ShaderConst_DebugDraw, 4);
Struct(UI_DRect)
{
Vec2 p0;
Vec2 p1;
Vec4 tint_lin;
Vec4 background_lin;
Vec4 border_lin;
Vec4 debug_lin;
f32 border;
Vec2 tex_uv0;
Vec2 tex_uv1;
Texture2DHandle tex;
f32 tl_rounding;
f32 tr_rounding;
f32 br_rounding;
f32 bl_rounding;
};

View File

@ -1,7 +1,5 @@
ConstantBuffer<UI_DRectSig> UI_drect_sig : register (b0);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Rect shader //~ Rect
Struct(UI_DRectPSInput) Struct(UI_DRectPSInput)
{ {
@ -25,8 +23,7 @@ Struct(UI_DRectPSOutput)
VertexShader(UI_DRectVS, UI_DRectPSInput) VertexShader(UI_DRectVS, UI_DRectPSInput)
{ {
ConstantBuffer<UI_DRectSig> sig = UI_drect_sig; StructuredBuffer<UI_DRect> rects = StructuredBufferFromHandle<UI_DRect>(UI_ShaderConst_Rects);
StructuredBuffer<UI_DRect> rects = UniformResourceFromRid(sig.rects);
UI_DRect rect = rects[SV_InstanceID]; UI_DRect rect = rects[SV_InstanceID];
Vec2 rect_uv = RectUvFromVertexId(SV_VertexID); Vec2 rect_uv = RectUvFromVertexId(SV_VertexID);
@ -34,7 +31,7 @@ VertexShader(UI_DRectVS, UI_DRectPSInput)
Vec2 target_pos = lerp(rect.p0, rect.p1, rect_uv); Vec2 target_pos = lerp(rect.p0, rect.p1, rect_uv);
UI_DRectPSInput result; UI_DRectPSInput result;
result.sv_position = Vec4(NdcFromPos(target_pos, sig.target_size).xy, 0, 1); result.sv_position = Vec4(NdcFromPos(target_pos, Vec2(UI_ShaderConst_TargetWidth, UI_ShaderConst_TargetHeight).xy), 0, 1);
result.background_lin = rect.background_lin; result.background_lin = rect.background_lin;
result.border_lin = rect.border_lin; result.border_lin = rect.border_lin;
result.tint_lin = rect.tint_lin; result.tint_lin = rect.tint_lin;
@ -50,8 +47,9 @@ VertexShader(UI_DRectVS, UI_DRectPSInput)
PixelShader(UI_DRectPS, UI_DRectPSOutput, UI_DRectPSInput input) PixelShader(UI_DRectPS, UI_DRectPSOutput, UI_DRectPSInput input)
{ {
ConstantBuffer<UI_DRectSig> sig = UI_drect_sig; StructuredBuffer<UI_DRect> rects = StructuredBufferFromHandle<UI_DRect>(UI_ShaderConst_Rects);
StructuredBuffer<UI_DRect> rects = UniformResourceFromRid(sig.rects); SamplerState sampler = SamplerStateFromHandle(UI_ShaderConst_Sampler);
UI_DRect rect = rects[input.rect_idx]; UI_DRect rect = rects[input.rect_idx];
Vec2 p = input.sv_position.xy; Vec2 p = input.sv_position.xy;
@ -108,10 +106,9 @@ PixelShader(UI_DRectPS, UI_DRectPSOutput, UI_DRectPSInput input)
{ {
background_color = border_color; background_color = border_color;
} }
else if (rect.flags & UI_DRectFlag_DrawTexture) else if (!IsGpuHandleNil(rect.tex))
{ {
SamplerState sampler = UniformSamplerFromRid(sig.sampler); Texture2D<Vec4> tex = Texture2DFromHandle<Vec4>(rect.tex);
Texture2D<Vec4> tex = NonUniformResourceFromRid(rect.tex);
background_color = tex.Sample(sampler, input.tex_uv); background_color = tex.Sample(sampler, input.tex_uv);
} }
else else
@ -126,7 +123,7 @@ PixelShader(UI_DRectPS, UI_DRectPSOutput, UI_DRectPSInput input)
final_color *= input.tint_lin; final_color *= input.tint_lin;
/* Debug color */ /* Debug color */
if (sig.debug_enabled) if (UI_ShaderConst_DebugDraw)
{ {
final_color = rect.debug_lin; final_color = rect.debug_lin;
} }

View File

@ -29,9 +29,16 @@ Struct(WND_Cmd)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Frame types //~ Frame types
Enum(WND_BackbufferSizeMode)
{
WND_BackbufferSizeMode_MatchWindow,
WND_BackbufferSizeMode_MatchMonitor,
};
Struct(WND_Frame) Struct(WND_Frame)
{ {
WND_Handle window; WND_Handle window;
GPU_ResourceHandle backbuffer;
ControllerEventsArray controller_events; ControllerEventsArray controller_events;
@ -51,11 +58,6 @@ Struct(WND_Frame)
void WND_Startup(void); void WND_Startup(void);
////////////////////////////////////////////////////////////
//~ @hookdecl Helpers
u64 WND_OsHandleFromWindow(WND_Handle window);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ @hookdecl Command //~ @hookdecl Command
@ -65,5 +67,5 @@ void WND_PushCmd_(WND_Frame frame, WND_Cmd desc);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ @hookdecl Frame //~ @hookdecl Frame
WND_Frame WND_BeginFrame(void); WND_Frame WND_BeginFrame(GPU_Format backbuffer_format, WND_BackbufferSizeMode backbuffer_size_mode);
void WND_EndFrame(WND_Frame frame); void WND_EndFrame(WND_Frame frame, i32 vsync);

View File

@ -1,9 +1,13 @@
@Layer window @Layer window
//- Dependencies
@Dep gpu
//- Api //- Api
@IncludeC window.h @IncludeC window.h
//- Win32 impl //- Win32 impl
@DefaultWindowsImpl window_win32 @DefaultWindowsImpl window_win32
//- Startup
@Startup WND_Startup @Startup WND_Startup

View File

@ -108,7 +108,6 @@ void WND_W32_ProcessMessagesForever(WaveLaneCtx *lane)
window->w2u_events_arena = AcquireArena(Gibi(64)); window->w2u_events_arena = AcquireArena(Gibi(64));
//- Initialize hwnd //- Initialize hwnd
HWND hwnd = 0;
{ {
/* /*
* From martins (https://gist.github.com/mmozeiko/5e727f845db182d468a34d524508ad5f#file-win32_d3d11-c-L66-L70): * From martins (https://gist.github.com/mmozeiko/5e727f845db182d468a34d524508ad5f#file-win32_d3d11-c-L66-L70):
@ -120,7 +119,7 @@ void WND_W32_ProcessMessagesForever(WaveLaneCtx *lane)
DWORD exstyle = WS_EX_APPWINDOW | WS_EX_NOREDIRECTIONBITMAP; DWORD exstyle = WS_EX_APPWINDOW | WS_EX_NOREDIRECTIONBITMAP;
/* TODO: Check for hwnd success */ /* TODO: Check for hwnd success */
hwnd = CreateWindowExW( window->hwnd = CreateWindowExW(
exstyle, exstyle,
g->window_class.lpszClassName, g->window_class.lpszClassName,
L"", L"",
@ -137,13 +136,17 @@ void WND_W32_ProcessMessagesForever(WaveLaneCtx *lane)
/* Dark mode */ /* Dark mode */
BOOL dark_mode = 1; BOOL dark_mode = 1;
DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, (LPCVOID)&dark_mode, sizeof(dark_mode)); DwmSetWindowAttribute(window->hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, (LPCVOID)&dark_mode, sizeof(dark_mode));
/* Set window as userdata */ /* Set window as userdata */
/* FIXME: Necessary? */ /* FIXME: Necessary? */
SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)window); SetWindowLongPtrW(window->hwnd, GWLP_USERDATA, (LONG_PTR)window);
}
//- Acquire swapchain
{
window->swapchain = GPU_AcquireSwapchain((u64)window->hwnd);
} }
window->hwnd = hwnd;
//- Begin processing messages //- Begin processing messages
Atomic32Set(&window->is_ready, 1); Atomic32Set(&window->is_ready, 1);
@ -382,15 +385,6 @@ LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM l
return result; return result;
} }
////////////////////////////////////////////////////////////
//~ @hookimpl Helpers
u64 WND_OsHandleFromWindow(WND_Handle handle)
{
WND_W32_Window *window = WND_W32_WindowFromHandle(handle);
return (u64)window->hwnd;
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ @hookimpl Command //~ @hookimpl Command
@ -409,7 +403,7 @@ void WND_PushCmd_(WND_Frame frame, WND_Cmd desc)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ @hookimpl Frame //~ @hookimpl Frame
WND_Frame WND_BeginFrame(void) WND_Frame WND_BeginFrame(GPU_Format backbuffer_format, WND_BackbufferSizeMode backbuffer_size_mode)
{ {
WND_W32_SharedState *g = &WND_W32_shared_state; WND_W32_SharedState *g = &WND_W32_shared_state;
WND_W32_Window *window = &g->window; WND_W32_Window *window = &g->window;
@ -422,6 +416,41 @@ WND_Frame WND_BeginFrame(void)
HWND hwnd = window->hwnd; HWND hwnd = window->hwnd;
result.window.v = (u64)window; result.window.v = (u64)window;
/* Grab monitor info */
RECT monitor_rect = ZI;
{
MONITORINFO monitor_info = { .cbSize = sizeof(monitor_info) };
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY), &monitor_info);
monitor_rect = monitor_info.rcMonitor;
}
result.monitor_size = VEC2I32(monitor_rect.right - monitor_rect.left, monitor_rect.bottom - monitor_rect.top);
result.monitor_size.x = MaxI32(result.monitor_size.x, 1);
result.monitor_size.y = MaxI32(result.monitor_size.y, 1);
/* Client rect */
RECT client_rect = ZI;
GetClientRect(hwnd, (LPRECT)&client_rect);
/* Screen rect */
RECT screen_rect = client_rect;
ClientToScreen(hwnd, (LPPOINT)&screen_rect.left);
ClientToScreen(hwnd, (LPPOINT)&screen_rect.right);
result.draw_size = VEC2I32(screen_rect.right - screen_rect.left, screen_rect.bottom - screen_rect.top);
result.draw_size.x = MaxI32(result.draw_size.x, 1);
result.draw_size.y = MaxI32(result.draw_size.y, 1);
/* Prepare backbuffer */
Vec2I32 backbuffer_size = ZI;
if (backbuffer_size_mode == WND_BackbufferSizeMode_MatchWindow)
{
backbuffer_size = result.draw_size;
}
else if (backbuffer_size_mode == WND_BackbufferSizeMode_MatchMonitor)
{
backbuffer_size = result.monitor_size;
}
result.backbuffer = GPU_PrepareBackbuffer(window->swapchain, backbuffer_format, backbuffer_size);
/* Reset per-frame data */ /* Reset per-frame data */
if (!window->frame_arena) if (!window->frame_arena)
{ {
@ -444,29 +473,6 @@ WND_Frame WND_BeginFrame(void)
UnlockTicketMutex(&window->w2u_tm); UnlockTicketMutex(&window->w2u_tm);
} }
/* Grab monitor info */
RECT monitor_rect = ZI;
{
MONITORINFO monitor_info = { .cbSize = sizeof(monitor_info) };
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY), &monitor_info);
monitor_rect = monitor_info.rcMonitor;
}
result.monitor_size = VEC2I32(monitor_rect.right - monitor_rect.left, monitor_rect.bottom - monitor_rect.top);
result.monitor_size.x = MaxI32(result.monitor_size.x ,1);
result.monitor_size.y = MaxI32(result.monitor_size.y ,1);
/* Client rect */
RECT client_rect = ZI;
GetClientRect(hwnd, (LPRECT)&client_rect);
/* Screen rect */
RECT screen_rect = client_rect;
ClientToScreen(hwnd, (LPPOINT)&screen_rect.left);
ClientToScreen(hwnd, (LPPOINT)&screen_rect.right);
result.draw_size = VEC2I32(screen_rect.right - screen_rect.left, screen_rect.bottom - screen_rect.top);
result.draw_size.x = MaxI32(result.draw_size.x ,1);
result.draw_size.y = MaxI32(result.draw_size.y ,1);
/* Minimized / maximized / fullscreen */ /* Minimized / maximized / fullscreen */
DWORD style = (DWORD)GetWindowLongPtr(hwnd, GWL_STYLE); DWORD style = (DWORD)GetWindowLongPtr(hwnd, GWL_STYLE);
DWORD ex_style = (DWORD)GetWindowLongPtr(hwnd, GWL_EXSTYLE); DWORD ex_style = (DWORD)GetWindowLongPtr(hwnd, GWL_EXSTYLE);
@ -518,7 +524,7 @@ WND_Frame WND_BeginFrame(void)
return result; return result;
} }
void WND_EndFrame(WND_Frame frame) void WND_EndFrame(WND_Frame frame, i32 vsync)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
WND_W32_SharedState *g = &WND_W32_shared_state; WND_W32_SharedState *g = &WND_W32_shared_state;
@ -656,6 +662,9 @@ void WND_EndFrame(WND_Frame frame)
BringWindowToTop(hwnd); BringWindowToTop(hwnd);
} }
/* Commit backbuffer */
GPU_CommitBackbuffer(frame.backbuffer, vsync);
++window->frame_gen; ++window->frame_gen;
EndScratch(scratch); EndScratch(scratch);
} }

View File

@ -4,9 +4,11 @@
Struct(WND_W32_Window) Struct(WND_W32_Window)
{ {
HWND hwnd; HWND hwnd;
GPU_SwapchainHandle swapchain;
GPU_ResourceHandle backbuffer;
Atomic32 is_ready; Atomic32 is_ready;
/* Window state */ /* Window proc state */
u16 previous_utf16_high_surrogate; u16 previous_utf16_high_surrogate;
/* User state */ /* User state */
@ -18,8 +20,7 @@ Struct(WND_W32_Window)
b32 is_fullscreen; b32 is_fullscreen;
RECT fullscreen_restore_rect; RECT fullscreen_restore_rect;
/* Window -> User */ /* Window proc -> User */
/* Reads outside of window thread must lock */
TicketMutex w2u_tm; TicketMutex w2u_tm;
Arena *w2u_events_arena; Arena *w2u_events_arena;
}; };