206 lines
4.6 KiB
C
206 lines
4.6 KiB
C
/* TODO: Remove this entire layer */
|
|
|
|
AC_SharedState AC_shared_state = ZI;
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Startup
|
|
|
|
void AC_Startup(void)
|
|
{
|
|
__prof;
|
|
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 RtcIsEnabled
|
|
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);
|
|
LAX lock;
|
|
|
|
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);
|
|
}
|