ui gpu refactor progress
This commit is contained in:
parent
0559ba8cba
commit
ed74c5cea5
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
@ -1,13 +0,0 @@
|
||||
@Layer asset_cache
|
||||
|
||||
//- Dependencies
|
||||
@Dep platform
|
||||
|
||||
//- Api
|
||||
@IncludeC asset_cache.h
|
||||
|
||||
//- Impl
|
||||
@IncludeC asset_cache.c
|
||||
|
||||
//- Startup
|
||||
@Startup AC_Startup
|
||||
@ -684,12 +684,12 @@
|
||||
|
||||
Struct(ResourceStore)
|
||||
{
|
||||
u64 hash;
|
||||
u64 v;
|
||||
};
|
||||
|
||||
Struct(ResourceKey)
|
||||
{
|
||||
u64 hash;
|
||||
u64 v;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
@ -46,13 +46,13 @@ void InitResourceSystem(u64 archive_strings_count, String *archive_strings)
|
||||
|
||||
b32 IsResourceNil(ResourceKey resource)
|
||||
{
|
||||
return resource.hash == 0;
|
||||
return resource.v == 0;
|
||||
}
|
||||
|
||||
ResourceKey ResourceKeyFromStore(ResourceStore *store, String name)
|
||||
{
|
||||
ResourceKey result = ZI;
|
||||
result.hash = HashFnv64(store->hash, name);
|
||||
result.v = HashFnv64(store->v, name);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -81,7 +81,7 @@ ResourceEntry *ResourceEntryFromHash(u64 hash)
|
||||
String DataFromResource(ResourceKey resource)
|
||||
{
|
||||
String result = ZI;
|
||||
ResourceEntry *entry = ResourceEntryFromHash(resource.hash);
|
||||
ResourceEntry *entry = ResourceEntryFromHash(resource.v);
|
||||
if (entry)
|
||||
{
|
||||
result = entry->data;
|
||||
@ -92,7 +92,7 @@ String DataFromResource(ResourceKey resource)
|
||||
String NameFromResource(ResourceKey resource)
|
||||
{
|
||||
String result = ZI;
|
||||
ResourceEntry *entry = ResourceEntryFromHash(resource.hash);
|
||||
ResourceEntry *entry = ResourceEntryFromHash(resource.v);
|
||||
if (entry)
|
||||
{
|
||||
result = entry->name;
|
||||
|
||||
247
src/font/font.c
247
src/font/font.c
@ -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;
|
||||
}
|
||||
@ -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);
|
||||
@ -1,12 +0,0 @@
|
||||
@Layer font
|
||||
|
||||
//- Dependencies
|
||||
@Dep ttf
|
||||
@Dep gpu
|
||||
@Dep asset_cache
|
||||
|
||||
//- Api
|
||||
@IncludeC font.h
|
||||
|
||||
//- Impl
|
||||
@IncludeC font.c
|
||||
297
src/glyph_cache/glyph_cache.c
Normal file
297
src/glyph_cache/glyph_cache.c
Normal 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;
|
||||
// }
|
||||
140
src/glyph_cache/glyph_cache.h
Normal file
140
src/glyph_cache/glyph_cache.h
Normal 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);
|
||||
11
src/glyph_cache/glyph_cache.lay
Normal file
11
src/glyph_cache/glyph_cache.lay
Normal file
@ -0,0 +1,11 @@
|
||||
@Layer glyph_cache
|
||||
|
||||
//- Dependencies
|
||||
@Dep ttf
|
||||
@Dep gpu
|
||||
|
||||
//- Api
|
||||
@IncludeC glyph_cache.h
|
||||
|
||||
//- Impl
|
||||
@IncludeC glyph_cache.c
|
||||
@ -1,7 +1,6 @@
|
||||
@Layer gpu
|
||||
|
||||
//- Dependencies
|
||||
@Dep window
|
||||
@Dep platform
|
||||
|
||||
//- Api
|
||||
|
||||
@ -50,47 +50,12 @@ void GPU_StartupCommon(void)
|
||||
GPU_CommitCommandList(cl);
|
||||
|
||||
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)
|
||||
{
|
||||
@ -103,28 +68,49 @@ GPU_ArenaHandle GPU_PermArena(void)
|
||||
return perm;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Cpu -> Gpu copy helpers
|
||||
//- Cpu -> Gpu copy
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Common resource helpers
|
||||
//- Viewport / scissor
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
GPU_IndexBufferDesc GPU_GetCommonQuadIndices(void)
|
||||
GPU_IndexBufferDesc GPU_GetSharedQuadIndices(void)
|
||||
{
|
||||
return GPU_shared_util_state.quad_indices;
|
||||
}
|
||||
|
||||
Texture3DHandle GPU_GetCommonNoise(void)
|
||||
Texture3DHandle GPU_GetSharedNoise(void)
|
||||
{
|
||||
return GPU_shared_util_state.noise_tex;
|
||||
}
|
||||
|
||||
@ -17,18 +17,25 @@ extern ThreadLocal GPU_ArenaHandle GPU_t_perm_arena;
|
||||
void GPU_StartupCommon(void);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Arena helpers
|
||||
//~ Helpers
|
||||
|
||||
//- Arena
|
||||
|
||||
GPU_ArenaHandle GPU_PermArena(void);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Cpu -> Gpu copy helpers
|
||||
//- Cpu -> Gpu copy
|
||||
|
||||
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);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Common resource helpers
|
||||
//- Viewport / scissor
|
||||
|
||||
SamplerStateHandle GPU_GetCommonPointSampler(void);
|
||||
GPU_IndexBufferDesc GPU_GetCommonQuadIndices(void);
|
||||
Texture3DHandle GPU_GetCommonNoise(void);
|
||||
Rng3 GPU_ViewportFromTexture(GPU_ResourceHandle texture);
|
||||
Rng2 GPU_ScissorFromTexture(GPU_ResourceHandle texture);
|
||||
|
||||
//- Shared resources
|
||||
|
||||
SamplerStateHandle GPU_GetSharedPointSampler(void);
|
||||
GPU_IndexBufferDesc GPU_GetSharedQuadIndices(void);
|
||||
Texture3DHandle GPU_GetSharedNoise(void);
|
||||
|
||||
@ -2,13 +2,15 @@
|
||||
//~ Handle types
|
||||
|
||||
Struct(GPU_ArenaHandle) { u64 v; };
|
||||
|
||||
Struct(GPU_CommandListHandle) { u64 v; };
|
||||
|
||||
Struct(GPU_ResourceHandle) { 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
|
||||
|
||||
@ -493,7 +495,8 @@ void GPU_Startup(void);
|
||||
GPU_ArenaHandle GPU_AcquireArena(void);
|
||||
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
|
||||
@ -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_PushSampler(GPU_ArenaHandle arena, GPU_SamplerDesc desc);
|
||||
|
||||
b32 GPU_IsResourceNil(GPU_ResourceHandle handle);
|
||||
|
||||
#define GPU_PushBuffer(arena, type, count, ...) GPU_PushBufferEx((arena), \
|
||||
(GPU_BufferDesc) { \
|
||||
.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)
|
||||
|
||||
//- Arena
|
||||
|
||||
void GPU_ResetArena(GPU_CommandListHandle cl, GPU_ArenaHandle arena);
|
||||
|
||||
//- 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_CopyCpuToTexture(GPU_CommandListHandle cl_handle, GPU_ResourceHandle dst_handle, Vec3I32 dst_offset, void *src, Vec3I32 src_dims, Rng3I32 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, GPU_ResourceHandle dst, Vec3I32 dst_offset, void *src, Vec3I32 src_dims, Rng3I32 src_copy_range);
|
||||
|
||||
//- 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_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_CopyTextureToTexture(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_handle, GPU_ResourceHandle dst_handle, Vec3I32 dst_offset, GPU_ResourceHandle src_handle, Rng3I32 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, GPU_ResourceHandle dst, Vec3I32 dst_offset, GPU_ResourceHandle src, Vec3I32 src_dims, 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, GPU_ResourceHandle dst, Vec3I32 dst_offset, GPU_ResourceHandle src, Rng3I32 src_copy_range);
|
||||
|
||||
//- Constant
|
||||
|
||||
@ -614,8 +611,8 @@ void GPU_BarrierEx(GPU_CommandListHandle cl, GPU_BarrierDesc desc);
|
||||
GPU_BarrierEx((_cl), (GPU_BarrierDesc) { \
|
||||
.resource = (_resource), \
|
||||
.sync_prev = _sync_prev, \
|
||||
.sync_next = _sync_next, \
|
||||
.access_prev = _access_prev, \
|
||||
.sync_next = _sync_next, \
|
||||
.access_next = _access_next, \
|
||||
})
|
||||
|
||||
@ -623,8 +620,8 @@ void GPU_BarrierEx(GPU_CommandListHandle cl, GPU_BarrierDesc desc);
|
||||
GPU_BarrierEx((_cl), (GPU_BarrierDesc) { \
|
||||
.resource = (_resource), \
|
||||
.sync_prev = _sync_prev, \
|
||||
.sync_next = _sync_next, \
|
||||
.access_prev = _access_prev, \
|
||||
.sync_next = _sync_next, \
|
||||
.access_next = _access_next, \
|
||||
.layout = _layout, \
|
||||
})
|
||||
@ -633,8 +630,8 @@ void GPU_BarrierEx(GPU_CommandListHandle cl, GPU_BarrierDesc desc);
|
||||
GPU_BarrierEx((_cl), (GPU_BarrierDesc) { \
|
||||
.is_global = 1, \
|
||||
.sync_prev = _sync_prev, \
|
||||
.sync_next = _sync_next, \
|
||||
.access_prev = _access_prev, \
|
||||
.sync_next = _sync_next, \
|
||||
.access_next = _access_next, \
|
||||
})
|
||||
|
||||
@ -653,30 +650,13 @@ void GPU_Compute(GPU_CommandListHandle cl, ComputeShader cs, Vec3I32 groups);
|
||||
|
||||
//- Rasterize
|
||||
|
||||
void GPU_RasterizeEx(GPU_CommandListHandle cl,
|
||||
void GPU_Rasterize(GPU_CommandListHandle cl,
|
||||
VertexShader vs, PixelShader ps,
|
||||
u32 instances_count, GPU_IndexBufferDesc index_buffer,
|
||||
u32 render_targets_count, GPU_ResourceHandle *render_targets,
|
||||
Rng3 viewport, Rng2 scissor,
|
||||
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
|
||||
|
||||
void GPU_ClearRenderTarget(GPU_CommandListHandle cl, GPU_ResourceHandle render_target, Vec4 color);
|
||||
@ -698,7 +678,7 @@ GPU_Stats GPU_QueryStats(void);
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @hookdecl Swapchain
|
||||
|
||||
GPU_SwapchainHandle GPU_AcquireSwapchain(WND_Handle window);
|
||||
GPU_SwapchainHandle GPU_AcquireSwapchain(u64 os_window_handle);
|
||||
void GPU_ReleaseSwapchain(GPU_SwapchainHandle swapchain);
|
||||
|
||||
/* Waits until a new backbuffer is ready from the swapchain.
|
||||
|
||||
@ -761,9 +761,25 @@ void GPU_ReleaseArena(GPU_ArenaHandle arena)
|
||||
/* 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);
|
||||
}
|
||||
|
||||
b32 GPU_IsResourceNil(GPU_ResourceHandle handle)
|
||||
{
|
||||
return handle.v == 0;
|
||||
}
|
||||
|
||||
//- Pointer creation
|
||||
|
||||
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 bound_compute_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_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);
|
||||
}
|
||||
|
||||
//- 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
|
||||
|
||||
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
|
||||
|
||||
void GPU_RasterizeEx(GPU_CommandListHandle cl_handle,
|
||||
void GPU_Rasterize(GPU_CommandListHandle cl_handle,
|
||||
VertexShader vs, PixelShader ps,
|
||||
u32 instances_count, GPU_IndexBufferDesc index_buffer,
|
||||
u32 render_targets_count, GPU_ResourceHandle *render_targets,
|
||||
@ -2500,14 +2497,14 @@ GPU_Stats GPU_QueryStats(void)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @hookimpl Swapchain
|
||||
|
||||
GPU_SwapchainHandle GPU_AcquireSwapchain(WND_Handle window)
|
||||
GPU_SwapchainHandle GPU_AcquireSwapchain(u64 os_window_handle)
|
||||
{
|
||||
GPU_D12_Swapchain *swapchain = 0;
|
||||
{
|
||||
Arena *perm = PermArena();
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
|
||||
//- Dependencies
|
||||
@Dep gpu
|
||||
@Dep sprite
|
||||
@Dep font
|
||||
@Dep platform
|
||||
@Dep window
|
||||
|
||||
@ -198,8 +198,8 @@ JobImpl(V_VisWorker, _, __)
|
||||
Vec4 swapchain_color = V_GetWidgetTheme().window_background_color;
|
||||
ui_frame_flags |= UI_FrameFlag_Debug * !!persist.ui_debug;
|
||||
ui_frame_flags |= UI_FrameFlag_Vsync * !!VSYNC;
|
||||
UI_Frame ui_frame = UI_BeginFrame(ui_frame_flags, swapchain_color);
|
||||
WND_Frame window_frame = ui_frame.window_frame;
|
||||
UI_Frame *ui_frame = UI_BeginFrame(ui_frame_flags, swapchain_color);
|
||||
WND_Frame window_frame = ui_frame->window_frame;
|
||||
|
||||
/* Restore window */
|
||||
{
|
||||
@ -296,7 +296,7 @@ JobImpl(V_VisWorker, _, __)
|
||||
}
|
||||
|
||||
/* 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 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_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);
|
||||
|
||||
/* Backdrop pass */
|
||||
|
||||
@ -2,12 +2,9 @@ void PT_RunForever(WaveLaneCtx *lane)
|
||||
{
|
||||
GPU_ArenaHandle gpu_frame_arena = GPU_AcquireArena();
|
||||
|
||||
b32 swapchain_initialized = 0;
|
||||
GPU_SwapchainHandle swapchain = ZI;
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
{
|
||||
@ -45,9 +35,9 @@ void PT_RunForever(WaveLaneCtx *lane)
|
||||
{
|
||||
GPU_SetConstant(cl, PT_ShaderConst_TestTarget, final_target_rwhandle);
|
||||
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_NoiseTex, GPU_GetCommonNoise());
|
||||
GPU_SetConstant(cl, PT_ShaderConst_NoiseTex, GPU_GetSharedNoise());
|
||||
}
|
||||
|
||||
/* Test pass */
|
||||
@ -59,20 +49,22 @@ void PT_RunForever(WaveLaneCtx *lane)
|
||||
/* Prep blit pass */
|
||||
{
|
||||
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 */
|
||||
{
|
||||
GPU_Rasterize(cl,
|
||||
PT_BlitVS, PT_BlitPS,
|
||||
1, GPU_GetCommonQuadIndices(),
|
||||
backbuffer, GPU_RasterMode_TriangleList);
|
||||
1, GPU_GetSharedQuadIndices(),
|
||||
1, &window_frame.backbuffer,
|
||||
GPU_ViewportFromTexture(window_frame.backbuffer), GPU_ScissorFromTexture(window_frame.backbuffer),
|
||||
GPU_RasterMode_TriangleList);
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
@ -82,9 +74,8 @@ void PT_RunForever(WaveLaneCtx *lane)
|
||||
}
|
||||
GPU_CommitCommandList(cl);
|
||||
}
|
||||
GPU_CommitBackbuffer(backbuffer, VSYNC);
|
||||
}
|
||||
WND_EndFrame(window_frame);
|
||||
WND_EndFrame(window_frame, VSYNC);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
//- Dependencies
|
||||
@Dep gpu
|
||||
@Dep window
|
||||
@Dep ui
|
||||
|
||||
//- Api
|
||||
@IncludeC proto_shaders.h
|
||||
|
||||
@ -2,19 +2,19 @@
|
||||
|
||||
//- Dependencies
|
||||
@Dep gpu
|
||||
@Dep font
|
||||
@Dep glyph_cache
|
||||
@Dep window
|
||||
|
||||
//- Api
|
||||
@IncludeC ui_core.h
|
||||
@IncludeC ui_common.h
|
||||
@IncludeC ui_gpu.h
|
||||
@IncludeGpu ui_gpu.h
|
||||
@IncludeC ui_shaders.h
|
||||
@IncludeGpu ui_shaders.h
|
||||
|
||||
//- Impl
|
||||
@IncludeC ui_core.c
|
||||
@IncludeC ui_common.c
|
||||
@IncludeGpu ui_gpu.hlsl
|
||||
@IncludeGpu ui_shaders.hlsl
|
||||
|
||||
//- Shaders
|
||||
@VertexShader UI_DRectVS
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
UI_Key UI_BuildLabel(String text)
|
||||
{
|
||||
UI_Key parent = UI_UseTop(Parent);
|
||||
ResourceKey font = UI_UseTop(Font);
|
||||
GC_FontKey font = UI_UseTop(Font);
|
||||
f32 font_size = UI_UseTop(FontSize);
|
||||
Vec4 tint = UI_UseTop(Tint);
|
||||
UI_Alignment alignment = UI_UseTop(ChildAlignment);
|
||||
|
||||
473
src/ui/ui_core.c
473
src/ui/ui_core.c
@ -5,17 +5,14 @@ UI_State UI_state = ZI;
|
||||
|
||||
void UI_Startup(void)
|
||||
{
|
||||
/* Prefetch default font */
|
||||
ResourceKey default_font = UI_GetDefaultFontResource();
|
||||
F_LoadFontAsync(default_font, 16);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ 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_State *g = &UI_state;
|
||||
u64 seed = ++g->bframe.transient_key_seed;
|
||||
UI_Frame *frame = UI_CurrentFrame();
|
||||
u64 seed = ++frame->transient_key_seed;
|
||||
UI_Key key = ZI;
|
||||
key.hash = RandU64FromSeed(seed);
|
||||
return key;
|
||||
@ -77,10 +74,10 @@ UI_Box *UI_BoxFromKey(UI_Key key)
|
||||
|
||||
String UI_StringF_(String fmt, ...)
|
||||
{
|
||||
UI_State *g = &UI_state;
|
||||
UI_Frame *frame = UI_CurrentFrame();
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
String str = FormatStringV(g->bframe.cmds_arena, fmt, args);
|
||||
String str = FormatStringV(frame->arena, fmt, args);
|
||||
va_end(args);
|
||||
return str;
|
||||
}
|
||||
@ -90,8 +87,8 @@ String UI_StringF_(String fmt, ...)
|
||||
|
||||
UI_Checkpoint UI_PushCP(UI_Key parent)
|
||||
{
|
||||
UI_State *g = &UI_state;
|
||||
UI_Stack *stack = g->bframe.top_stack;
|
||||
UI_Frame *frame = UI_CurrentFrame();
|
||||
UI_Stack *stack = frame->top_stack;
|
||||
stack->top_checkpoint.v += 1;
|
||||
if (parent.hash != 0)
|
||||
{
|
||||
@ -102,16 +99,16 @@ UI_Checkpoint UI_PushCP(UI_Key parent)
|
||||
|
||||
void UI_PopCP(UI_Checkpoint cp)
|
||||
{
|
||||
UI_State *g = &UI_state;
|
||||
UI_Stack *stack = g->bframe.top_stack;
|
||||
UI_Frame *frame = UI_CurrentFrame();
|
||||
UI_Stack *stack = frame->top_stack;
|
||||
for (UI_StyleKind kind = UI_StyleKind_None; kind < UI_StyleKind_Count; ++kind)
|
||||
{
|
||||
UI_StyleNode *n = stack->style_tops[kind];
|
||||
while (n && n->checkpoint.v >= cp.v)
|
||||
{
|
||||
UI_StyleNode *next = n->next;
|
||||
n->next = g->bframe.first_free_style_node;
|
||||
g->bframe.first_free_style_node = n;
|
||||
n->next = frame->first_free_style_node;
|
||||
frame->first_free_style_node = n;
|
||||
stack->style_tops[kind] = next;
|
||||
n = next;
|
||||
}
|
||||
@ -121,8 +118,8 @@ void UI_PopCP(UI_Checkpoint cp)
|
||||
|
||||
UI_Checkpoint UI_TopCP(void)
|
||||
{
|
||||
UI_State *g = &UI_state;
|
||||
UI_Stack *stack = g->bframe.top_stack;
|
||||
UI_Frame *frame = UI_CurrentFrame();
|
||||
UI_Stack *stack = frame->top_stack;
|
||||
return stack->top_checkpoint;
|
||||
}
|
||||
|
||||
@ -131,8 +128,8 @@ UI_Checkpoint UI_TopCP(void)
|
||||
|
||||
void UI_PushDefaults(void)
|
||||
{
|
||||
UI_State *g = &UI_state;
|
||||
UI_Stack *stack = g->bframe.top_stack;
|
||||
UI_Frame *frame = UI_CurrentFrame();
|
||||
UI_Stack *stack = frame->top_stack;
|
||||
UI_Checkpoint checkpoint = stack->top_checkpoint;
|
||||
{
|
||||
for (UI_StyleKind kind = UI_StyleKind_None; kind < UI_StyleKind_Count; ++kind)
|
||||
@ -144,8 +141,14 @@ void UI_PushDefaults(void)
|
||||
default: 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_Height: { desc.style.Height = UI_GROW(1, 0); } break;
|
||||
case UI_StyleKind_Font: { desc.style.Font = UI_GetDefaultFontResource(); } break;
|
||||
case UI_StyleKind_Height: { desc.style.Height = UI_GROW(1, 0); }
|
||||
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_Tint: { desc.style.Tint = Color_White; } 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)
|
||||
{
|
||||
UI_State *g = &UI_state;
|
||||
UI_Stack *stack = g->bframe.top_stack;
|
||||
UI_Frame *frame = UI_CurrentFrame();
|
||||
UI_Stack *stack = frame->top_stack;
|
||||
UI_StyleKind kind = desc.style.kind;
|
||||
if (kind >= UI_StyleKind_BeginVirtualStyles_)
|
||||
{
|
||||
@ -246,15 +249,15 @@ void UI_PushStyle(UI_StyleDesc desc)
|
||||
}
|
||||
else
|
||||
{
|
||||
n = g->bframe.first_free_style_node;
|
||||
n = frame->first_free_style_node;
|
||||
if (n)
|
||||
{
|
||||
g->bframe.first_free_style_node = n->next;
|
||||
frame->first_free_style_node = n->next;
|
||||
ZeroStruct(n);
|
||||
}
|
||||
else
|
||||
{
|
||||
n = PushStruct(g->bframe.cmds_arena, UI_StyleNode);
|
||||
n = PushStruct(frame->arena, UI_StyleNode);
|
||||
}
|
||||
n->next = stack->style_tops[kind];
|
||||
stack->style_tops[kind] = n;
|
||||
@ -272,7 +275,7 @@ void UI_PushStyle(UI_StyleDesc desc)
|
||||
|
||||
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;
|
||||
|
||||
case UI_StyleKind_Tag:
|
||||
@ -289,8 +292,8 @@ void UI_PushStyle(UI_StyleDesc desc)
|
||||
|
||||
UI_Style UI_PopStyle(UI_StyleDesc desc)
|
||||
{
|
||||
UI_State *g = &UI_state;
|
||||
UI_Stack *stack = g->bframe.top_stack;
|
||||
UI_Frame *frame = UI_CurrentFrame();
|
||||
UI_Stack *stack = frame->top_stack;
|
||||
UI_Style result = ZI;
|
||||
UI_StyleKind kind = desc.style.kind;
|
||||
result.kind = kind;
|
||||
@ -362,8 +365,8 @@ UI_Style UI_PopStyle(UI_StyleDesc desc)
|
||||
if (desc.use && n->pop_when_used)
|
||||
{
|
||||
stack->style_tops[kind] = n->next;
|
||||
n->next = g->bframe.first_free_style_node;
|
||||
g->bframe.first_free_style_node = n;
|
||||
n->next = frame->first_free_style_node;
|
||||
frame->first_free_style_node = n;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@ -374,8 +377,8 @@ UI_Style UI_PopStyle(UI_StyleDesc desc)
|
||||
|
||||
UI_Key UI_BuildBoxEx(UI_Key key)
|
||||
{
|
||||
UI_State *g = &UI_state;
|
||||
UI_CmdNode *n = PushStruct(g->bframe.cmds_arena, UI_CmdNode);
|
||||
UI_Frame *frame = UI_CurrentFrame();
|
||||
UI_CmdNode *n = PushStruct(frame->arena, UI_CmdNode);
|
||||
n->cmd.kind = UI_CmdKind_BuildBox;
|
||||
{
|
||||
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.tint = UI_UseTop(Tint);
|
||||
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.rounding = UI_UseTop(Rounding);
|
||||
n->cmd.box.text = UI_UseTop(Text);
|
||||
n->cmd.box.floating_pos = UI_UseTop(FloatingPos);
|
||||
}
|
||||
++g->bframe.cmds_count;
|
||||
SllQueuePush(g->bframe.first_cmd_node, g->bframe.last_cmd_node, n);
|
||||
++frame->cmds_count;
|
||||
SllQueuePush(frame->first_cmd_node, frame->last_cmd_node, n);
|
||||
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_CmdNode *n = PushStruct(g->bframe.cmds_arena, UI_CmdNode);
|
||||
UI_Frame *frame = UI_CurrentFrame();
|
||||
UI_CmdNode *n = PushStruct(frame->arena, UI_CmdNode);
|
||||
n->cmd.kind = UI_CmdKind_SetRawTexture;
|
||||
{
|
||||
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.uv1 = uv1;
|
||||
}
|
||||
++g->bframe.cmds_count;
|
||||
SllQueuePush(g->bframe.first_cmd_node, g->bframe.last_cmd_node, n);
|
||||
++frame->cmds_count;
|
||||
SllQueuePush(frame->first_cmd_node, frame->last_cmd_node, n);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -438,19 +441,9 @@ UI_Report UI_ReportFromKey(UI_Key key)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ 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_Frame result = ZI;
|
||||
UI_BFrameState old_bframe = g->bframe;
|
||||
|
||||
//////////////////////////////
|
||||
//- Wait on swapchain
|
||||
|
||||
if (g->eframe.swapchain)
|
||||
{
|
||||
GPU_YieldOnSwapchain(g->eframe.swapchain);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- 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_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
|
||||
|
||||
/* Zero frame data */
|
||||
/* Reset frame data */
|
||||
{
|
||||
ZeroStruct(&g->bframe);
|
||||
g->bframe.cmds_arena = old_bframe.cmds_arena;
|
||||
g->bframe.transient_key_seed;
|
||||
}
|
||||
if (!g->bframe.cmds_arena)
|
||||
{
|
||||
g->bframe.cmds_arena = AcquireArena(Gibi(64));
|
||||
Arena *old_arena = frame->arena;
|
||||
Arena *old_rects_arena = frame->arena;
|
||||
GPU_ArenaHandle old_gpu_arena = frame->gpu_arena;
|
||||
ZeroStruct(frame);
|
||||
frame->arena = old_arena;
|
||||
frame->rects_arena = old_rects_arena;
|
||||
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 dt_ns = now_ns - old_bframe.time_ns;
|
||||
g->bframe.time_ns = now_ns;
|
||||
g->bframe.dt_ns = dt_ns;
|
||||
g->bframe.tick = old_bframe.tick + 1;
|
||||
i64 dt_ns = now_ns - last_frame->time_ns;
|
||||
frame->time_ns = now_ns;
|
||||
frame->dt_ns = dt_ns;
|
||||
frame->tick = last_frame->tick + 1;
|
||||
}
|
||||
ResetArena(g->bframe.cmds_arena);
|
||||
|
||||
/* Init style stack */
|
||||
{
|
||||
g->bframe.top_stack = PushStruct(g->bframe.cmds_arena, UI_Stack);
|
||||
frame->top_stack = PushStruct(frame->arena, UI_Stack);
|
||||
UI_PushDefaults();
|
||||
}
|
||||
|
||||
g->bframe.frame_flags = frame_flags;
|
||||
g->bframe.swapchain_color = swapchain_color;
|
||||
|
||||
//////////////////////////////
|
||||
//- Begin window frame
|
||||
|
||||
g->bframe.window_frame = WND_BeginFrame();
|
||||
frame->frame_flags = frame_flags;
|
||||
frame->swapchain_color = swapchain_color;
|
||||
|
||||
//////////////////////////////
|
||||
//- 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;
|
||||
f64 dt = SecondsFromNs(g->bframe.dt_ns);
|
||||
frame->cursor_pos = last_frame->cursor_pos;
|
||||
f64 dt = SecondsFromNs(frame->dt_ns);
|
||||
f64 inv_dt = 1.0 / dt;
|
||||
|
||||
/* Locate boxes */
|
||||
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 */
|
||||
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];
|
||||
if (cev.kind == ControllerEventKind_CursorMove)
|
||||
{
|
||||
g->bframe.cursor_pos = Vec2FromFields(cev.cursor_pos);
|
||||
frame->cursor_pos = Vec2FromVec(cev.cursor_pos);
|
||||
}
|
||||
}
|
||||
|
||||
/* Init box reports */
|
||||
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)
|
||||
{
|
||||
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. */
|
||||
Vec2 p0 = box->p0;
|
||||
Vec2 p1 = box->p1;
|
||||
Vec2 point = g->bframe.cursor_pos;
|
||||
Vec2 point = frame->cursor_pos;
|
||||
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 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_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;
|
||||
}
|
||||
}
|
||||
@ -615,7 +625,7 @@ UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
|
||||
/* Update box hot & active states */
|
||||
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;
|
||||
f32 target_hot = box == active_box || (box == hovered_box && (box == active_box || active_box == 0));
|
||||
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;
|
||||
}
|
||||
|
||||
g->bframe.hovered_box = hovered_box ? hovered_box->key : UI_NilKey;
|
||||
g->bframe.active_box = active_box ? active_box->key : UI_NilKey;
|
||||
frame->hovered_box = hovered_box ? hovered_box->key : UI_NilKey;
|
||||
frame->active_box = active_box ? active_box->key : UI_NilKey;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Build root box
|
||||
|
||||
{
|
||||
UI_SetNext(Width, UI_PIX(g->bframe.window_frame.draw_size.x, 1));
|
||||
UI_SetNext(Height, UI_PIX(g->bframe.window_frame.draw_size.y, 1));
|
||||
UI_SetNext(Width, UI_PIX(frame->window_frame.draw_size.x, 1));
|
||||
UI_SetNext(Height, UI_PIX(frame->window_frame.draw_size.y, 1));
|
||||
UI_SetNext(Parent, UI_NilKey);
|
||||
UI_BuildBoxEx(UI_RootKey);
|
||||
}
|
||||
|
||||
result.window_frame = g->bframe.window_frame;
|
||||
result.cursor_pos = g->bframe.cursor_pos;
|
||||
result.hovered_box = g->bframe.hovered_box;
|
||||
result.active_box = g->bframe.hovered_box;
|
||||
return result;
|
||||
return frame;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Frame helpers
|
||||
|
||||
Arena *UI_FrameArena(void)
|
||||
UI_Frame *UI_CurrentFrame(void)
|
||||
{
|
||||
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)
|
||||
{
|
||||
UI_State *g = &UI_state;
|
||||
return g->bframe.cursor_pos;
|
||||
return UI_CurrentFrame()->cursor_pos;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ End frame
|
||||
|
||||
i64 UI_EndFrame(UI_Frame frame)
|
||||
void UI_EndFrame(UI_Frame *frame)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
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;
|
||||
Rng2 draw_viewport = ZI;
|
||||
draw_viewport.p1 = Vec2FromFields(draw_size);
|
||||
|
||||
//////////////////////////////
|
||||
//- 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);
|
||||
Vec2I32 draw_size = frame->window_frame.draw_size;
|
||||
Rng3 draw_viewport = RNG3(VEC3(0, 0, 0), VEC3(draw_size.x, draw_size.y, 1));
|
||||
Rng2 draw_scissor = RNG2(VEC2(0, 0), VEC2(draw_size.x, draw_size.y));
|
||||
|
||||
//////////////////////////////
|
||||
//- Process commands
|
||||
|
||||
/* FIXME: Reset raw texture data */
|
||||
|
||||
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;
|
||||
|
||||
@ -724,14 +710,14 @@ i64 UI_EndFrame(UI_Frame frame)
|
||||
key = UI_TransKey();
|
||||
}
|
||||
|
||||
b32 is_root = g->eframe.root_box == 0;
|
||||
b32 is_root = frame->root_box == 0;
|
||||
UI_Box *parent = 0;
|
||||
if (!is_root)
|
||||
{
|
||||
parent = UI_BoxFromKey(cmd.box.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->key = key;
|
||||
box->last_updated_tick = g->eframe.tick;
|
||||
box->last_updated_tick = frame->tick;
|
||||
|
||||
/* Update box */
|
||||
{
|
||||
@ -795,20 +781,17 @@ i64 UI_EndFrame(UI_Frame frame)
|
||||
++parent->count;
|
||||
}
|
||||
|
||||
/* Prefetch font */
|
||||
/* Fetch run */
|
||||
box->glyph_run = &GC_NilRun;
|
||||
if (box->desc.text.len > 0)
|
||||
{
|
||||
box->font = F_LoadFontAsync(box->desc.font_resource, box->desc.font_size);
|
||||
if (box->font)
|
||||
{
|
||||
box->glyph_run = F_RunFromString(g->eframe.layout_arena, box->font, box->desc.text);
|
||||
}
|
||||
box->glyph_run = GC_RunFromString(frame->arena, box->desc.font, box->desc.text);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_root)
|
||||
{
|
||||
g->eframe.root_box = box;
|
||||
frame->root_box = box;
|
||||
}
|
||||
} break;
|
||||
|
||||
@ -818,7 +801,7 @@ i64 UI_EndFrame(UI_Frame frame)
|
||||
UI_Box *box = UI_BoxFromKey(key);
|
||||
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_uv1 = cmd.set_raw_texture.uv1;
|
||||
}
|
||||
@ -831,7 +814,7 @@ i64 UI_EndFrame(UI_Frame frame)
|
||||
//- Prune boxes
|
||||
|
||||
// {
|
||||
// u64 cur_tick = g->eframe.tick;
|
||||
// u64 cur_tick = frame->tick;
|
||||
// UI_BoxIter it = UI_ITER(g->root_box);
|
||||
// UI_Box *box = UI_NextBox(&it);
|
||||
// while (box != 0)
|
||||
@ -846,10 +829,10 @@ i64 UI_EndFrame(UI_Frame frame)
|
||||
|
||||
/* Build pre-order & post-order box arrays */
|
||||
u64 boxes_count = g->boxes_count;
|
||||
UI_Box **boxes_pre = PushStructsNoZero(g->eframe.layout_arena, UI_Box *, boxes_count);
|
||||
UI_Box **boxes_post = PushStructsNoZero(g->eframe.layout_arena, UI_Box *, boxes_count);
|
||||
g->eframe.boxes_pre = boxes_pre;
|
||||
g->eframe.boxes_post = boxes_post;
|
||||
UI_Box **boxes_pre = PushStructsNoZero(frame->arena, UI_Box *, boxes_count);
|
||||
UI_Box **boxes_post = PushStructsNoZero(frame->arena, UI_Box *, boxes_count);
|
||||
frame->boxes_pre = boxes_pre;
|
||||
frame->boxes_post = boxes_post;
|
||||
{
|
||||
Struct(BoxNode) { BoxNode *next; b32 visited; UI_Box *box; };
|
||||
BoxNode *first_dfs = 0;
|
||||
@ -857,7 +840,7 @@ i64 UI_EndFrame(UI_Frame frame)
|
||||
u64 post_index = 0;
|
||||
{
|
||||
BoxNode *n = PushStruct(scratch.arena, BoxNode);
|
||||
n->box = g->eframe.root_box;
|
||||
n->box = frame->root_box;
|
||||
SllStackPush(first_dfs, n);
|
||||
}
|
||||
while (first_dfs)
|
||||
@ -916,21 +899,15 @@ i64 UI_EndFrame(UI_Frame frame)
|
||||
{
|
||||
/* TODO: Distinguish between baseline alignment & visual alignment */
|
||||
f32 text_size = 0;
|
||||
if (box->font)
|
||||
{
|
||||
if (axis == Axis_X)
|
||||
{
|
||||
if (box->glyph_run.count > 0)
|
||||
{
|
||||
F_RunRect rr = box->glyph_run.rects[box->glyph_run.count - 1];
|
||||
GC_RunRect rr = box->glyph_run->rects[box->glyph_run->count - 1];
|
||||
f32 baseline_length = rr.pos + rr.advance;
|
||||
text_size = baseline_length;
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
@ -1231,29 +1208,11 @@ i64 UI_EndFrame(UI_Frame frame)
|
||||
//////////////////////////////
|
||||
//- Render
|
||||
|
||||
GPU_CommandList *cl = GPU_OpenCommandList(GPU_QueueKind_Direct);
|
||||
GPU_CommandListHandle cl = GPU_PrepareCommandList(GPU_QueueKind_Direct);
|
||||
{
|
||||
//////////////////////////////
|
||||
//- 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 */
|
||||
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->p1.x > box->p0.x);
|
||||
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 */
|
||||
{
|
||||
UI_DRect *rect = PushStruct(g->eframe.rects_arena, UI_DRect);
|
||||
rect->flags |= UI_DRectFlag_DrawTexture * !(IsGpuPointerNil(box->raw_texture));
|
||||
UI_DRect *rect = PushStruct(frame->rects_arena, UI_DRect);
|
||||
rect->p0 = box->p0;
|
||||
rect->p1 = box->p1;
|
||||
rect->tex_uv0 = VEC2(0, 0);
|
||||
@ -1281,62 +1240,55 @@ i64 UI_EndFrame(UI_Frame frame)
|
||||
rect->tr_rounding = box->rounding_tr;
|
||||
rect->br_rounding = box->rounding_br;
|
||||
rect->bl_rounding = box->rounding_bl;
|
||||
|
||||
/* Texture */
|
||||
if (!IsGpuPointerNil(box->raw_texture))
|
||||
{
|
||||
rect->tex = box->raw_texture;
|
||||
rect->tex_uv0 = box->raw_texture_uv0;
|
||||
rect->tex_uv1 = box->raw_texture_uv1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
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 */
|
||||
GC_RunRect *truncated_rects = raw_run->rects;
|
||||
u32 truncated_rects_count = raw_run->count;
|
||||
if (should_truncate && !AnyBit(box->desc.flags, UI_BoxFlag_NoTextTruncation))
|
||||
{
|
||||
/* Get elipses run */
|
||||
F_Run trunc_run = F_RunFromString(scratch.arena, box->font, Lit("..."));
|
||||
if (trunc_run.count > 0)
|
||||
GC_Run *elipses_run = GC_RunFromString(scratch.arena, box->desc.font, Lit("..."));
|
||||
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 */
|
||||
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)
|
||||
{
|
||||
break;
|
||||
}
|
||||
--run.count;
|
||||
--truncated_rects_count;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
CopyStructs(new_rects, run.rects, run.count);
|
||||
f32 trunc_offset = run.count > 0 ? (run.rects[run.count - 1].pos + run.rects[run.count - 1].advance) : 0;
|
||||
for (u32 i = 0; i < trunc_run.count; ++i)
|
||||
truncated_rects_count += elipses_run->count;
|
||||
truncated_rects = PushStructsNoZero(scratch.arena, GC_RunRect, truncated_rects_count + elipses_run->count);
|
||||
CopyStructs(truncated_rects, raw_run->rects, raw_run->count);
|
||||
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];
|
||||
*rr = trunc_run.rects[i];
|
||||
rr->pos += trunc_offset;
|
||||
GC_RunRect *rr = &truncated_rects[i + truncated_rects_count];
|
||||
*rr = elipses_run->rects[i];
|
||||
rr->pos += elipses_offset;
|
||||
}
|
||||
}
|
||||
run.count += trunc_run.count;
|
||||
run.rects = new_rects;
|
||||
}
|
||||
|
||||
UI_AxisAlignment x_alignment = box->desc.child_alignment[Axis_X];
|
||||
@ -1347,10 +1299,10 @@ i64 UI_EndFrame(UI_Frame frame)
|
||||
}
|
||||
|
||||
/* Calculate baseline */
|
||||
f32 ascent = box->font->ascent;
|
||||
f32 descent = box->font->descent;
|
||||
f32 cap = box->font->cap;
|
||||
f32 baseline_width = run.count > 0 ? (run.rects[run.count - 1].pos + run.rects[run.count - 1].advance) : 0;
|
||||
f32 ascent = raw_run->ascent;
|
||||
f32 descent = raw_run->descent;
|
||||
f32 cap = raw_run->cap;
|
||||
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 box_width = box->p1.x - box->p0.x;
|
||||
f32 box_height = box->p1.y - box->p0.y;
|
||||
@ -1394,113 +1346,90 @@ i64 UI_EndFrame(UI_Frame frame)
|
||||
baseline = CeilVec2(baseline);
|
||||
|
||||
/* 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];
|
||||
Vec2 atlas_p0 = Vec2FromFields(rr.atlas_p0);
|
||||
Vec2 atlas_p1 = Vec2FromFields(rr.atlas_p1);
|
||||
Vec2 glyph_size = SubVec2(atlas_p1, atlas_p0);
|
||||
GC_RunRect rr = truncated_rects[i];
|
||||
Vec2 glyph_size = rr.size;
|
||||
if (glyph_size.x != 0 || glyph_size.y != 0)
|
||||
{
|
||||
UI_DRect *rect = PushStruct(g->eframe.rects_arena, UI_DRect);
|
||||
rect->flags |= UI_DRectFlag_DrawTexture;
|
||||
UI_DRect *rect = PushStruct(frame->rects_arena, UI_DRect);
|
||||
rect->p0 = AddVec2(baseline, VEC2(rr.pos, 0));
|
||||
rect->p0 = AddVec2(rect->p0, rr.offset);
|
||||
rect->p1 = AddVec2(rect->p0, glyph_size);
|
||||
rect->debug_lin = LinearFromSrgb(box->desc.debug_color);
|
||||
rect->tint_lin = LinearFromSrgb(box->desc.tint);
|
||||
rect->tex_uv0 = MulVec2Vec2(atlas_p0, inv_font_image_size);
|
||||
rect->tex_uv1 = MulVec2Vec2(atlas_p1, inv_font_image_size);
|
||||
rect->tex = tex_rid;
|
||||
rect->tex = rr.tex;
|
||||
rect->tex_uv0 = rr.uv.p0;
|
||||
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
|
||||
|
||||
/* 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
|
||||
{
|
||||
GPU_TransitionToRenderable(cl, g->eframe.draw_target, 0);
|
||||
GPU_ClearRenderable(cl, g->eframe.draw_target);
|
||||
GPU_DumbMemoryLayoutSync(cl, draw_target, GPU_Layout_DirectQueue_RenderTargetWrite);
|
||||
GPU_ClearRenderTarget(cl, draw_target, VEC4(0, 0, 0, 0));
|
||||
}
|
||||
|
||||
//- 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 */
|
||||
{
|
||||
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,
|
||||
&sig,
|
||||
UI_DRectVS, UI_DRectPS,
|
||||
1,
|
||||
viewport,
|
||||
scissor,
|
||||
draw_rects_count,
|
||||
GPU_GetCommonQuadIndices(),
|
||||
GPU_RasterizeMode_TriangleList);
|
||||
}
|
||||
1, GPU_GetSharedQuadIndices(),
|
||||
1, &draw_target,
|
||||
draw_viewport, draw_scissor,
|
||||
GPU_RasterMode_TriangleList);
|
||||
|
||||
/* Render rect wireframes */
|
||||
if (AnyBit(g->bframe.frame_flags, UI_FrameFlag_Debug))
|
||||
if (AnyBit(frame->frame_flags, UI_FrameFlag_Debug))
|
||||
{
|
||||
UI_DRectSig sig = ZI;
|
||||
sig.target_size = draw_size;
|
||||
sig.sampler = GPU_SamplerStateRidFromResource(GPU_GetCommonPointSampler());
|
||||
sig.rects = GPU_StructuredBufferRidFromResource(draw_rects_buffer);
|
||||
sig.debug_enabled = 1;
|
||||
GPU_SetConstant(cl, UI_ShaderConst_DebugDraw, 1);
|
||||
GPU_Rasterize(cl,
|
||||
&sig,
|
||||
UI_DRectVS, UI_DRectPS,
|
||||
1,
|
||||
viewport,
|
||||
scissor,
|
||||
draw_rects_count,
|
||||
GPU_GetCommonQuadIndices(),
|
||||
GPU_RasterizeMode_WireTriangleList);
|
||||
1, GPU_GetSharedQuadIndices(),
|
||||
1, &draw_target,
|
||||
draw_viewport, draw_scissor,
|
||||
GPU_RasterMode_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
|
||||
|
||||
{
|
||||
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;
|
||||
WND_EndFrame(frame->window_frame, VSYNC);
|
||||
|
||||
EndScratch(scratch);
|
||||
}
|
||||
|
||||
@ -106,10 +106,10 @@ Enum(UI_BoxFlag)
|
||||
X(Border, f32) \
|
||||
X(FloatingPos, Vec2) \
|
||||
X(Rounding, UI_Round) \
|
||||
X(Font, ResourceKey) \
|
||||
X(Font, GC_FontKey) \
|
||||
X(FontSize, u32) \
|
||||
X(Text, String) \
|
||||
X(BackgroundTexture, GpuPointer) \
|
||||
X(BackgroundTexture, Texture2DHandle) \
|
||||
X(BackgroundTextureUv0, Vec2) \
|
||||
X(BackgroundTextureUv1, Vec2) \
|
||||
/* --------------------------------------- */ \
|
||||
@ -217,7 +217,7 @@ Struct(UI_BoxDesc)
|
||||
f32 border;
|
||||
Vec2 floating_pos;
|
||||
String text;
|
||||
ResourceKey font_resource;
|
||||
GC_FontKey font;
|
||||
f32 font_size;
|
||||
Axis child_layout_axis;
|
||||
UI_AxisAlignment child_alignment[Axis_CountXY];
|
||||
@ -232,7 +232,7 @@ Struct(UI_Cmd)
|
||||
struct
|
||||
{
|
||||
UI_Key key;
|
||||
GPU_Resource *texture;
|
||||
Texture2DHandle tex;
|
||||
Vec2 uv0;
|
||||
Vec2 uv1;
|
||||
} set_raw_texture;
|
||||
@ -268,7 +268,7 @@ Struct(UI_Box)
|
||||
|
||||
//- Cmd data
|
||||
UI_BoxDesc desc;
|
||||
GpuPointer raw_texture;
|
||||
Texture2DHandle raw_texture;
|
||||
Vec2 raw_texture_uv0;
|
||||
Vec2 raw_texture_uv1;
|
||||
|
||||
@ -277,8 +277,7 @@ Struct(UI_Box)
|
||||
u64 post_index;
|
||||
|
||||
//- Layout data
|
||||
F_Run glyph_run;
|
||||
F_Font *font;
|
||||
GC_Run *glyph_run;
|
||||
f32 layout_cursor;
|
||||
f32 solved_dims[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)
|
||||
{
|
||||
@ -310,37 +311,12 @@ Enum(UI_FrameFlag)
|
||||
|
||||
Struct(UI_Frame)
|
||||
{
|
||||
Arena *arena;
|
||||
Arena *rects_arena;
|
||||
GPU_ArenaHandle gpu_arena;
|
||||
|
||||
WND_Frame window_frame;
|
||||
Vec2 cursor_pos;
|
||||
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;
|
||||
GPU_ResourceHandle backbuffer;
|
||||
|
||||
u64 transient_key_seed;
|
||||
|
||||
@ -364,28 +340,22 @@ Struct(UI_State)
|
||||
/* Style stack */
|
||||
UI_Stack *top_stack;
|
||||
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 */
|
||||
UI_Box *root_box;
|
||||
UI_Box **boxes_pre;
|
||||
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;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -396,7 +366,7 @@ void UI_Startup(void);
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Font helpers
|
||||
|
||||
ResourceKey UI_GetDefaultFontResource(void);
|
||||
GC_FontKey UI_GetDefaultFont(void);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Key helpers
|
||||
@ -472,7 +442,7 @@ UI_Style UI_PopStyle(UI_StyleDesc desc);
|
||||
UI_Key UI_BuildBoxEx(UI_Key key);
|
||||
#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
|
||||
@ -482,15 +452,16 @@ UI_Report UI_ReportFromKey(UI_Key key);
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ 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
|
||||
|
||||
UI_Frame *UI_CurrentFrame(void);
|
||||
Arena *UI_FrameArena(void);
|
||||
Vec2 UI_CursorPos(void);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ End frame
|
||||
|
||||
void UI_EndFrame(UI_Frame frame);
|
||||
void UI_EndFrame(UI_Frame *frame);
|
||||
|
||||
@ -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
27
src/ui/ui_shaders.h
Normal 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;
|
||||
};
|
||||
@ -1,7 +1,5 @@
|
||||
ConstantBuffer<UI_DRectSig> UI_drect_sig : register (b0);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Rect shader
|
||||
//~ Rect
|
||||
|
||||
Struct(UI_DRectPSInput)
|
||||
{
|
||||
@ -25,8 +23,7 @@ Struct(UI_DRectPSOutput)
|
||||
|
||||
VertexShader(UI_DRectVS, UI_DRectPSInput)
|
||||
{
|
||||
ConstantBuffer<UI_DRectSig> sig = UI_drect_sig;
|
||||
StructuredBuffer<UI_DRect> rects = UniformResourceFromRid(sig.rects);
|
||||
StructuredBuffer<UI_DRect> rects = StructuredBufferFromHandle<UI_DRect>(UI_ShaderConst_Rects);
|
||||
UI_DRect rect = rects[SV_InstanceID];
|
||||
|
||||
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);
|
||||
|
||||
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.border_lin = rect.border_lin;
|
||||
result.tint_lin = rect.tint_lin;
|
||||
@ -50,8 +47,9 @@ VertexShader(UI_DRectVS, UI_DRectPSInput)
|
||||
|
||||
PixelShader(UI_DRectPS, UI_DRectPSOutput, UI_DRectPSInput input)
|
||||
{
|
||||
ConstantBuffer<UI_DRectSig> sig = UI_drect_sig;
|
||||
StructuredBuffer<UI_DRect> rects = UniformResourceFromRid(sig.rects);
|
||||
StructuredBuffer<UI_DRect> rects = StructuredBufferFromHandle<UI_DRect>(UI_ShaderConst_Rects);
|
||||
SamplerState sampler = SamplerStateFromHandle(UI_ShaderConst_Sampler);
|
||||
|
||||
UI_DRect rect = rects[input.rect_idx];
|
||||
|
||||
Vec2 p = input.sv_position.xy;
|
||||
@ -108,10 +106,9 @@ PixelShader(UI_DRectPS, UI_DRectPSOutput, UI_DRectPSInput input)
|
||||
{
|
||||
background_color = border_color;
|
||||
}
|
||||
else if (rect.flags & UI_DRectFlag_DrawTexture)
|
||||
else if (!IsGpuHandleNil(rect.tex))
|
||||
{
|
||||
SamplerState sampler = UniformSamplerFromRid(sig.sampler);
|
||||
Texture2D<Vec4> tex = NonUniformResourceFromRid(rect.tex);
|
||||
Texture2D<Vec4> tex = Texture2DFromHandle<Vec4>(rect.tex);
|
||||
background_color = tex.Sample(sampler, input.tex_uv);
|
||||
}
|
||||
else
|
||||
@ -126,7 +123,7 @@ PixelShader(UI_DRectPS, UI_DRectPSOutput, UI_DRectPSInput input)
|
||||
final_color *= input.tint_lin;
|
||||
|
||||
/* Debug color */
|
||||
if (sig.debug_enabled)
|
||||
if (UI_ShaderConst_DebugDraw)
|
||||
{
|
||||
final_color = rect.debug_lin;
|
||||
}
|
||||
@ -29,9 +29,16 @@ Struct(WND_Cmd)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Frame types
|
||||
|
||||
Enum(WND_BackbufferSizeMode)
|
||||
{
|
||||
WND_BackbufferSizeMode_MatchWindow,
|
||||
WND_BackbufferSizeMode_MatchMonitor,
|
||||
};
|
||||
|
||||
Struct(WND_Frame)
|
||||
{
|
||||
WND_Handle window;
|
||||
GPU_ResourceHandle backbuffer;
|
||||
|
||||
ControllerEventsArray controller_events;
|
||||
|
||||
@ -51,11 +58,6 @@ Struct(WND_Frame)
|
||||
|
||||
void WND_Startup(void);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @hookdecl Helpers
|
||||
|
||||
u64 WND_OsHandleFromWindow(WND_Handle window);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @hookdecl Command
|
||||
|
||||
@ -65,5 +67,5 @@ void WND_PushCmd_(WND_Frame frame, WND_Cmd desc);
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @hookdecl Frame
|
||||
|
||||
WND_Frame WND_BeginFrame(void);
|
||||
void WND_EndFrame(WND_Frame frame);
|
||||
WND_Frame WND_BeginFrame(GPU_Format backbuffer_format, WND_BackbufferSizeMode backbuffer_size_mode);
|
||||
void WND_EndFrame(WND_Frame frame, i32 vsync);
|
||||
|
||||
@ -1,9 +1,13 @@
|
||||
@Layer window
|
||||
|
||||
//- Dependencies
|
||||
@Dep gpu
|
||||
|
||||
//- Api
|
||||
@IncludeC window.h
|
||||
|
||||
//- Win32 impl
|
||||
@DefaultWindowsImpl window_win32
|
||||
|
||||
//- Startup
|
||||
@Startup WND_Startup
|
||||
|
||||
@ -108,7 +108,6 @@ void WND_W32_ProcessMessagesForever(WaveLaneCtx *lane)
|
||||
window->w2u_events_arena = AcquireArena(Gibi(64));
|
||||
|
||||
//- Initialize hwnd
|
||||
HWND hwnd = 0;
|
||||
{
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/* TODO: Check for hwnd success */
|
||||
hwnd = CreateWindowExW(
|
||||
window->hwnd = CreateWindowExW(
|
||||
exstyle,
|
||||
g->window_class.lpszClassName,
|
||||
L"",
|
||||
@ -137,13 +136,17 @@ void WND_W32_ProcessMessagesForever(WaveLaneCtx *lane)
|
||||
|
||||
/* Dark mode */
|
||||
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 */
|
||||
/* 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
|
||||
Atomic32Set(&window->is_ready, 1);
|
||||
@ -382,15 +385,6 @@ LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM l
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @hookimpl Helpers
|
||||
|
||||
u64 WND_OsHandleFromWindow(WND_Handle handle)
|
||||
{
|
||||
WND_W32_Window *window = WND_W32_WindowFromHandle(handle);
|
||||
return (u64)window->hwnd;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @hookimpl Command
|
||||
|
||||
@ -409,7 +403,7 @@ void WND_PushCmd_(WND_Frame frame, WND_Cmd desc)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @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_Window *window = &g->window;
|
||||
@ -422,6 +416,41 @@ WND_Frame WND_BeginFrame(void)
|
||||
HWND hwnd = window->hwnd;
|
||||
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 */
|
||||
if (!window->frame_arena)
|
||||
{
|
||||
@ -444,29 +473,6 @@ WND_Frame WND_BeginFrame(void)
|
||||
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 */
|
||||
DWORD style = (DWORD)GetWindowLongPtr(hwnd, GWL_STYLE);
|
||||
DWORD ex_style = (DWORD)GetWindowLongPtr(hwnd, GWL_EXSTYLE);
|
||||
@ -518,7 +524,7 @@ WND_Frame WND_BeginFrame(void)
|
||||
return result;
|
||||
}
|
||||
|
||||
void WND_EndFrame(WND_Frame frame)
|
||||
void WND_EndFrame(WND_Frame frame, i32 vsync)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
WND_W32_SharedState *g = &WND_W32_shared_state;
|
||||
@ -656,6 +662,9 @@ void WND_EndFrame(WND_Frame frame)
|
||||
BringWindowToTop(hwnd);
|
||||
}
|
||||
|
||||
/* Commit backbuffer */
|
||||
GPU_CommitBackbuffer(frame.backbuffer, vsync);
|
||||
|
||||
++window->frame_gen;
|
||||
EndScratch(scratch);
|
||||
}
|
||||
|
||||
@ -4,9 +4,11 @@
|
||||
Struct(WND_W32_Window)
|
||||
{
|
||||
HWND hwnd;
|
||||
GPU_SwapchainHandle swapchain;
|
||||
GPU_ResourceHandle backbuffer;
|
||||
Atomic32 is_ready;
|
||||
|
||||
/* Window state */
|
||||
/* Window proc state */
|
||||
u16 previous_utf16_high_surrogate;
|
||||
|
||||
/* User state */
|
||||
@ -18,8 +20,7 @@ Struct(WND_W32_Window)
|
||||
b32 is_fullscreen;
|
||||
RECT fullscreen_restore_rect;
|
||||
|
||||
/* Window -> User */
|
||||
/* Reads outside of window thread must lock */
|
||||
/* Window proc -> User */
|
||||
TicketMutex w2u_tm;
|
||||
Arena *w2u_events_arena;
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user