diff --git a/src/app/app_core.c b/src/app/app_core.c index 4d8b353e..2d149b3a 100644 --- a/src/app/app_core.c +++ b/src/app/app_core.c @@ -239,7 +239,7 @@ void P_AppStartup(String args_str) /* Subsystems */ N_StartupReceipt host_sr = host_startup(); - AC_StartupReceipt asset_cache_sr = asset_cache_startup(); + AC_StartupReceipt asset_cache_sr = AC_Startup(); TTF_StartupReceipt ttf_sr = ttf_startup(); F_StartupReceipt font_sr = font_startup(&asset_cache_sr, &ttf_sr); S_StartupReceipt sprite_sr = sprite_startup(); diff --git a/src/asset_cache/asset_cache_core.c b/src/asset_cache/asset_cache_core.c index bfa782ed..ee513dfb 100644 --- a/src/asset_cache/asset_cache_core.c +++ b/src/asset_cache/asset_cache_core.c @@ -1,52 +1,43 @@ -/* ========================== * - * Global state - * ========================== */ +/* TODO: Remove this entire layer */ -#define MAX_ASSETS 1024 -#define ASSET_LOOKUP_TABLE_CAPACITY (MAX_ASSETS * 4) +AC_SharedState AC_shared_state = ZI; -Global struct { - P_Mutex lookup_mutex; - AC_Asset lookup[ASSET_LOOKUP_TABLE_CAPACITY]; - u64 num_assets; +//////////////////////////////// +//~ Startup - P_Mutex store_mutex; - Arena *store_arena; - -#if RtcIsEnabled - /* Array of len `num_assets` pointing into populated entries of `lookup`. */ - AC_Asset *dbg_table[ASSET_LOOKUP_TABLE_CAPACITY]; - u64 dbg_table_count; - P_Mutex dbg_table_mutex; -#endif -} G = ZI, DebugAlias(G, G_asset_cache); - -/* ========================== * - * Startup - * ========================== */ - -AC_StartupReceipt asset_cache_startup(void) +AC_StartupReceipt AC_Startup(void) { __prof; - /* Init store */ - G.store_arena = AllocArena(Gibi(64)); + AC_SharedState *g = &AC_shared_state; + g->store_arena = AllocArena(Gibi(64)); return (AC_StartupReceipt) { 0 }; } -/* ========================== * - * Lookup - * ========================== */ +//////////////////////////////// +//~ Hash -internal void refresh_dbg_table(void) +u64 AC_HashFromKey(String key) +{ + /* TODO: Better hash */ + return HashFnv64(Fnv64Basis, key); +} + +//////////////////////////////// +//~ Cache + +void AC_RefreshDebugTable(void) { #if RtcIsEnabled - P_Lock lock = P_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; + AC_SharedState *g = &AC_shared_state; + P_Lock lock = P_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; } } P_Unlock(&lock); @@ -55,38 +46,41 @@ internal void refresh_dbg_table(void) /* Returns first matching slot or first empty slot if not found. * Check returned slot->hash != 0 for presence. */ -internal AC_Asset *asset_cache_get_slot_locked(P_Lock *lock, String key, u64 hash) +AC_Asset *AC_GetAssetCacheSlotLocked(P_Lock *lock, String key, u64 hash) { - P_AssertLockedES(lock, &G.lookup_mutex); + AC_SharedState *g = &AC_shared_state; + P_AssertLockedES(lock, &g->lookup_mutex); (UNUSED)lock; - u64 index = hash % countof(G.lookup); - for (;;) { - AC_Asset *slot = &G.lookup[index]; - if (slot->hash) { + u64 index = hash % countof(g->lookup); + for (;;) + { + AC_Asset *slot = &g->lookup[index]; + if (slot->hash) + { /* Occupied */ - if (hash == slot->hash && EqString(key, slot->key)) { + if (hash == slot->hash && EqString(key, slot->key)) + { /* Matched slot */ return slot; - } else { + } + else + { ++index; - if (index >= countof(G.lookup)) { + if (index >= countof(g->lookup)) + { index = 0; } } - } else { + } + else + { /* Empty slot */ return slot; } } } -u64 asset_cache_hash(String key) -{ - /* TODO: Better hash */ - return HashFnv64(Fnv64Basis, key); -} - /* `key` text is copied by this function * * Returns existing asset entry or inserts a new one. @@ -95,38 +89,45 @@ u64 asset_cache_hash(String key) * inserted the asset into the cache. * * */ -AC_Asset *asset_cache_touch(String key, u64 hash, b32 *is_first_touch) +AC_Asset *AC_TouchCache(String key, u64 hash, b32 *is_first_touch) { AC_Asset *asset = 0; + AC_SharedState *g = &AC_shared_state; /* Lookup */ { - P_Lock lock = P_LockS(&G.lookup_mutex); - asset = asset_cache_get_slot_locked(&lock, key, hash); + P_Lock lock = P_LockS(&g->lookup_mutex); + asset = AC_GetAssetCacheSlotLocked(&lock, key, hash); P_Unlock(&lock); } /* Insert if not found */ - if (asset->hash) { - if (is_first_touch) { + if (asset->hash) + { + if (is_first_touch) + { *is_first_touch = 0; } - } else { - P_Lock lock = P_LockE(&G.lookup_mutex); + } + else + { + P_Lock lock = P_LockE(&g->lookup_mutex); /* Re-check asset presence in case it was inserted since lock */ - asset = asset_cache_get_slot_locked(&lock, key, hash); + asset = AC_GetAssetCacheSlotLocked(&lock, key, hash); - if (!asset->hash) { - if (G.num_assets >= MAX_ASSETS) { + if (!asset->hash) + { + if (g->num_assets >= AC_MaxAssets) + { P_Panic(Lit("Max assets reached")); } String key_stored = ZI; { /* CopyStruct key to store */ - AC_Store store = asset_cache_store_open(); + AC_Store store = AC_OpenStore(); key_stored = CopyString(store.arena, key); - asset_cache_store_close(&store); + AC_CloseStore(&store); } /* Initialize asset data */ P_LogInfoF("Inserting asset cache entry for \"%F\"", FmtString(key)); @@ -136,12 +137,13 @@ AC_Asset *asset_cache_touch(String key, u64 hash, b32 *is_first_touch) .key = key_stored }; P_CounterAdd(&asset->counter, 1); - if (is_first_touch) { + if (is_first_touch) + { *is_first_touch = 1; } - ++G.num_assets; + ++g->num_assets; - refresh_dbg_table(); + AC_RefreshDebugTable(); } P_Unlock(&lock); @@ -150,61 +152,56 @@ AC_Asset *asset_cache_touch(String key, u64 hash, b32 *is_first_touch) return asset; } -/* ========================== * - * Marking - * ========================== */ +//////////////////////////////// +//~ Status /* Call this once asset job has been created */ -void asset_cache_mark_loading(AC_Asset *asset) +void AC_MarkLoading(AC_Asset *asset) { asset->status = ASSET_STATUS_LOADING; } /* Call this once asset job has finished */ -void asset_cache_mark_ready(AC_Asset *asset, void *store_data) +void AC_MarkReady(AC_Asset *asset, void *store_data) { asset->store_data = store_data; asset->status = ASSET_STATUS_READY; P_CounterAdd(&asset->counter, -1); } -/* ========================== * - * Job - * ========================== */ - -void asset_cache_wait(AC_Asset *asset) +void AC_WaitOnAssetReady(AC_Asset *asset) { P_WaitOnCounter(&asset->counter); } -/* ========================== * - * Store - * ========================== */ +//////////////////////////////// +//~ Store -/* NOTE: At the moment only one global asset store exists, however in the - * future there could be more based on asset lifetime. */ - -void *asset_cache_get_store_data(AC_Asset *asset) +void *AC_DataFromStore(AC_Asset *asset) { - if (asset->status == ASSET_STATUS_READY) { + if (asset->status == ASSET_STATUS_READY) + { return asset->store_data; - } else { + } + else + { return 0; } } /* Asset store should be opened to allocate memory to the store arena */ -AC_Store asset_cache_store_open(void) +AC_Store AC_OpenStore(void) { - P_Lock lock = P_LockE(&G.store_mutex); + AC_SharedState *g = &AC_shared_state; + P_Lock lock = P_LockE(&g->store_mutex); AC_Store store = { .lock = lock, - .arena = G.store_arena + .arena = g->store_arena }; return store; } -void asset_cache_store_close(AC_Store *store) +void AC_CloseStore(AC_Store *store) { P_Unlock(&store->lock); } diff --git a/src/asset_cache/asset_cache_core.h b/src/asset_cache/asset_cache_core.h index 22b997ad..e4275cad 100644 --- a/src/asset_cache/asset_cache_core.h +++ b/src/asset_cache/asset_cache_core.h @@ -1,14 +1,19 @@ -typedef i32 AC_Status; enum { - ASSET_STATUS_NONE, +/* TODO: Remove this entire layer */ +//////////////////////////////// +//~ Asset types + +typedef i32 AC_Status; enum +{ + ASSET_STATUS_NONE, ASSET_STATUS_UNINITIALIZED, - /* TODO: ASSET_STATUS_QUEUED? */ ASSET_STATUS_LOADING, ASSET_STATUS_READY }; -Struct(AC_Asset) { - /* Managed via asset_cache_touch */ +Struct(AC_Asset) +{ + /* Managed via AC_TouchCache */ u64 hash; String key; @@ -21,25 +26,70 @@ Struct(AC_Asset) { void *store_data; }; -Struct(AC_Store) { +//////////////////////////////// +//~ Asset store types + +Struct(AC_Store) +{ Arena *arena; /* internal */ P_Lock lock; }; -Struct(AC_StartupReceipt) { i32 _; }; -AC_StartupReceipt asset_cache_startup(void); +//////////////////////////////// +//~ Shared state -AC_Asset *asset_cache_touch(String key, u64 hash, b32 *is_first_touch); +#define AC_MaxAssets 1024 +#define AC_AssetLookupTableCapacity (AC_MaxAssets * 4) -void asset_cache_mark_loading(AC_Asset *asset); -void asset_cache_mark_ready(AC_Asset *asset, void *store_data); +Struct(AC_SharedState) +{ + P_Mutex lookup_mutex; + AC_Asset lookup[AC_AssetLookupTableCapacity]; + u64 num_assets; -void asset_cache_wait(AC_Asset *asset); + P_Mutex store_mutex; + Arena *store_arena; -void *asset_cache_get_store_data(AC_Asset *asset); -AC_Store asset_cache_store_open(void); -void asset_cache_store_close(AC_Store *store); +#if RtcIsEnabled + /* Array of len `num_assets` pointing into populated entries of `lookup`. */ + AC_Asset *dbg_table[AC_AssetLookupTableCapacity]; + u64 dbg_table_count; + P_Mutex dbg_table_mutex; +#endif +}; -u64 asset_cache_hash(String key); +extern AC_SharedState AC_shared_state; + +//////////////////////////////// +//~ Startup + +Struct(AC_StartupReceipt) { i32 _; }; +AC_StartupReceipt AC_Startup(void); + +//////////////////////////////// +//~ Hash + +u64 AC_HashFromKey(String key); + +//////////////////////////////// +//~ Cache operations + +void AC_RefreshDebugTable(void); +AC_Asset *AC_GetAssetCacheSlotLocked(P_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_WaitOnAssetReady(AC_Asset *asset); + +//////////////////////////////// +//~ Store operations + +void *AC_DataFromStore(AC_Asset *asset); +AC_Store AC_OpenStore(void); +void AC_CloseStore(AC_Store *store); diff --git a/src/font/font_core.c b/src/font/font_core.c index 059ed812..b988655c 100644 --- a/src/font/font_core.c +++ b/src/font/font_core.c @@ -105,11 +105,11 @@ internal P_JobDef(font_load_asset_job, job) /* Allocate store memory */ F_Font *font = 0; { - AC_Store store = asset_cache_store_open(); + AC_Store store = AC_OpenStore(); font = PushStruct(store.arena, F_Font); font->glyphs = PushStructsNoZero(store.arena, F_Glyph, result.glyphs_count); font->lookup = PushStructs(store.arena, u16, LOOKUP_TABLE_SIZE); - asset_cache_store_close(&store); + AC_CloseStore(&store); } /* Set font data */ @@ -139,7 +139,7 @@ internal P_JobDef(font_load_asset_job, job) font_task_params_release(params); P_LogSuccessF("Loaded font \"%F\" (point size %F) in %F seconds", FmtString(path), FmtFloat((f64)point_size), FmtFloat(SecondsFromNs(P_TimeNs() - start_ns))); - asset_cache_mark_ready(asset, font); + AC_MarkReady(asset, font); EndScratch(scratch); } @@ -155,9 +155,9 @@ AC_Asset *font_load_asset(String path, f32 point_size, b32 wait) Lit("%F%F_font"), FmtString(path), FmtFloatP((f64)point_size, 1)); - u64 hash = asset_cache_hash(key); + u64 hash = AC_HashFromKey(key); b32 is_first_touch; - AC_Asset *asset = asset_cache_touch(key, hash, &is_first_touch); + AC_Asset *asset = AC_TouchCache(key, hash, &is_first_touch); if (is_first_touch) { /* Assemble task params */ @@ -173,10 +173,10 @@ AC_Asset *font_load_asset(String path, f32 point_size, b32 wait) params->point_size = point_size; /* PushStruct task */ - asset_cache_mark_loading(asset); + AC_MarkLoading(asset); P_Run(1, font_load_asset_job, params, P_Pool_Background, P_Priority_Low, 0); if (wait) { - asset_cache_wait(asset); + AC_WaitOnAssetReady(asset); } } @@ -188,7 +188,7 @@ F_Font *font_load_async(String path, f32 point_size) { __prof; AC_Asset *asset = font_load_asset(path, point_size, 0); - F_Font *f = (F_Font *)asset_cache_get_store_data(asset); + F_Font *f = (F_Font *)AC_DataFromStore(asset); return f; } @@ -196,8 +196,8 @@ F_Font *font_load(String path, f32 point_size) { __prof; AC_Asset *asset = font_load_asset(path, point_size, 1); - asset_cache_wait(asset); - F_Font *f = (F_Font *)asset_cache_get_store_data(asset); + AC_WaitOnAssetReady(asset); + F_Font *f = (F_Font *)AC_DataFromStore(asset); return f; } diff --git a/src/sound/sound_core.c b/src/sound/sound_core.c index 6d0f58c3..7d90bdb6 100644 --- a/src/sound/sound_core.c +++ b/src/sound/sound_core.c @@ -108,10 +108,10 @@ internal P_JobDef(sound_load_asset_job, job) u64 samples_count = decoded.samples_count; i16 *samples = 0; { - AC_Store store = asset_cache_store_open(); + AC_Store store = AC_OpenStore(); sound = PushStructNoZero(store.arena, SND_Sound); samples = PushStructsNoZero(store.arena, i16, samples_count); - asset_cache_store_close(&store); + AC_CloseStore(&store); } /* Initialize */ @@ -122,19 +122,19 @@ internal P_JobDef(sound_load_asset_job, job) CopyBytes(sound->samples, decoded.samples, decoded.samples_count * sizeof(*decoded.samples)); P_LogSuccessF("Loaded sound \"%F\" in %F seconds", FmtString(path), FmtFloat(SecondsFromNs(P_TimeNs() - start_ns))); - asset_cache_mark_ready(asset, sound); + AC_MarkReady(asset, sound); } else { P_LogErrorF("Error loading sound \"%F\": %F", FmtString(path), FmtString(error_msg)); /* Store */ SND_Sound *sound = 0; { - AC_Store store = asset_cache_store_open(); + AC_Store store = AC_OpenStore(); sound = PushStructNoZero(store.arena, SND_Sound); - asset_cache_store_close(&store); + AC_CloseStore(&store); } *sound = (SND_Sound) { 0 }; - asset_cache_mark_ready(asset, sound); + AC_MarkReady(asset, sound); } sound_task_params_release(params); @@ -152,9 +152,9 @@ AC_Asset *sound_load_asset(String path, u32 flags, b32 wait) Lit("%F%F_sound"), FmtString(path), FmtUint((u64)flags)); - u64 hash = asset_cache_hash(key); + u64 hash = AC_HashFromKey(key); b32 is_first_touch; - AC_Asset *asset = asset_cache_touch(key, hash, &is_first_touch); + AC_Asset *asset = AC_TouchCache(key, hash, &is_first_touch); if (is_first_touch) { /* Assemble task params */ @@ -170,10 +170,10 @@ AC_Asset *sound_load_asset(String path, u32 flags, b32 wait) params->flags = flags; /* PushStruct task */ - asset_cache_mark_loading(asset); + AC_MarkLoading(asset); P_Run(1, sound_load_asset_job, params, P_Pool_Background, P_Priority_Low, &asset->counter); if (wait) { - asset_cache_wait(asset); + AC_WaitOnAssetReady(asset); } } @@ -185,7 +185,7 @@ SND_Sound *sound_load_async(String path, u32 flags) { __prof; AC_Asset *asset = sound_load_asset(path, flags, 0); - SND_Sound *sound = (SND_Sound *)asset_cache_get_store_data(asset); + SND_Sound *sound = (SND_Sound *)AC_DataFromStore(asset); return sound; } @@ -194,7 +194,7 @@ SND_Sound *sound_load(String path, u32 flags) { __prof; AC_Asset *asset = sound_load_asset(path, flags, 1); - asset_cache_wait(asset); - SND_Sound *sound = (SND_Sound *)asset_cache_get_store_data(asset); + AC_WaitOnAssetReady(asset); + SND_Sound *sound = (SND_Sound *)AC_DataFromStore(asset); return sound; }