job refactor progress

This commit is contained in:
jacob 2025-08-05 10:26:13 -05:00
parent 7906108994
commit 63e1412752
40 changed files with 727 additions and 707 deletions

View File

@ -29,7 +29,7 @@ void AC_RefreshDebugTable(void)
{
#if RtcIsEnabled
AC_SharedState *g = &AC_shared_state;
P_Lock lock = P_LockE(&g->dbg_table_mutex);
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)
@ -40,16 +40,16 @@ void AC_RefreshDebugTable(void)
g->dbg_table[g->dbg_table_count++] = asset;
}
}
P_Unlock(&lock);
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(P_Lock *lock, String key, u64 hash)
AC_Asset *AC_GetAssetCacheSlotLocked(Lock *lock, String key, u64 hash)
{
AC_SharedState *g = &AC_shared_state;
P_AssertLockedES(lock, &g->lookup_mutex);
AssertLockedES(lock, &g->lookup_mutex);
LAX lock;
u64 index = hash % countof(g->lookup);
@ -96,9 +96,9 @@ AC_Asset *AC_TouchCache(String key, u64 hash, b32 *is_first_touch)
/* Lookup */
{
P_Lock lock = P_LockS(&g->lookup_mutex);
Lock lock = LockS(&g->lookup_mutex);
asset = AC_GetAssetCacheSlotLocked(&lock, key, hash);
P_Unlock(&lock);
Unlock(&lock);
}
/* Insert if not found */
@ -111,7 +111,7 @@ AC_Asset *AC_TouchCache(String key, u64 hash, b32 *is_first_touch)
}
else
{
P_Lock lock = P_LockE(&g->lookup_mutex);
Lock lock = LockE(&g->lookup_mutex);
/* Re-check asset presence in case it was inserted since lock */
asset = AC_GetAssetCacheSlotLocked(&lock, key, hash);
@ -136,7 +136,7 @@ AC_Asset *AC_TouchCache(String key, u64 hash, b32 *is_first_touch)
.hash = hash,
.key = key_stored
};
P_CounterAdd(&asset->counter, 1);
AddCounter(&asset->counter, 1);
if (is_first_touch)
{
*is_first_touch = 1;
@ -146,7 +146,7 @@ AC_Asset *AC_TouchCache(String key, u64 hash, b32 *is_first_touch)
AC_RefreshDebugTable();
}
P_Unlock(&lock);
Unlock(&lock);
}
return asset;
@ -166,12 +166,12 @@ void AC_MarkReady(AC_Asset *asset, void *store_data)
{
asset->store_data = store_data;
asset->status = ASSET_STATUS_READY;
P_CounterAdd(&asset->counter, -1);
AddCounter(&asset->counter, -1);
}
void AC_WaitOnAssetReady(AC_Asset *asset)
{
P_WaitOnCounter(&asset->counter);
WaitOnCounter(&asset->counter);
}
////////////////////////////////
@ -193,7 +193,7 @@ void *AC_DataFromStore(AC_Asset *asset)
AC_Store AC_OpenStore(void)
{
AC_SharedState *g = &AC_shared_state;
P_Lock lock = P_LockE(&g->store_mutex);
Lock lock = LockE(&g->store_mutex);
AC_Store store = {
.lock = lock,
.arena = g->store_arena
@ -203,5 +203,5 @@ AC_Store AC_OpenStore(void)
void AC_CloseStore(AC_Store *store)
{
P_Unlock(&store->lock);
Unlock(&store->lock);
}

View File

@ -34,7 +34,7 @@ Struct(AC_Store)
Arena *arena;
/* internal */
P_Lock lock;
Lock lock;
};
////////////////////////////////
@ -45,18 +45,18 @@ Struct(AC_Store)
Struct(AC_SharedState)
{
P_Mutex lookup_mutex;
Mutex lookup_mutex;
AC_Asset lookup[AC_AssetLookupTableCapacity];
u64 num_assets;
P_Mutex store_mutex;
Mutex store_mutex;
Arena *store_arena;
#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;
Mutex dbg_table_mutex;
#endif
};
@ -77,7 +77,7 @@ 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_GetAssetCacheSlotLocked(Lock *lock, String key, u64 hash);
AC_Asset *AC_TouchCache(String key, u64 hash, b32 *is_first_touch);
////////////////////////////////

View File

@ -10,9 +10,10 @@
#include "base_uid.c"
#include "base_uni.c"
#include "base_incbin.c"
#include "base_snc.c"
#if PlatformIsWindows
# include "win32/base_win32.c"
#else
# error Base layer platform backend not implemented
#enidf
#endif

View File

@ -8,8 +8,9 @@
#include "../prof/prof.h"
# include "base_intrinsics.h"
# include "base_memory.h"
# include "base_job.h"
# include "base_arena.h"
# include "base_snc.h"
# include "base_job.h"
# include "base_uid.h"
# include "base_string.h"
# include "base_uni.h"

View File

@ -548,6 +548,23 @@ ForceInline void UnlockTicketMutex(TicketMutex *tm)
}
#endif
////////////////////////////////
//~ Fibers
#define MaxFibers 4096
#if !LanguageIsGpu
ForceInline i16 FiberId(void)
{
/* FIXME */
//return (i16)(i64)GetFiberData();
Assert(0);
return 0;
}
StaticAssert(MaxFibers < I16Max); /* Fiber id type should fit max fibers */
#endif
////////////////////////////////
//~ Config

View File

@ -33,30 +33,59 @@ typedef i32 PriorityKind; enum
};
////////////////////////////////
//~ @hookdecl Fiber helpers
//~ @hookdecl Futex
#define MaxFibers 4096
i16 FiberId(void);
StaticAssert(MaxFibers < I16Max); /* Fiber id type should fit max fibers */
/* Futex-like wait & wake */
void FutexWait(volatile void *addr, void *cmp, u32 size, i64 timeout_ns);
void FutexWake(void *addr, i32 count);
////////////////////////////////
//~ @hookdecl Job helpers
#define EmptySig { i32 _; }
typedef void GenericJobFunc(void *, i32);
Struct(GenericJobDesc)
{
Arena *arena;
void *sig;
GenericJobFunc *func;
i32 count;
PoolKind pool;
PriorityKind priority;
Counter *counter;
};
Struct(JobDescParams)
{
i32 count;
PoolKind pool;
PriorityKind priority;
Counter *counter;
};
#define JobDecl(job, sigdef) \
typedef struct job##_Sig sigdef job##_Sig; \
Struct(job##_Desc) { Counter *counter; Arena *job_arena; job##_Sig *sig; }; \
void job(job##_Sig *)
Struct(job##_Desc) { Arena *arena; job##_Sig *sig; GenericJobFunc *func; i32 count; PoolKind pool; PriorityKind priority; Counter *counter;}; \
void job(job##_Sig *, i32)
#define JobDef(job, sig_arg) void job(job##_Sig *sig_arg)
#define PushJobDesc(job, ...) (job##_Desc *)PushJobDesc_(sizeof(job##_Sig), alignof(job##_Sig), (GenericJobFunc *)(i64)job, (JobDescParams) { .count = 1, .pool = PoolKind_Inherit, .priority = PriorityKind_Inherit, .counter = 0, __VA_ARGS__ })
GenericJobDesc *PushJobDesc_(u64 sig_size, u64 sig_align, GenericJobFunc *func, JobDescParams params);
#define RunJob(job, desc) job(&desc->sig)
#define JobDef(job, sig_arg, id_arg) void job(job##_Sig *sig_arg, i32 id_arg)
#define RunJob(_count, job, _pool, _priority, _counter, ...) do { \
job##_Desc *__job_desc = (job##_Desc *)PushJobDesc_(sizeof(job##_Sig), alignof(job##_Sig), (GenericJobFunc *)(i64)job, (JobDescParams) { .count = _count, .pool = _pool, .priority = _priority, .counter = _counter,}); \
*__job_desc->sig = (job##_Sig) { __VA_ARGS__ }; \
} while (0)
void RunJobEx(GenericJobDesc *desc);
////////////////////////////////
//~ @hookdecl Wait
//~ @hookdecl Helpers
/* Futex-like wait & wake */
void P_Wait(volatile void *addr, void *cmp, u32 size, i64 timeout_ns);
void P_Wake(void *addr, i32 count);
i64 TimeNs(void);
u32 GetLogicalProcessorCount(void);
u32 ThreadId(void);
i64 GetCurrentSchedulerPeriodNs(void);

View File

@ -2,8 +2,10 @@
//~ True randomness
#if PlatformIsWindows
#if 0
# define BCRYPT_RNG_ALG_HANDLE ((void *)0x00000081)
u32 BCryptGenRandom(void *algorithm, u8 *buffer, u32 buffer_size, u32 flags);
#endif
void TrueRand(String buffer)
{
BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, (u8 *)buffer.text, buffer.len, 0);

View File

@ -2,7 +2,7 @@
//~ Mutex
//- Exclusive mutex lock
P_Lock P_LockSpinE(P_Mutex *m, i32 spin)
Lock LockSpinE(Mutex *m, i32 spin)
{
b32 locked = 0;
i32 spin_cnt = 0;
@ -49,7 +49,7 @@ P_Lock P_LockSpinE(P_Mutex *m, i32 spin)
}
else
{
P_Wait(&m->v, &v, 4, I64Max);
FutexWait(&m->v, &v, 4, I64Max);
spin_cnt = 0;
}
}
@ -59,14 +59,14 @@ P_Lock P_LockSpinE(P_Mutex *m, i32 spin)
Atomic32FetchSet(&m->exclusive_fiber_id, FiberId());
#endif
P_Lock lock = ZI;
Lock lock = ZI;
lock.exclusive = 1;
lock.mutex = m;
return lock;
}
//- Shared mutex lock
P_Lock P_LockSpinS(P_Mutex *m, i32 spin)
Lock LockSpinS(Mutex *m, i32 spin)
{
b32 locked = 0;
i32 spin_cnt = 0;
@ -96,30 +96,30 @@ P_Lock P_LockSpinS(P_Mutex *m, i32 spin)
}
else
{
P_Wait(&m->v, &v, 4, I64Max);
FutexWait(&m->v, &v, 4, I64Max);
spin_cnt = 0;
}
}
}
P_Lock lock = ZI;
Lock lock = ZI;
lock.mutex = m;
return lock;
}
//- Mutex lock wrappers
P_Lock P_LockE(P_Mutex *m)
Lock LockE(Mutex *m)
{
return P_LockSpinE(m, P_DefaultMutexSpin);
return LockSpinE(m, DefaultMutexSpin);
}
P_Lock P_LockS(P_Mutex *m)
Lock LockS(Mutex *m)
{
return P_LockSpinS(m, P_DefaultMutexSpin);
return LockSpinS(m, DefaultMutexSpin);
}
void P_Unlock(P_Lock *l)
void Unlock(Lock *l)
{
P_Mutex *m = l->mutex;
Mutex *m = l->mutex;
if (l->exclusive)
{
#if RtcIsEnabled
@ -131,64 +131,64 @@ void P_Unlock(P_Lock *l)
{
Atomic32FetchAdd(&m->v, -1);
}
P_Wake(&m->v, I32Max);
FutexWake(&m->v, I32Max);
ZeroStruct(l);
}
////////////////////////////////
//~ Condition variable
void P_WaitOnCv(P_Cv *cv, P_Lock *l)
void WaitOnCv(Cv *cv, Lock *l)
{
P_WaitOnCvTime(cv, l, I64Max);
WaitOnCvTime(cv, l, I64Max);
}
void P_WaitOnCvTime(P_Cv *cv, P_Lock *l, i64 timeout_ns)
void WaitOnCvTime(Cv *cv, Lock *l, i64 timeout_ns)
{
u64 old_wake_gen = Atomic64Fetch(&cv->wake_gen);
P_Mutex *mutex = l->mutex;
Mutex *mutex = l->mutex;
b32 exclusive = l->exclusive;
{
P_Unlock(l);
Unlock(l);
{
P_Wait(&cv->wake_gen, &old_wake_gen, sizeof(old_wake_gen), timeout_ns);
FutexWait(&cv->wake_gen, &old_wake_gen, sizeof(old_wake_gen), timeout_ns);
}
if (exclusive)
{
*l = P_LockE(mutex);
*l = LockE(mutex);
}
else
{
*l = P_LockS(mutex);
*l = LockS(mutex);
}
}
}
void P_SignalCv(P_Cv *cv, i32 count)
void SignalCv(Cv *cv, i32 count)
{
Atomic64FetchAdd(&cv->wake_gen, 1);
P_Wake(&cv->wake_gen, count);
FutexWake(&cv->wake_gen, count);
}
////////////////////////////////
//~ Counter
void P_CounterAdd(Counter *counter, i64 x)
void AddCounter(Counter *counter, i64 x)
{
i64 old_v = Atomic64FetchAdd(&counter->v, x);
i64 new_v = old_v + x;
if (old_v > 0 && new_v <= 0)
{
P_Wake(&counter->v, I32Max);
FutexWake(&counter->v, I32Max);
}
}
void P_WaitOnCounter(Counter *counter)
void WaitOnCounter(Counter *counter)
{
i64 v = Atomic64Fetch(&counter->v);
while (v > 0)
{
P_Wait(&counter->v, &v, sizeof(v), I64Max);
FutexWait(&counter->v, &v, sizeof(v), I64Max);
v = Atomic64Fetch(&counter->v);
}
}

83
src/base/base_snc.h Normal file
View File

@ -0,0 +1,83 @@
////////////////////////////////
//~ Mutex types
#define DefaultMutexSpin 4000
AlignedStruct(Mutex, 64)
{
/* Bit 31 = Exclusive lock is held
* Bit 30 = Exclusive lock is pending
* Bit 0-30 = Shared locks count
*/
Atomic32 v;
#if RtcIsEnabled
Atomic32 exclusive_fiber_id;
u8 _pad[56];
#else
u8 _pad[60];
#endif
};
StaticAssert(sizeof(Mutex) == 64); /* Padding validation */
StaticAssert(alignof(Mutex) == 64); /* Prevent false sharing */
Struct(Lock)
{
Mutex *mutex;
b32 exclusive;
};
////////////////////////////////
//~ Condition variable types
AlignedStruct(Cv, 64)
{
Atomic64 wake_gen;
u8 _pad[56];
};
StaticAssert(sizeof(Cv) == 64); /* Padding validation */
StaticAssert(alignof(Cv) == 64); /* Prevent false sharing */
////////////////////////////////
//~ Counter types
AlignedStruct(Counter, 64)
{
Atomic64 v;
u8 _pad[56];
};
StaticAssert(sizeof(Counter) == 64); /* Padding validation */
StaticAssert(alignof(Counter) == 64); /* Prevent false sharing */
////////////////////////////////
//~ Mutex operations
Lock LockSpinE(Mutex *m, i32 spin);
Lock LockSpinS(Mutex *m, i32 spin);
Lock LockE(Mutex *m);
Lock LockS(Mutex *m);
void Unlock(Lock *lock);
//- Lock assertion
#if RtcIsEnabled
# define AssertLockedE(l, m) Assert((l)->mutex == (m) && (l)->exclusive == 1)
# define AssertLockedES(l, m) Assert((l)->mutex == (m))
#else
# define AssertLockedE(l, m) LAX l
# define AssertLockedES(l, m) LAX l
#endif
////////////////////////////////
//~ Condition variable operations
void WaitOnCv(Cv *cv, Lock *lock);
void WaitOnCvTime(Cv *cv, Lock *l, i64 timeout_ns);
void SignalCv(Cv *cv, i32 count);
////////////////////////////////
//~ Counter operations
void AddCounter(Counter *counter, i64 x);
void WaitOnCounter(Counter *counter);

View File

@ -63,12 +63,12 @@ String StringFromI64(Arena *arena, i64 n, u64 base, u64 zfill)
u8 len = 0;
if (n < 0)
{
/* PushStruct sign */
/* Push sign */
StringFromChar(arena, '-');
len = 1;
n = -n;
}
/* PushStruct unsigned number */
/* Push unsigned number */
String uint_str = StringFromU64(arena, n, base, zfill);
return (String)
{

View File

@ -1,5 +1,7 @@
W32_SharedCtx W32_shared_ctx = ZI;
/* FIXME: Enable logs, panic, shutdown */
////////////////////////////////
//~ Win32 libs
@ -21,6 +23,19 @@ void StartupJobs(void)
{
W32_SharedCtx *g = &W32_shared_ctx;
/* Init timer */
{
LARGE_INTEGER qpf;
QueryPerformanceFrequency(&qpf);
g->ns_per_qpc = 1000000000 / qpf.QuadPart;
}
{
LARGE_INTEGER qpc;
QueryPerformanceCounter(&qpc);
g->timer_start_qpc = qpc.QuadPart;
}
/* Init fibers */
g->num_fibers = 1; /* Fiber at index 0 always nil */
g->fiber_names_arena = AllocArena(Gibi(64));
@ -47,6 +62,7 @@ void StartupJobs(void)
/* Start job scheduler */
Atomic64FetchSet(&g->current_scheduler_cycle_period_ns.v, W32_DefaultSchedulerPeriodNs);
W32_Thread *scheduler_thread = W32_AllocThread(W32_JobSchedulerEntryFunc, 0, Lit("Scheduler thread"), PROF_THREAD_GROUP_SCHEDULER);
LAX scheduler_thread;
//- Start job workers
/* TODO: Heuristic worker counts & affinities */
@ -114,12 +130,12 @@ void StartupJobs(void)
}
}
P_OnExit(ShutdownJobs);
//P_OnExit(ShutdownJobs);
}
////////////////////////////////
//~ Shutdown
#if 0
void ShutdownJobs(void)
{
/* Signal shutdown */
@ -162,7 +178,7 @@ void ShutdownJobs(void)
/* Find any dangling threads that haven't exited gracefully by now */
if (!Atomic32Fetch(&g->panicking))
{
P_Lock lock = P_LockS(&g->threads_mutex);
LockTicketMutex(&g->threads_tm);
if (g->first_thread)
{
TempArena scratch = BeginScratchNoConflict();
@ -176,29 +192,13 @@ void ShutdownJobs(void)
++num_dangling_threads;
}
threads_msg = StringFormat(scratch.arena, Lit("%F dangling thread(s):\n%F"), FmtUint(num_dangling_threads), FmtString(threads_msg));
P_Panic(threads_msg);
//P_Panic(threads_msg);
EndScratch(scratch);
}
P_Unlock(&lock);
UnlockTicketMutex(&g->threads_tm);
}
}
////////////////////////////////
//~ Win32 ticket mutex
void LockTicketMutex(W32_TicketMutex *tm)
{
i64 ticket = Atomic64FetchAdd(&tm->ticket.v, 1);
while (Atomic64Fetch(&tm->serving.v) != ticket)
{
_mm_pause();
}
}
void UnlockTicketMutex(W32_TicketMutex *tm)
{
Atomic64FetchAdd(&tm->serving.v, 1);
}
#endif
////////////////////////////////
//~ Win32 thread
@ -219,7 +219,7 @@ DWORD WINAPI W32_Win32ThreadProc(LPVOID vt)
SetThreadDescription(GetCurrentThread(), t->thread_name_wstr);
}
P_LogInfoF("New thread \"%F\" created with ID %F", FmtString(StringFromCstrNoLimit(t->thread_name_cstr)), FmtUint(P_GetThreadId()));
//P_LogInfoF("New thread \"%F\" created with ID %F", FmtString(StringFromCstrNoLimit(t->thread_name_cstr)), FmtUint(ThreadId()));
/* Enter thread entry point */
t->entry_point(t->thread_data);
@ -236,12 +236,12 @@ W32_Thread *W32_AllocThread(W32_ThreadFunc *entry_point, void *thread_data, Stri
TempArena scratch = BeginScratchNoConflict();
W32_SharedCtx *g = &W32_shared_ctx;
Assert(entry_point != 0);
P_LogInfoF("Creating thread \"%F\"", FmtString(thread_name));
//P_LogInfoF("Creating thread \"%F\"", FmtString(thread_name));
/* Allocate thread object */
W32_Thread *t = 0;
{
P_Lock lock = P_LockE(&g->threads_mutex);
LockTicketMutex(&g->threads_tm);
if (g->first_free_thread)
{
t = g->first_free_thread;
@ -262,7 +262,7 @@ W32_Thread *W32_AllocThread(W32_ThreadFunc *entry_point, void *thread_data, Stri
g->first_thread = t;
}
g->last_thread = t;
P_Unlock(&lock);
UnlockTicketMutex(&g->threads_tm);
}
t->entry_point = entry_point;
@ -293,7 +293,7 @@ W32_Thread *W32_AllocThread(W32_ThreadFunc *entry_point, void *thread_data, Stri
if (!t->handle)
{
P_Panic(Lit("Failed to create thread"));
//P_Panic(Lit("Failed to create thread"));
}
EndScratch(scratch);
@ -319,7 +319,7 @@ b32 W32_TryReleaseThread(W32_Thread *thread, f32 timeout_seconds)
success = 1;
CloseHandle(handle);
{
P_Lock lock = P_LockE(&g->threads_mutex);
LockTicketMutex(&g->threads_tm);
{
W32_Thread *prev = t->prev;
W32_Thread *next = t->next;
@ -342,7 +342,7 @@ b32 W32_TryReleaseThread(W32_Thread *thread, f32 timeout_seconds)
t->next = g->first_free_thread;
g->first_free_thread = t;
}
P_Unlock(&lock);
UnlockTicketMutex(&g->threads_tm);
}
}
}
@ -710,30 +710,30 @@ W32_Fiber *W32_AllocFiber(W32_JobPool *pool)
{
if (pool != 0)
{
LockTicketMutex(&pool->free_fibers_lock);
LockTicketMutex(&pool->free_fibers_tm);
if (pool->first_free_fiber_id)
{
fiber_id = pool->first_free_fiber_id;
fiber = &g->fibers[fiber_id];
pool->first_free_fiber_id = fiber->parent_id;
}
UnlockTicketMutex(&pool->free_fibers_lock);
UnlockTicketMutex(&pool->free_fibers_tm);
}
if (!fiber_id)
{
LockTicketMutex(&g->fibers_lock);
LockTicketMutex(&g->fibers_tm);
{
{
fiber_id = g->num_fibers++;
if (fiber_id >= MaxFibers)
{
P_Panic(Lit("Max fibers reached"));
//P_Panic(Lit("Max fibers reached"));
}
fiber = &g->fibers[fiber_id];
new_name_cstr = PushStructs(g->fiber_names_arena, char, W32_FiberNameMaxSize);
}
}
UnlockTicketMutex(&g->fibers_lock);
UnlockTicketMutex(&g->fibers_tm);
}
}
@ -809,13 +809,13 @@ W32_Fiber *W32_AllocFiber(W32_JobPool *pool)
//- Release fiber
void W32_ReleaseFiber(W32_JobPool *pool, W32_Fiber *fiber)
{
LockTicketMutex(&pool->free_fibers_lock);
LockTicketMutex(&pool->free_fibers_tm);
{
i16 fiber_id = fiber->id;
fiber->parent_id = pool->first_free_fiber_id;
pool->first_free_fiber_id = fiber_id;
}
UnlockTicketMutex(&pool->free_fibers_lock);
UnlockTicketMutex(&pool->free_fibers_tm);
}
@ -855,6 +855,7 @@ void W32_YieldFiber(W32_Fiber *fiber, W32_Fiber *parent_fiber)
}
//- Fiber entry
void W32_FiberEntryPoint(void *id_ptr)
{
i16 id = (i32)(i64)id_ptr;
@ -866,12 +867,10 @@ void W32_FiberEntryPoint(void *id_ptr)
{
W32_YieldParam *yield_param = fiber->yield_param;
yield_param->kind = W32_YieldKind_None;
P_JobData data = ZI;
data.id = fiber->job_id;
data.sig = fiber->job_sig;
{
MemoryBarrier();
fiber->job_func(data);
GenericJobFunc *job_func = fiber->job_func;
job_func(fiber->job_sig, fiber->job_id);
MemoryBarrier();
}
}
@ -881,7 +880,7 @@ void W32_FiberEntryPoint(void *id_ptr)
Counter *job_counter = fiber->job_counter;
if (job_counter)
{
P_CounterAdd(job_counter, -1);
AddCounter(job_counter, -1);
}
/* Yield to worker */
fiber->yield_param->kind = W32_YieldKind_Done;
@ -959,7 +958,7 @@ W32_ThreadDef(W32_JobWorkerEntryFunc, worker_ctx_arg)
PriorityKind job_priority = 0;
i16 job_fiber_id = 0;
i32 job_id = 0;
P_JobFunc *job_func = 0;
GenericJobFunc *job_func = 0;
void *job_sig = 0;
Counter *job_counter = 0;
{
@ -1064,7 +1063,7 @@ W32_ThreadDef(W32_JobWorkerEntryFunc, worker_ctx_arg)
{
/* Invalid yield kind */
TempArena scratch = BeginScratchNoConflict();
P_Panic(StringFormat(scratch.arena, Lit("Invalid fiber yield kind \"%F\""), FmtSint(yield.kind)));
//P_Panic(StringFormat(scratch.arena, Lit("Invalid fiber yield kind \"%F\""), FmtSint(yield.kind)));
EndScratch(scratch);
} break;
@ -1133,11 +1132,11 @@ W32_ThreadDef(W32_JobWorkerEntryFunc, worker_ctx_arg)
}
else
{
LockTicketMutex(&g->wait_lists_arena_lock);
LockTicketMutex(&g->wait_lists_arena_tm);
{
wait_addr_list = PushStructNoZero(g->wait_lists_arena, W32_WaitList);
}
UnlockTicketMutex(&g->wait_lists_arena_lock);
UnlockTicketMutex(&g->wait_lists_arena_tm);
}
ZeroStruct(wait_addr_list);
wait_addr_list->value = (u64)wait_addr;
@ -1187,11 +1186,11 @@ W32_ThreadDef(W32_JobWorkerEntryFunc, worker_ctx_arg)
}
else
{
LockTicketMutex(&g->wait_lists_arena_lock);
LockTicketMutex(&g->wait_lists_arena_tm);
{
wait_time_list = PushStructNoZero(g->wait_lists_arena, W32_WaitList);
}
UnlockTicketMutex(&g->wait_lists_arena_lock);
UnlockTicketMutex(&g->wait_lists_arena_tm);
}
ZeroStruct(wait_time_list);
wait_time_list->value = wait_time;
@ -1291,7 +1290,7 @@ W32_ThreadDef(W32_JobSchedulerEntryFunc, UNUSED arg)
HANDLE timer = CreateWaitableTimerExW(0, 0, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS);
if (!timer)
{
P_Panic(Lit("Failed to create high resolution timer"));
//P_Panic(Lit("Failed to create high resolution timer"));
}
/* Create rolling buffer of scheduler cycles initialized to default value */
@ -1319,7 +1318,7 @@ W32_ThreadDef(W32_JobSchedulerEntryFunc, UNUSED arg)
}
/* Calculate mean period */
i64 now_ns = P_TimeNs();
i64 now_ns = TimeNs();
i64 period_ns = last_cycle_ns == 0 ? W32_DefaultSchedulerPeriodNs : now_ns - last_cycle_ns;
last_cycle_ns = now_ns;
@ -1348,9 +1347,9 @@ W32_ThreadDef(W32_JobSchedulerEntryFunc, UNUSED arg)
}
////////////////////////////////
//~ Wait / wake
//~ @hookdef Futex
void P_Wait(volatile void *addr, void *cmp, u32 size, i64 timeout_ns)
void FutexWait(volatile void *addr, void *cmp, u32 size, i64 timeout_ns)
{
W32_Fiber *fiber = W32_FiberFromId(FiberId());
i16 parent_id = fiber->parent_id;
@ -1390,31 +1389,46 @@ void P_Wait(volatile void *addr, void *cmp, u32 size, i64 timeout_ns)
}
}
void P_Wake(void *addr, i32 count)
void FutexWake(void *addr, i32 count)
{
W32_WakeByAddress(addr, count);
}
////////////////////////////////
//~ Fiber
//~ @hoodef Job
i16 FiberId(void)
GenericJobDesc *PushJobDesc_(u64 sig_size, u64 sig_align, GenericJobFunc *func, JobDescParams params)
{
return (i16)(i64)GetFiberData();
GenericJobDesc *result = 0;
/* FIXME: Pool arenas */
Arena *arena = AllocArena(Mebi(1));
result = PushStruct(arena, GenericJobDesc);
result->arena = arena;
result->sig = PushBytes(arena, sig_size, sig_align);
result->func = func;
result->count = params.count;
result->pool = params.pool;
result->priority = params.priority;
result->counter = params.counter;
return result;
}
////////////////////////////////
//~ Job
void P_Run(i32 count, P_JobFunc *func, void *sig, PoolKind pool_kind, PriorityKind priority, Counter *counter)
#if 1
void RunJobEx(GenericJobDesc *desc)
{
__prof;
struct W32_SharedCtx *g = &W32_shared_ctx;
i32 count = desc->count;
Counter *counter = desc->counter;
PoolKind pool_kind = desc->pool;
PriorityKind priority = desc->priority;
GenericJobFunc *func = desc->func;
void *sig = desc->sig;
if (count > 0)
{
if (counter)
{
P_CounterAdd(counter, count);
AddCounter(counter, count);
}
W32_Fiber *fiber = W32_FiberFromId(FiberId());
priority = ClampI32(priority, fiber->job_priority, PriorityKind_Count - 1); /* A job cannot create a job with a higher priority than itself */
@ -1474,3 +1488,101 @@ void P_Run(i32 count, P_JobFunc *func, void *sig, PoolKind pool_kind, PriorityKi
}
}
}
#else
void RunJob(i32 count, GenericJobFunc *func, void *sig, PoolKind pool_kind, PriorityKind priority, Counter *counter)
{
__prof;
struct W32_SharedCtx *g = &W32_shared_ctx;
if (count > 0)
{
if (counter)
{
AddCounter(counter, count);
}
W32_Fiber *fiber = W32_FiberFromId(FiberId());
priority = ClampI32(priority, fiber->job_priority, PriorityKind_Count - 1); /* A job cannot create a job with a higher priority than itself */
if (pool_kind == PoolKind_Inherit)
{
pool_kind = fiber->job_pool;
}
W32_JobPool *pool = &g->job_pools[pool_kind];
W32_JobQueue *queue = &pool->job_queues[priority];
LockTicketMutex(&queue->lock);
{
W32_JobInfo *info = 0;
if (queue->first_free)
{
info = queue->first_free;
queue->first_free = info->next;
}
else
{
info = PushStructNoZero(queue->arena, W32_JobInfo);
}
ZeroStruct(info);
info->count = count;
info->func = func;
info->sig = sig;
info->counter = counter;
if (queue->last)
{
queue->last->next = info;
}
else
{
queue->first = info;
}
queue->last = info;
}
UnlockTicketMutex(&queue->lock);
/* Wake workers */
{
LockTicketMutex(&pool->workers_wake_tm);
{
Atomic64FetchAdd(&pool->num_jobs_in_queue.v, count);
if (count >= W32_WakeAllThreshold)
{
WakeByAddressAll(&pool->num_jobs_in_queue);
}
else
{
for (i32 i = 0; i < count; ++i)
{
WakeByAddressSingle(&pool->num_jobs_in_queue);
}
}
}
UnlockTicketMutex(&pool->workers_wake_tm);
}
}
}
#endif
////////////////////////////////
//~ @hookdef Helpers
i64 TimeNs(void)
{
struct W32_SharedCtx *g = &W32_shared_ctx;
LARGE_INTEGER qpc;
QueryPerformanceCounter(&qpc);
i64 result = (qpc.QuadPart - g->timer_start_qpc) * g->ns_per_qpc;
return result;
}
u32 GetLogicalProcessorCount(void)
{
return GetActiveProcessorCount(ALL_PROCESSOR_GROUPS);
}
u32 ThreadId(void)
{
return GetCurrentThreadId();
}
i64 GetCurrentSchedulerPeriodNs(void)
{
W32_SharedCtx *g = &W32_shared_ctx;
return Atomic64Fetch(&g->current_scheduler_cycle_period_ns.v);
}

View File

@ -5,7 +5,6 @@
# define UNICODE
# define WIN32_LEAN_AND_MEAN
# include <Windows.h>
#if 0
# include <WinSock2.h>
# include <TlHelp32.h>
# include <WS2tcpip.h>
@ -16,7 +15,6 @@
# include <bcrypt.h>
# include <avrt.h>
# include <shellapi.h>
#endif
#pragma warning(pop)
////////////////////////////////
@ -123,7 +121,7 @@ AlignedStruct(W32_Fiber, 64)
/* ---------------------------------------------------- */
/* -------------------- Cache line -------------------- */
/* ---------------------------------------------------- */
void *job_func; /* 08 bytes */
GenericJobFunc *job_func; /* 08 bytes */
/* ---------------------------------------------------- */
void *job_sig; /* 08 bytes */
/* ---------------------------------------------------- */
@ -158,7 +156,7 @@ Struct(W32_JobInfo)
i32 num_dispatched;
i32 count;
void *func;
GenericJobFunc *func;
void *sig;
struct Counter *counter;
@ -217,6 +215,8 @@ AlignedStruct(W32_JobPool, 64)
Struct(W32_SharedCtx)
{
i64 timer_start_qpc;
i64 ns_per_qpc;
Atomic32 shutdown;
//- Worker thread pool

View File

@ -1,7 +1,7 @@
////////////////////////////////
//~ Load job
JobDef(F_LoadAssetJob, job)
JobDef(F_LoadJob, sig, _)
{
__prof;
TempArena scratch = BeginScratchNoConflict();
@ -25,13 +25,12 @@ JobDef(F_LoadAssetJob, job)
0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
};
F_LoadJobSig *params = job.sig;
String path = STRING(params->path_len, (u8 *)params->path_cstr);
f32 point_size = params->point_size;
AC_Asset *asset = params->asset;
String path = sig->path;
f32 point_size = sig->point_size;
AC_Asset *asset = sig->asset;
P_LogInfoF("Loading font \"%F\" (point size %F)", FmtString(path), FmtFloat((f64)point_size));
i64 start_ns = P_TimeNs();
i64 start_ns = TimeNs();
Assert(StringEndsWith(path, Lit(".ttf")));
Assert(countof(font_codes) < F_LookupTableSize);
@ -87,7 +86,7 @@ JobDef(F_LoadAssetJob, job)
font->lookup[codepoint] = result.cache_indices[i];
}
P_LogSuccessF("Loaded font \"%F\" (point size %F) in %F seconds", FmtString(path), FmtFloat((f64)point_size), FmtFloat(SecondsFromNs(P_TimeNs() - start_ns)));
P_LogSuccessF("Loaded font \"%F\" (point size %F) in %F seconds", FmtString(path), FmtFloat((f64)point_size), FmtFloat(SecondsFromNs(TimeNs() - start_ns)));
AC_MarkReady(asset, font);
EndScratch(scratch);
@ -113,22 +112,12 @@ AC_Asset *F_LoadAsset(String path, f32 point_size, b32 wait)
if (is_first_touch)
{
/* Assemble task params */
F_LoadJobSig *params = F_AllocJobSig();
if (path.len > (sizeof(params->path_cstr) - 1))
{
P_Panic(StringFormat(scratch.arena,
Lit("Font path \"%F\" too long!"),
FmtString(path)));
}
CstrBuffFromStringToBuff(StringFromArray(params->path_cstr), path);
params->path_len = path.len;
params->asset = asset;
params->point_size = point_size;
/* PushStruct task */
AC_MarkLoading(asset);
P_Run(1, F_LoadAssetJob, params, PoolKind_Background, PriorityKind_Low, 0);
F_LoadJob_Desc *desc = PushJobDesc(F_LoadJob, .pool = PoolKind_Background, .priority = PriorityKind_Low);
desc->sig->asset = asset;
desc->sig->path = PushString(desc->arena, path);
desc->sig->point_size = point_size;
RunJobEx((GenericJobDesc *)desc);
if (wait)
{
AC_WaitOnAssetReady(asset);

View File

@ -27,7 +27,7 @@ Struct(F_Font)
////////////////////////////////
//~ Font load job
JobDecl(F_LoadAssetJob, { AC_Asset *asset; f32 point_size; String path; });
JobDecl(F_LoadJob, { AC_Asset *asset; f32 point_size; String path; });
////////////////////////////////
//~ Font load operations

View File

@ -71,7 +71,7 @@ void GPU_Startup(void)
P_OnExit(GPU_D12_Shutdown);
/* Start evictor job */
P_Run(1, GPU_D12_EvictorJob, 0, PoolKind_Background, PriorityKind_Low, &g->evictor_job_counter);
RunJob(1, GPU_D12_EvictorJob, PoolKind_Background, PriorityKind_Low, &g->evictor_job_counter, 0);
}
P_ExitFuncDef(GPU_D12_Shutdown)
@ -92,12 +92,12 @@ P_ExitFuncDef(GPU_D12_Shutdown)
#endif
{
P_Lock lock = P_LockE(&g->evictor_wake_mutex);
Lock lock = LockE(&g->evictor_wake_mutex);
g->evictor_shutdown = 1;
P_SignalCv(&g->evictor_wake_cv, I32Max);
P_Unlock(&lock);
SignalCv(&g->evictor_wake_cv, I32Max);
Unlock(&lock);
}
P_WaitOnCounter(&g->evictor_job_counter);
WaitOnCounter(&g->evictor_job_counter);
}
/* ========================== *
@ -322,13 +322,10 @@ void GPU_D12_InitObjects(void)
{.type = D3D12_COMMAND_LIST_TYPE_COPY, .priority = D3D12_COMMAND_QUEUE_PRIORITY_HIGH, .dbg_name = Lit("Copy queue") },
{.type = D3D12_COMMAND_LIST_TYPE_COPY, .priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, .dbg_name = Lit("Background copy queue") }
};
GPU_D12_AllocCommandQueueJobSig sig = ZI;
sig.descs_in = params;
sig.cqs_out = g->command_queues;
{
Counter counter = ZI;
P_Run(DX12_NUM_QUEUES, GPU_D12_AllocCommandQueueJob, &sig, PoolKind_Inherit, PriorityKind_Inherit, &counter);
P_WaitOnCounter(&counter);
RunJob(DX12_NUM_QUEUES, GPU_D12_AllocCommandQueueJob, PoolKind_Inherit, PriorityKind_Low, &counter, .descs_in = params, .cqs_out = g->command_queues);
WaitOnCounter(&counter);
}
#if ProfilingIsEnabled
{
@ -418,12 +415,9 @@ void GPU_InitPipelines(void)
GPU_D12_Pipeline **pipelines = PushStructs(scratch.arena, GPU_D12_Pipeline *, num_pipelines);
{
__profn("Allocate pipelines");
GPU_D12_AllocPipelineJobSig sig = ZI;
sig.descs_in = descs;
sig.pipelines_out = pipelines;
Counter counter = ZI;
P_Run(num_pipelines, GPU_D12_AllocPipelineJob, &sig, PoolKind_Inherit, PriorityKind_Inherit, &counter);
P_WaitOnCounter(&counter);
RunJob(num_pipelines, GPU_D12_AllocPipelineJob, PoolKind_Inherit, PriorityKind_Inherit, &counter, .descs_in = descs, .pipelines_out = pipelines);
WaitOnCounter(&counter);
}
for (u32 i = 0; i < num_pipelines; ++i)
{
@ -502,11 +496,8 @@ void GPU_D12_InitNoise(void)
/* Upload texture */
{
Counter counter = ZI;
GPU_D12_UploadJobSig sig = ZI;
sig.resource = r;
sig.data = data.text;
P_Run(1, GPU_D12_UploadJob, &sig, PoolKind_Inherit, PriorityKind_Inherit, &counter);
P_WaitOnCounter(&counter);
RunJob(1, GPU_D12_UploadJob, PoolKind_Inherit, PriorityKind_Low, &counter, .resource = r, .data = data.text);
WaitOnCounter(&counter);
}
}
}
@ -526,17 +517,16 @@ void GPU_D12_InitNoise(void)
#if RESOURCE_RELOADING
JobDef(GPU_D12_CompileShaderJob, job)
JobDef(GPU_D12_CompileShaderJob, sig, id)
{
__prof;
GPU_D12_CompileShaderJobSig *sig = job.sig;
Arena *arena = sig->arena;
GPU_D12_ShaderDesc *desc = &sig->descs[job.id];
GPU_D12_CompiledShaderResult *result = &sig->results[job.id];
GPU_D12_ShaderDesc *desc = &sig->descs[id];
GPU_D12_CompiledShaderResult *result = &sig->results[id];
TempArena scratch = BeginScratch(arena);
{
i64 start_ns = P_TimeNs();
i64 start_ns = TimeNs();
DXC_Result dxc_result = ZI;
{
__profn("Compile shader");
@ -565,7 +555,7 @@ JobDef(GPU_D12_CompileShaderJob, job)
result->success = dxc_result.success;
result->dxc = dxc_result.dxc;
result->errors = dxc_result.errors;
result->elapsed_ns = P_TimeNs() - start_ns;
result->elapsed_ns = TimeNs() - start_ns;
}
EndScratch(scratch);
@ -577,17 +567,16 @@ JobDef(GPU_D12_CompileShaderJob, job)
* Pipeline
* ========================== */
JobDef(GPU_D12_AllocPipelineJob, job)
JobDef(GPU_D12_AllocPipelineJob, sig, id)
{
__prof;
GPU_D12_SharedState *g = &GPU_D12_shared_state;
GPU_D12_AllocPipelineJobSig *sig = job.sig;
GPU_D12_PipelineDesc *desc = &sig->descs_in[job.id];
GPU_D12_PipelineDesc *desc = &sig->descs_in[id];
GPU_D12_Pipeline **pipelines_out = sig->pipelines_out;
GPU_D12_Pipeline *pipeline = 0;
{
P_Lock lock = P_LockE(&g->pipelines_mutex);
Lock lock = LockE(&g->pipelines_mutex);
if (g->first_free_pipeline)
{
pipeline = g->first_free_pipeline;
@ -597,17 +586,17 @@ JobDef(GPU_D12_AllocPipelineJob, job)
{
pipeline = PushStructNoZero(g->pipelines_arena, GPU_D12_Pipeline);
}
P_Unlock(&lock);
Unlock(&lock);
}
ZeroStruct(pipeline);
pipelines_out[job.id] = pipeline;
pipelines_out[id] = pipeline;
pipeline->desc = *desc;
pipeline->name = desc->name;
pipeline->hash = HashFnv64(Fnv64Basis, pipeline->name);
TempArena scratch = BeginScratchNoConflict();
{
i64 start_ns = P_TimeNs();
i64 start_ns = TimeNs();
String pipeline_name = pipeline->name;
P_LogInfoF("Loading pipeline \"%F\"", FmtString(pipeline_name));
b32 success = 1;
@ -880,7 +869,7 @@ JobDef(GPU_D12_AllocPipelineJob, job)
pipeline->pso = pso;
pipeline->rootsig = rootsig;
pipeline->compilation_time_ns = P_TimeNs() - start_ns;
pipeline->compilation_time_ns = TimeNs() - start_ns;
pipeline->success = success;
pipeline->is_gfx = cs_dxc.len == 0;
pipeline->error = error_str;
@ -913,12 +902,12 @@ void GPU_D12_ReleasePipelineNow(GPU_D12_Pipeline *pipeline)
{
ID3D12PipelineState_Release(pipeline->pso);
}
P_Lock lock = P_LockE(&g->pipelines_mutex);
Lock lock = LockE(&g->pipelines_mutex);
{
pipeline->next = g->first_free_pipeline;
g->first_free_pipeline = pipeline;
}
P_Unlock(&lock);
Unlock(&lock);
}
/* ========================== *
@ -931,13 +920,13 @@ GPU_D12_PipelineScope *GPU_D12_BeginPipelineScope(void)
GPU_D12_SharedState *g = &GPU_D12_shared_state;
GPU_D12_PipelineScope *scope = 0;
{
P_Lock lock = P_LockE(&g->pipelines_mutex);
Lock lock = LockE(&g->pipelines_mutex);
if (g->first_free_pipeline_scope)
{
scope = g->first_free_pipeline_scope;
g->first_free_pipeline_scope = scope->next_free;
}
P_Unlock(&lock);
Unlock(&lock);
}
Arena *arena = 0;
if (scope)
@ -959,7 +948,7 @@ void GPU_D12_EndPipelineScope(GPU_D12_PipelineScope *scope)
{
__prof;
GPU_D12_SharedState *g = &GPU_D12_shared_state;
P_Lock lock = P_LockE(&g->pipelines_mutex);
Lock lock = LockE(&g->pipelines_mutex);
{
for (DictEntry *entry = scope->refs->first; entry; entry = entry->next)
{
@ -972,7 +961,7 @@ void GPU_D12_EndPipelineScope(GPU_D12_PipelineScope *scope)
scope->next_free = g->first_free_pipeline_scope;
g->first_free_pipeline_scope = scope;
}
P_Unlock(&lock);
Unlock(&lock);
}
Readonly GPU_D12_Pipeline GPU_D12_nil_pipeline = ZI;
@ -991,13 +980,13 @@ GPU_D12_Pipeline *GPU_D12_PipelineFromName(GPU_D12_PipelineScope *scope, String
else
{
{
P_Lock lock = P_LockE(&g->pipelines_mutex);
Lock lock = LockE(&g->pipelines_mutex);
tmp = (GPU_D12_Pipeline *)DictValueFromHash(g->top_successful_pipelines, hash);
if (tmp)
{
++tmp->refcount;
}
P_Unlock(&lock);
Unlock(&lock);
}
if (tmp)
{
@ -1013,7 +1002,7 @@ void GPU_D12_RegisterPipeline(u64 num_pipelines, GPU_D12_Pipeline **pipelines)
{
__prof;
GPU_D12_SharedState *g = &GPU_D12_shared_state;
P_Lock lock = P_LockE(&g->pipelines_mutex);
Lock lock = LockE(&g->pipelines_mutex);
{
for (u64 i = 0; i < num_pipelines; ++i)
{
@ -1042,7 +1031,7 @@ void GPU_D12_RegisterPipeline(u64 num_pipelines, GPU_D12_Pipeline **pipelines)
}
}
}
P_Unlock(&lock);
Unlock(&lock);
}
#if RESOURCE_RELOADING
@ -1085,40 +1074,42 @@ W_CallbackFuncDef(GPU_D12_WatchPipelineCallback, name)
pipeline_name = split.count > 1 ? split.strings[split.count - 2] : pipeline_name;
}
{
GPU_D12_CompileShaderJobSig sig = ZI;
sig.arena = scratch.arena;
GPU_D12_CompileShaderJob_Desc *job_desc = PushJobDesc(GPU_D12_CompileShaderJob, .count = 0);
job_desc->sig->arena = scratch.arena;
if (is_rs)
{
num_shaders = 2;
shader_descs = PushStructs(scratch.arena, GPU_D12_ShaderDesc, num_shaders);
shader_results = PushStructs(scratch.arena, GPU_D12_CompiledShaderResult, num_shaders);
sig.descs = shader_descs;
sig.results = shader_results;
sig.descs[0].src = data;
sig.descs[0].friendly_name = friendly_name;
sig.descs[0].entry = Lit("vs");
sig.descs[0].target = Lit("vs_6_6");
sig.descs[1].src = data;
sig.descs[1].friendly_name = friendly_name;
sig.descs[1].entry = Lit("ps");
sig.descs[1].target = Lit("ps_6_6");
job_desc->sig->descs = shader_descs;
job_desc->sig->results = shader_results;
job_desc->sig->descs[0].src = data;
job_desc->sig->descs[0].friendly_name = friendly_name;
job_desc->sig->descs[0].entry = Lit("vs");
job_desc->sig->descs[0].target = Lit("vs_6_6");
job_desc->sig->descs[1].src = data;
job_desc->sig->descs[1].friendly_name = friendly_name;
job_desc->sig->descs[1].entry = Lit("ps");
job_desc->sig->descs[1].target = Lit("ps_6_6");
}
else if (is_cs)
{
num_shaders = 1;
shader_descs = PushStructs(scratch.arena, GPU_D12_ShaderDesc, num_shaders);
shader_results = PushStructs(scratch.arena, GPU_D12_CompiledShaderResult, num_shaders);
sig.descs = shader_descs;
sig.results = shader_results;
sig.descs[0].src = data;
sig.descs[0].friendly_name = friendly_name;
sig.descs[0].entry = Lit("cs");
sig.descs[0].target = Lit("cs_6_6");
job_desc->sig->descs = shader_descs;
job_desc->sig->results = shader_results;
job_desc->sig->descs[0].src = data;
job_desc->sig->descs[0].friendly_name = friendly_name;
job_desc->sig->descs[0].entry = Lit("cs");
job_desc->sig->descs[0].target = Lit("cs_6_6");
}
{
Counter counter = ZI;
P_Run(num_shaders, GPU_D12_CompileShaderJob, &sig, PoolKind_Inherit, PriorityKind_Inherit, &counter);
P_WaitOnCounter(&counter);
job_desc->count = num_shaders;
job_desc->counter = &counter;
RunJobEx((GenericJobDesc *)job_desc);
WaitOnCounter(&counter);
}
}
P_CloseFIle(file);
@ -1177,15 +1168,12 @@ W_CallbackFuncDef(GPU_D12_WatchPipelineCallback, name)
__profn("Compile dirty pipelines");
GPU_D12_Pipeline **pipelines = PushStructs(scratch.arena, GPU_D12_Pipeline *, num_pipelines);
{
GPU_D12_AllocPipelineJobSig sig = ZI;
sig.descs_in = pipeline_descs;
sig.pipelines_out = pipelines;
Counter counter = ZI;
P_Run(num_pipelines, GPU_D12_AllocPipelineJob, &sig, PoolKind_Inherit, PriorityKind_Inherit, &counter);
P_WaitOnCounter(&counter);
RunJob(num_pipelines, GPU_D12_AllocPipelineJob, PoolKind_Inherit, PriorityKind_Low, &counter, .descs_in = pipeline_descs, .pipelines_out = pipelines);
WaitOnCounter(&counter);
}
{
P_Lock lock = P_LockS(&g->pipelines_mutex);
Lock lock = LockS(&g->pipelines_mutex);
for (u32 i = 0; i < num_pipelines; ++i)
{
GPU_D12_Pipeline *pipeline = pipelines[i];
@ -1216,7 +1204,7 @@ W_CallbackFuncDef(GPU_D12_WatchPipelineCallback, name)
}
}
P_Unlock(&lock);
Unlock(&lock);
}
GPU_D12_RegisterPipeline(num_pipelines, pipelines);
}
@ -1237,7 +1225,7 @@ GPU_D12_Descriptor *GPU_D12_AllocDescriptor(GPU_D12_CpuDescriptorHeap *dh)
u32 index = 0;
D3D12_CPU_DESCRIPTOR_HANDLE handle = ZI;
{
P_Lock lock = P_LockE(&dh->mutex);
Lock lock = LockE(&dh->mutex);
if (dh->first_free_descriptor)
{
d = dh->first_free_descriptor;
@ -1255,7 +1243,7 @@ GPU_D12_Descriptor *GPU_D12_AllocDescriptor(GPU_D12_CpuDescriptorHeap *dh)
index = dh->num_descriptors_reserved++;
handle.ptr = dh->handle.ptr + (index * dh->descriptor_size);
}
P_Unlock(&lock);
Unlock(&lock);
}
ZeroStruct(d);
d->heap = dh;
@ -1267,12 +1255,12 @@ GPU_D12_Descriptor *GPU_D12_AllocDescriptor(GPU_D12_CpuDescriptorHeap *dh)
void GPU_D12_ReleaseDescriptor(GPU_D12_Descriptor *descriptor)
{
GPU_D12_CpuDescriptorHeap *dh = descriptor->heap;
P_Lock lock = P_LockE(&dh->mutex);
Lock lock = LockE(&dh->mutex);
{
descriptor->next_free = dh->first_free_descriptor;
dh->first_free_descriptor = descriptor;
}
P_Unlock(&lock);
Unlock(&lock);
}
/* ========================== *
@ -1342,31 +1330,31 @@ void GPU_D12_ReleaseDataFenced(void *data, GPU_D12_FencedReleaseKind kind)
for (u32 i = 0; i < countof(g->command_queues); ++i)
{
GPU_D12_CommandQueue *cq = g->command_queues[i];
P_Lock lock = P_LockS(&cq->submit_fence_mutex);
Lock lock = LockS(&cq->submit_fence_mutex);
{
fr_targets[i] = cq->submit_fence_target;
}
P_Unlock(&lock);
Unlock(&lock);
}
/* PushStruct data to release queue */
/* Push data to release queue */
{
P_Lock lock = P_LockE(&g->fenced_releases_mutex);
Lock lock = LockE(&g->fenced_releases_mutex);
{
*PushStruct(g->fenced_releases_arena, GPU_D12_FencedReleaseData) = fr;
CopyBytes(g->fenced_release_targets, fr_targets, sizeof(fr_targets));
}
P_Unlock(&lock);
Unlock(&lock);
}
/* Wake evictor */
{
P_Lock lock = P_LockE(&g->evictor_wake_mutex);
Lock lock = LockE(&g->evictor_wake_mutex);
{
++g->evictor_wake_gen;
P_SignalCv(&g->evictor_wake_cv, I32Max);
SignalCv(&g->evictor_wake_cv, I32Max);
}
P_Unlock(&lock);
Unlock(&lock);
}
}
@ -1380,7 +1368,7 @@ GPU_D12_Resource *GPU_D12_AllocResource(D3D12_HEAP_PROPERTIES heap_props, D3D12_
GPU_D12_SharedState *g = &GPU_D12_shared_state;
GPU_D12_Resource *r = 0;
{
P_Lock lock = P_LockE(&g->resources_mutex);
Lock lock = LockE(&g->resources_mutex);
if (g->first_free_resource)
{
r = g->first_free_resource;
@ -1390,7 +1378,7 @@ GPU_D12_Resource *GPU_D12_AllocResource(D3D12_HEAP_PROPERTIES heap_props, D3D12_
{
r = PushStructNoZero(g->resources_arena, GPU_D12_Resource);
}
P_Unlock(&lock);
Unlock(&lock);
}
ZeroStruct(r);
@ -1441,10 +1429,10 @@ void GPU_D12_ReleaseResourceNow(GPU_D12_Resource *t)
ID3D12Resource_Release(t->resource);
/* Add to free list */
P_Lock lock = P_LockE(&g->resources_mutex);
Lock lock = LockE(&g->resources_mutex);
t->next_free = g->first_free_resource;
g->first_free_resource = t;
P_Unlock(&lock);
Unlock(&lock);
}
void GPU_ReleaseResourceFenced(GPU_Resource *resource)
@ -1515,12 +1503,11 @@ void GPU_D12_InsertBarrier(ID3D12GraphicsCommandList *cl, i32 num_descs, GPU_D12
GPU_D12_CommandListPool *GPU_D12_AllocCommandListPool(GPU_D12_CommandQueue *cq);
JobDef(GPU_D12_AllocCommandQueueJob, job)
JobDef(GPU_D12_AllocCommandQueueJob, sig, id)
{
__prof;
GPU_D12_SharedState *g = &GPU_D12_shared_state;
GPU_D12_AllocCommandQueueJobSig *sig = job.sig;
GPU_D12_CommandQueueDesc *desc = &sig->descs_in[job.id];
GPU_D12_CommandQueueDesc *desc = &sig->descs_in[id];
{
GPU_D12_CommandQueue *cq = 0;
{
@ -1548,7 +1535,7 @@ JobDef(GPU_D12_AllocCommandQueueJob, job)
cq->cl_pool = GPU_D12_AllocCommandListPool(cq);
sig->cqs_out[job.id] = cq;
sig->cqs_out[id] = cq;
}
}
@ -1587,7 +1574,7 @@ GPU_D12_CommandList *GPU_D12_BeginCommandList(GPU_D12_CommandListPool *pool)
struct ID3D12GraphicsCommandList *old_cl = 0;
struct ID3D12CommandAllocator *old_ca = 0;
{
P_Lock lock = P_LockE(&pool->mutex);
Lock lock = LockE(&pool->mutex);
/* Find first command list ready for reuse */
for (GPU_D12_CommandList *tmp = pool->first_submitted_command_list; tmp; tmp = tmp->next_submitted)
{
@ -1625,12 +1612,12 @@ GPU_D12_CommandList *GPU_D12_BeginCommandList(GPU_D12_CommandListPool *pool)
{
cl = PushStructNoZero(pool->arena, GPU_D12_CommandList);
}
P_Unlock(&lock);
Unlock(&lock);
}
ZeroStruct(cl);
cl->cq = cq;
cl->pool = pool;
cl->global_record_lock = P_LockS(&g->global_command_list_record_mutex);
cl->global_record_lock = LockS(&g->global_command_list_record_mutex);
HRESULT hr = 0;
if (old_cl)
@ -1698,20 +1685,20 @@ u64 GPU_D12_EndCommandList(GPU_D12_CommandList *cl)
u64 submit_fence_target = 0;
{
__profn("Execute");
P_Lock submit_lock = P_LockS(&g->global_submit_mutex);
P_Lock fence_lock = P_LockE(&cq->submit_fence_mutex);
Lock submit_lock = LockS(&g->global_submit_mutex);
Lock fence_lock = LockE(&cq->submit_fence_mutex);
{
submit_fence_target = ++cq->submit_fence_target;
ID3D12CommandQueue_ExecuteCommandLists(cq->cq, 1, (ID3D12CommandList **)&cl->cl);
ID3D12CommandQueue_Signal(cq->cq, cq->submit_fence, submit_fence_target);
}
P_Unlock(&fence_lock);
P_Unlock(&submit_lock);
Unlock(&fence_lock);
Unlock(&submit_lock);
}
/* Add descriptor heaps to submitted list */
{
P_Lock lock = P_LockE(&g->command_descriptor_heaps_mutex);
Lock lock = LockE(&g->command_descriptor_heaps_mutex);
for (GPU_D12_CommandDescriptorHeap *cdh = cl->first_command_descriptor_heap; cdh; cdh = cdh->next_in_command_list)
{
cdh->submitted_cq = cq;
@ -1726,12 +1713,12 @@ u64 GPU_D12_EndCommandList(GPU_D12_CommandList *cl)
}
g->last_submitted_command_descriptor_heap = cdh;
}
P_Unlock(&lock);
Unlock(&lock);
}
/* Add command buffers to submitted list */
{
P_Lock lock = P_LockE(&g->command_buffers_mutex);
Lock lock = LockE(&g->command_buffers_mutex);
for (GPU_D12_CommandBuffer *cb = cl->first_command_buffer; cb; cb = cb->next_in_command_list)
{
GPU_D12_CommandBufferGroup *group = cb->group;
@ -1747,14 +1734,14 @@ u64 GPU_D12_EndCommandList(GPU_D12_CommandList *cl)
}
group->last_submitted = cb;
}
P_Unlock(&lock);
Unlock(&lock);
}
/* Add command list to pool submitted list */
P_Unlock(&cl->global_record_lock);
Unlock(&cl->global_record_lock);
cl->submitted_fence_target = submit_fence_target;
{
P_Lock lock = P_LockE(&pool->mutex);
Lock lock = LockE(&pool->mutex);
if (pool->last_submitted_command_list)
{
pool->last_submitted_command_list->next_submitted = cl;
@ -1764,7 +1751,7 @@ u64 GPU_D12_EndCommandList(GPU_D12_CommandList *cl)
pool->first_submitted_command_list = cl;
}
pool->last_submitted_command_list = cl;
P_Unlock(&lock);
Unlock(&lock);
}
return submit_fence_target;
@ -1786,7 +1773,7 @@ GPU_D12_CommandDescriptorHeap *GPU_D12_PushDescriptorHeap(GPU_D12_CommandList *c
D3D12_CPU_DESCRIPTOR_HANDLE old_start_cpu_handle = ZI;
D3D12_GPU_DESCRIPTOR_HANDLE old_start_gpu_handle = ZI;
{
P_Lock lock = P_LockE(&g->command_descriptor_heaps_mutex);
Lock lock = LockE(&g->command_descriptor_heaps_mutex);
/* Find first heap ready for reuse */
for (GPU_D12_CommandDescriptorHeap *tmp = g->first_submitted_command_descriptor_heap; tmp; tmp = tmp->next_submitted)
{
@ -1828,7 +1815,7 @@ GPU_D12_CommandDescriptorHeap *GPU_D12_PushDescriptorHeap(GPU_D12_CommandList *c
/* No available heap available for reuse, allocate new */
cdh = PushStructNoZero(g->command_descriptor_heaps_arena, GPU_D12_CommandDescriptorHeap);
}
P_Unlock(&lock);
Unlock(&lock);
}
ZeroStruct(cdh);
@ -1855,9 +1842,9 @@ GPU_D12_CommandDescriptorHeap *GPU_D12_PushDescriptorHeap(GPU_D12_CommandList *c
/* Copy CPU heap */
{
P_Lock lock = P_LockS(&dh_cpu->mutex);
Lock lock = LockS(&dh_cpu->mutex);
ID3D12Device_CopyDescriptorsSimple(g->device, dh_cpu->num_descriptors_reserved, cdh->start_cpu_handle, dh_cpu->handle, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
P_Unlock(&lock);
Unlock(&lock);
}
/* Insert into command list */
@ -1894,7 +1881,7 @@ GPU_D12_CommandBuffer *GPU_D12__PushCommandBuffer(GPU_D12_CommandList *cl, u64 d
GPU_D12_CommandBuffer *cb = 0;
GPU_D12_Resource *r = 0;
{
P_Lock lock = P_LockE(&g->command_buffers_mutex);
Lock lock = LockE(&g->command_buffers_mutex);
{
u64 group_hash = GPU_D12_CommandBufferHashFromSize(size);
@ -1946,7 +1933,7 @@ GPU_D12_CommandBuffer *GPU_D12__PushCommandBuffer(GPU_D12_CommandList *cl, u64 d
/* Allocate new */
cb = PushStructNoZero(g->command_buffers_arena, GPU_D12_CommandBuffer);
}
P_Unlock(&lock);
Unlock(&lock);
}
ZeroStruct(cb);
cb->group = cb_group;
@ -2017,10 +2004,9 @@ GPU_D12_CommandBuffer *GPU_D12__PushCommandBuffer(GPU_D12_CommandList *cl, u64 d
* Wait job
* ========================== */
JobDef(GPU_D12_WaitOnFenceJob, job)
JobDef(GPU_D12_WaitOnFenceJob, sig, UNUSED id)
{
__prof;
GPU_D12_WaitOnFenceJobSig *sig = job.sig;
ID3D12Fence *fence = sig->fence;
u64 target = sig->target;
if (ID3D12Fence_GetCompletedValue(fence) < target)
@ -2100,11 +2086,8 @@ GPU_Resource *GPU_AllocTexture(GPU_TextureFormat format, u32 flags, Vec2I32 size
{
/* TODO: Make wait optional */
Counter counter = ZI;
GPU_D12_UploadJobSig sig = ZI;
sig.resource = r;
sig.data = initial_data;
P_Run(1, GPU_D12_UploadJob, &sig, PoolKind_Inherit, PriorityKind_Inherit, &counter);
P_WaitOnCounter(&counter);
RunJob(1, GPU_D12_UploadJob, PoolKind_Inherit, PriorityKind_Inherit, &counter, .resource = r, .data = initial_data);
WaitOnCounter(&counter);
}
return (GPU_Resource *)r;
@ -2120,10 +2103,9 @@ Vec2I32 GPU_GetTextureSize(GPU_Resource *resource)
* Upload
* ========================== */
JobDef(GPU_D12_UploadJob, job)
JobDef(GPU_D12_UploadJob, sig, UNUSED id)
{
GPU_D12_SharedState *g = &GPU_D12_shared_state;
GPU_D12_UploadJobSig *sig = job.sig;
GPU_D12_Resource *r = sig->resource;
void *data = sig->data;
@ -2216,12 +2198,9 @@ JobDef(GPU_D12_UploadJob, job)
/* Wait on fence so we know it's safe to release upload heap */
if (ID3D12Fence_GetCompletedValue(cq->submit_fence) < fence_target)
{
GPU_D12_WaitOnFenceJobSig wait_sig = ZI;
wait_sig.fence = cq->submit_fence;
wait_sig.target = fence_target;
Counter counter = ZI;
P_Run(1, GPU_D12_WaitOnFenceJob, &wait_sig, PoolKind_Floating, PriorityKind_Low, &counter);
P_WaitOnCounter(&counter);
RunJob(1, GPU_D12_WaitOnFenceJob, PoolKind_Floating, PriorityKind_Inherit, &counter, .fence = cq->submit_fence, .target = fence_target);
WaitOnCounter(&counter);
}
/* Release upload heap now */
@ -3040,7 +3019,7 @@ GPU_Swapchain *GPU_AllocSwapchain(P_Window *window, Vec2I32 resolution)
GPU_D12_Swapchain *swapchain = 0;
{
P_Lock lock = P_LockE(&g->swapchains_mutex);
Lock lock = LockE(&g->swapchains_mutex);
if (g->first_free_swapchain)
{
swapchain = g->first_free_swapchain;
@ -3050,7 +3029,7 @@ GPU_Swapchain *GPU_AllocSwapchain(P_Window *window, Vec2I32 resolution)
{
swapchain = PushStruct(g->swapchains_arena, GPU_D12_Swapchain);
}
P_Unlock(&lock);
Unlock(&lock);
}
/* Create swapchain1 */
@ -3132,9 +3111,9 @@ GPU_D12_SwapchainBuffer *GPU_D12_UpdateSwapchain(GPU_D12_Swapchain *swapchain, V
GPU_D12_CommandQueue *cq = g->command_queues[DX12_QUEUE_DIRECT];
/* Lock direct queue submissions (in case any write to backbuffer) */
/* TODO: Less overkill approach - Only flush GPU_D12_BlitToSwapchain since we know it's the only operation targeting backbuffer */
P_Lock lock = P_LockE(&cq->submit_fence_mutex);
Lock lock = LockE(&cq->submit_fence_mutex);
//DEBUGBREAKABLE;
//P_Lock lock = P_LockE(&g->global_command_list_record_mutex);
//Lock lock = LockE(&g->global_command_list_record_mutex);
{
/* Flush direct queue */
//ID3D12CommandQueue_Signal(cq->cq, cq->submit_fence, ++cq->submit_fence_target);
@ -3161,7 +3140,7 @@ GPU_D12_SwapchainBuffer *GPU_D12_UpdateSwapchain(GPU_D12_Swapchain *swapchain, V
P_Panic(Lit("Failed to resize swapchain"));
}
}
P_Unlock(&lock);
Unlock(&lock);
GPU_D12_InitSwapchainResources(swapchain);
@ -3309,7 +3288,7 @@ void GPU_PresentSwapchain(GPU_Swapchain *gp_swapchain, Vec2I32 backbuffer_resolu
__profn("Mark queue frames");
/* Lock because frame marks shouldn't occur while command lists are recording */
P_Lock lock = P_LockE(&g->global_command_list_record_mutex);
Lock lock = LockE(&g->global_command_list_record_mutex);
for (u32 i = 0; i < countof(g->command_queues); ++i)
{
{
@ -3317,7 +3296,7 @@ void GPU_PresentSwapchain(GPU_Swapchain *gp_swapchain, Vec2I32 backbuffer_resolu
__prof_dx12_new_frame(cq->prof);
}
}
P_Unlock(&lock);
Unlock(&lock);
}
{
__profn("Collect queues");
@ -3334,7 +3313,7 @@ void GPU_PresentSwapchain(GPU_Swapchain *gp_swapchain, Vec2I32 backbuffer_resolu
* Evictor job
* ========================== */
JobDef(GPU_D12_EvictorJob, _)
JobDef(GPU_D12_EvictorJob, UNUSED sig, UNUSED id)
{
GPU_D12_SharedState *g = &GPU_D12_shared_state;
u64 completed_targets[DX12_NUM_QUEUES] = ZI;
@ -3352,13 +3331,13 @@ JobDef(GPU_D12_EvictorJob, _)
GPU_D12_FencedReleaseData *fenced_releases = 0;
{
__profn("Copy queued releases");
P_Lock lock = P_LockE(&g->fenced_releases_mutex);
Lock lock = LockE(&g->fenced_releases_mutex);
num_fenced_releases = g->fenced_releases_arena->pos / sizeof(GPU_D12_FencedReleaseData);
fenced_releases = PushStructsNoZero(scratch.arena, GPU_D12_FencedReleaseData, num_fenced_releases);
CopyBytes(fenced_releases, ArenaBase(g->fenced_releases_arena), g->fenced_releases_arena->pos);
ResetArena(g->fenced_releases_arena);
CopyBytes(targets, g->fenced_release_targets, sizeof(targets));
P_Unlock(&lock);
Unlock(&lock);
}
/* Wait until fences reach target */
@ -3374,14 +3353,9 @@ JobDef(GPU_D12_EvictorJob, _)
{
__profn("Wait on fence");
{
GPU_D12_WaitOnFenceJobSig sig = ZI;
sig.fence = cq->submit_fence;
sig.target = targets[i];
{
Counter counter = ZI;
P_Run(1, GPU_D12_WaitOnFenceJob, &sig, PoolKind_Floating, PriorityKind_Low, &counter);
P_WaitOnCounter(&counter);
}
Counter counter = ZI;
RunJob(1, GPU_D12_WaitOnFenceJob, PoolKind_Floating, PriorityKind_Inherit, &counter, .fence = cq->submit_fence, .target = targets[i]);
WaitOnCounter(&counter);
}
}
}
@ -3415,15 +3389,15 @@ JobDef(GPU_D12_EvictorJob, _)
}
EndScratch(scratch);
}
P_Lock lock = P_LockE(&g->evictor_wake_mutex);
Lock lock = LockE(&g->evictor_wake_mutex);
{
while (!g->evictor_shutdown && g->evictor_wake_gen == 0)
{
P_WaitOnCv(&g->evictor_wake_cv, &lock);
WaitOnCv(&g->evictor_wake_cv, &lock);
}
shutdown = g->evictor_shutdown;
g->evictor_wake_gen = 0;
}
P_Unlock(&lock);
Unlock(&lock);
}
}

View File

@ -133,7 +133,7 @@ Struct(GPU_D12_CommandQueue)
ID3D12CommandQueue *cq;
Arena *arena;
P_Mutex submit_fence_mutex;
Mutex submit_fence_mutex;
u64 submit_fence_target;
ID3D12Fence *submit_fence;
@ -148,7 +148,7 @@ Struct(GPU_D12_CommandListPool)
{
GPU_D12_CommandQueue *cq;
Arena *arena;
P_Mutex mutex;
Mutex mutex;
struct GPU_D12_CommandList *first_submitted_command_list;
struct GPU_D12_CommandList *last_submitted_command_list;
};
@ -197,7 +197,7 @@ Struct(GPU_D12_CommandList)
GPU_D12_CommandListPool *pool;
struct ID3D12CommandAllocator *ca;
struct ID3D12GraphicsCommandList *cl;
P_Lock global_record_lock;
Lock global_record_lock;
GPU_D12_Pipeline *cur_pipeline;
@ -232,7 +232,7 @@ Struct(GPU_D12_CpuDescriptorHeap)
{
enum D3D12_DESCRIPTOR_HEAP_TYPE type;
Arena *arena;
P_Mutex mutex;
Mutex mutex;
u32 descriptor_size;
u32 num_descriptors_reserved;
@ -352,23 +352,23 @@ Struct(GPU_D12_SharedState)
Atomic32 initialized;
/* Descriptor heaps pool */
P_Mutex command_descriptor_heaps_mutex;
Mutex command_descriptor_heaps_mutex;
Arena *command_descriptor_heaps_arena;
GPU_D12_CommandDescriptorHeap *first_submitted_command_descriptor_heap;
GPU_D12_CommandDescriptorHeap *last_submitted_command_descriptor_heap;
/* Command buffers pool */
P_Mutex command_buffers_mutex;
Mutex command_buffers_mutex;
Arena *command_buffers_arena;
Dict *command_buffers_dict;
/* Resources pool */
P_Mutex resources_mutex;
Mutex resources_mutex;
Arena *resources_arena;
GPU_D12_Resource *first_free_resource;
/* Swapchains pool */
P_Mutex swapchains_mutex;
Mutex swapchains_mutex;
Arena *swapchains_arena;
GPU_D12_Swapchain *first_free_swapchain;
@ -376,7 +376,7 @@ Struct(GPU_D12_SharedState)
TAR_Archive dxc_archive;
/* Pipeline cache */
P_Mutex pipelines_mutex;
Mutex pipelines_mutex;
Arena *pipelines_arena;
GPU_D12_Pipeline *first_free_pipeline;
Dict *pipeline_descs;
@ -385,7 +385,7 @@ Struct(GPU_D12_SharedState)
GPU_D12_PipelineScope *first_free_pipeline_scope;
/* Fenced release queue */
P_Mutex fenced_releases_mutex;
Mutex fenced_releases_mutex;
Arena *fenced_releases_arena;
u64 fenced_release_targets[DX12_NUM_QUEUES];
@ -407,14 +407,14 @@ Struct(GPU_D12_SharedState)
GPU_D12_CpuDescriptorHeap *rtv_heap;
/* Command queues */
P_Mutex global_command_list_record_mutex;
P_Mutex global_submit_mutex;
Mutex global_command_list_record_mutex;
Mutex global_submit_mutex;
GPU_D12_CommandQueue *command_queues[DX12_NUM_QUEUES];
/* Evictor job */
Counter evictor_job_counter;
P_Cv evictor_wake_cv;
P_Mutex evictor_wake_mutex;
Cv evictor_wake_cv;
Mutex evictor_wake_mutex;
i64 evictor_wake_gen;
b32 evictor_shutdown;
};
@ -457,7 +457,7 @@ void GPU_D12_InitNoise(void);
* Shader compilation
* ========================== */
JobDecl(GPU_D12_CompileShaderJob, { Arena *arena; GPU_D12_ShaderDesc *decs; GPU_D12_CompiledShaderResult results; });
JobDecl(GPU_D12_CompileShaderJob, { Arena *arena; GPU_D12_ShaderDesc *descs; GPU_D12_CompiledShaderResult *results; });
/* ========================== *
* Pipeline

View File

@ -873,7 +873,7 @@ void JSON_Parse(Arena *arena, JSON_Parser *p)
if (is_new_parent)
{
/* PushStruct self back to stack to re-check for closing brace later */
/* Push self back to stack to re-check for closing brace later */
*PushStructNoZero(scratch.arena, JSON_Blob *) = json;
++stack_count;

View File

@ -53,10 +53,10 @@ MIX_Track *MIX_TrackFromHandle(MIX_Handle handle)
}
}
MIX_Track *MIX_AllocTrackLocked(P_Lock *lock, SND_Sound *sound)
MIX_Track *MIX_AllocTrackLocked(Lock *lock, SND_Sound *sound)
{
MIX_SharedState *g = &M_shared_state;
P_AssertLockedE(lock, &g->mutex);
AssertLockedE(lock, &g->mutex);
LAX lock;
MIX_Track *track = 0;
@ -100,10 +100,10 @@ MIX_Track *MIX_AllocTrackLocked(P_Lock *lock, SND_Sound *sound)
return track;
}
void MIX_ReleaseTrackLocked(P_Lock *lock, MIX_Track *track)
void MIX_ReleaseTrackLocked(Lock *lock, MIX_Track *track)
{
MIX_SharedState *g = &M_shared_state;
P_AssertLockedE(lock, &g->mutex);
AssertLockedE(lock, &g->mutex);
LAX lock;
/* Remove from playing list */
@ -155,12 +155,12 @@ MIX_Handle MIX_PlaySoundEx(SND_Sound *sound, MIX_TrackDesc desc)
MIX_SharedState *g = &M_shared_state;
MIX_Track *track;
{
P_Lock lock = P_LockE(&g->mutex);
Lock lock = LockE(&g->mutex);
{
track = MIX_AllocTrackLocked(&lock, sound);
track->desc = desc;
}
P_Unlock(&lock);
Unlock(&lock);
}
return MIX_HandleFromTrack(track);
}
@ -175,7 +175,7 @@ MIX_TrackDesc MIX_TrackDescFromHandle(MIX_Handle handle)
if (track)
{
/* TODO: Only lock mutex on track itself or something */
P_Lock lock = P_LockE(&g->mutex);
Lock lock = LockE(&g->mutex);
{
/* Confirm handle is still valid now that we're locked */
track = MIX_TrackFromHandle(handle);
@ -184,7 +184,7 @@ MIX_TrackDesc MIX_TrackDescFromHandle(MIX_Handle handle)
result = track->desc;
}
}
P_Unlock(&lock);
Unlock(&lock);
}
return result;
@ -198,7 +198,7 @@ void MIX_UpdateTrack(MIX_Handle handle, MIX_TrackDesc desc)
if (track)
{
/* TODO: Only lock mutex on track itself or something */
P_Lock lock = P_LockE(&g->mutex);
Lock lock = LockE(&g->mutex);
{
/* Confirm handle is still valid now that we're locked */
track = MIX_TrackFromHandle(handle);
@ -207,19 +207,19 @@ void MIX_UpdateTrack(MIX_Handle handle, MIX_TrackDesc desc)
track->desc = desc;
}
}
P_Unlock(&lock);
Unlock(&lock);
}
}
void MIX_UpdateListener(Vec2 pos, Vec2 dir)
{
MIX_SharedState *g = &M_shared_state;
P_Lock lock = P_LockE(&g->mutex);
Lock lock = LockE(&g->mutex);
{
g->listener_pos = pos;
g->listener_dir = NormVec2(dir);
}
P_Unlock(&lock);
Unlock(&lock);
}
////////////////////////////////
@ -260,7 +260,7 @@ MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count)
MIX_MixData **mixes = 0;
u64 mixes_count = 0;
{
P_Lock lock = P_LockE(&g->mutex);
Lock lock = LockE(&g->mutex);
/* Read listener info */
listener_pos = g->listener_pos;
@ -276,7 +276,7 @@ MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count)
mixes[mixes_count++] = mix;
}
P_Unlock(&lock);
Unlock(&lock);
}
//- Process mix data
@ -461,7 +461,7 @@ MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count)
//- Update track effect data
{
__profn("Update track effect data");
P_Lock lock = P_LockE(&g->mutex);
Lock lock = LockE(&g->mutex);
for (u64 i = 0; i < mixes_count; ++i)
{
MIX_MixData *mix = mixes[i];
@ -475,7 +475,7 @@ MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count)
}
}
}
P_Unlock(&lock);
Unlock(&lock);
}
EndScratch(scratch);

View File

@ -79,7 +79,7 @@ Struct(MIX_Track){
Struct(MIX_SharedState)
{
P_Mutex mutex;
Mutex mutex;
/* Listener */
Vec2 listener_pos;
@ -106,8 +106,8 @@ MIX_StartupReceipt MIX_Startup(void);
MIX_Handle MIX_HandleFromTrack(MIX_Track *track);
MIX_Track *MIX_TrackFromHandle(MIX_Handle handle);
MIX_Track *MIX_AllocTrackLocked(P_Lock *lock, SND_Sound *sound);
void MIX_ReleaseTrackLocked(P_Lock *lock, MIX_Track *track);
MIX_Track *MIX_AllocTrackLocked(Lock *lock, SND_Sound *sound);
void MIX_ReleaseTrackLocked(Lock *lock, MIX_Track *track);
////////////////////////////////
//~ Mixer state operations

View File

@ -11,6 +11,7 @@
# include <mfidl.h>
# include <mfreadwrite.h>
# include <Shlwapi.h>
# include <objidl.h>
#pragma warning(pop)
#pragma comment(lib, "mfplat")
@ -121,7 +122,8 @@ MP3_Result MP3_Decode(Arena *arena, String encoded, u32 sample_rate, MP3_DecodeF
IMFSourceReader_Release(reader);
IMFByteStream_Close(byte_stream);
IStream_Release(i_stream);
/* FIXME: Enable this */
//IStream_Release(i_stream);
MFShutdown();
return result;

View File

@ -542,7 +542,7 @@ N_EventList N_BeginUpdate(Arena *arena, N_Host *host)
TempArena scratch = BeginScratch(arena);
N_EventList events = ZI;
i64 now_ns = P_TimeNs();
i64 now_ns = TimeNs();
{
__profn("Read packets");

View File

@ -246,7 +246,7 @@ Struct(N_Host)
u64 num_msg_assembler_lookup_bins;
/* Double buffer for incoming data */
P_Mutex rcv_buffer_write_mutex;
Mutex rcv_buffer_write_mutex;
N_RcvBuffer *rcv_buffer_read;
N_RcvBuffer *rcv_buffer_write;

View File

@ -1,6 +1,5 @@
#include "platform.h"
#include "platform_snc.c"
#include "platform_log.c"
#if PlatformIsWindows

View File

@ -3,7 +3,6 @@
#include "../base/base.h"
#include "platform_snc.h"
#include "platform_core.h"
#include "platform_log.h"

View File

@ -311,7 +311,6 @@ typedef P_ExitFuncDef(P_ExitFunc);
//~ @hookdecl Time helper operations
P_DateTime P_LocalTime(void);
i64 P_TimeNs(void);
////////////////////////////////
//~ @hookdecl File system operations
@ -403,9 +402,6 @@ void P_WriteSock(P_Sock *sock, P_Address address, String data);
void P_MessageBox(P_MessageBoxKind kind, String message);
void P_SetClipboardText(String str);
String P_GetClipboardText(Arena *arena);
u32 P_GetLogicalProcessorCount(void);
u32 P_GetThreadId(void);
i64 P_GetCurrentSchedulerPeriodNs(void);
////////////////////////////////
//~ @hookdecl Sleep

View File

@ -32,7 +32,7 @@ void P_RegisterLogCallback(P_LogEventCallbackFunc *func, i32 level)
{
P_SharedLogState *ctx = &P_shared_log_state;
if (!Atomic32Fetch(&ctx->initialized)) { return; }
P_Lock lock = P_LockE(&ctx->callbacks_mutex);
Lock lock = LockE(&ctx->callbacks_mutex);
{
LogEventCallback *callback = PushStruct(ctx->callbacks_arena, LogEventCallback);
callback->func = func;
@ -47,7 +47,7 @@ void P_RegisterLogCallback(P_LogEventCallbackFunc *func, i32 level)
}
ctx->last_callback = callback;
}
P_Unlock(&lock);
Unlock(&lock);
}
////////////////////////////////
@ -149,12 +149,12 @@ void P_Log_(i32 level, String msg)
}
u32 tid = P_GetThreadId();
u32 tid = ThreadId();
//- Format message
P_DateTime datetime = P_LocalTime();
i64 time_ns = P_TimeNs();
i64 time_ns = TimeNs();
String shorthand = settings.shorthand;
#if P_IncludeLogSourceLocation
@ -217,7 +217,7 @@ void P_Log_(i32 level, String msg)
event.line = line;
#endif
{
P_Lock lock = P_LockS(&ctx->callbacks_mutex);
Lock lock = LockS(&ctx->callbacks_mutex);
for (LogEventCallback *callback = ctx->first_callback; callback; callback = callback->next)
{
if (level <= callback->level)
@ -226,7 +226,7 @@ void P_Log_(i32 level, String msg)
callback->func(event);
}
}
P_Unlock(&lock);
Unlock(&lock);
}
EndScratch(scratch);

View File

@ -63,7 +63,7 @@ Struct(P_SharedLogState)
{
Atomic32 initialized;
P_Mutex callbacks_mutex;
Mutex callbacks_mutex;
Arena *callbacks_arena;
LogEventCallback *first_callback;
LogEventCallback *last_callback;

View File

@ -1,83 +0,0 @@
////////////////////////////////
//~ Mutex types
#define P_DefaultMutexSpin 4000
AlignedStruct(P_Mutex, 64)
{
/* Bit 31 = Exclusive lock is held
* Bit 30 = Exclusive lock is pending
* Bit 0-30 = Shared locks count
*/
Atomic32 v;
#if RtcIsEnabled
Atomic32 exclusive_fiber_id;
u8 _pad[56];
#else
u8 _pad[60];
#endif
};
StaticAssert(sizeof(P_Mutex) == 64); /* Padding validation */
StaticAssert(alignof(P_Mutex) == 64); /* Prevent false sharing */
Struct(P_Lock)
{
P_Mutex *mutex;
b32 exclusive;
};
////////////////////////////////
//~ Condition variable types
AlignedStruct(P_Cv, 64)
{
Atomic64 wake_gen;
u8 _pad[56];
};
StaticAssert(sizeof(P_Cv) == 64); /* Padding validation */
StaticAssert(alignof(P_Cv) == 64); /* Prevent false sharing */
////////////////////////////////
//~ Counter types
AlignedStruct(Counter, 64)
{
Atomic64 v;
u8 _pad[56];
};
StaticAssert(sizeof(Counter) == 64); /* Padding validation */
StaticAssert(alignof(Counter) == 64); /* Prevent false sharing */
////////////////////////////////
//~ Mutex operations
P_Lock P_LockSpinE(P_Mutex *m, i32 spin);
P_Lock P_LockSpinS(P_Mutex *m, i32 spin);
P_Lock P_LockE(P_Mutex *m);
P_Lock P_LockS(P_Mutex *m);
void P_Unlock(P_Lock *lock);
//- Lock assertion
#if RtcIsEnabled
# define P_AssertLockedE(l, m) Assert((l)->mutex == (m) && (l)->exclusive == 1)
# define P_AssertLockedES(l, m) Assert((l)->mutex == (m))
#else
# define P_AssertLockedE(l, m) LAX l
# define P_AssertLockedES(l, m) LAX l
#endif
////////////////////////////////
//~ Condition variable operations
void P_WaitOnCv(P_Cv *cv, P_Lock *lock);
void P_WaitOnCvTime(P_Cv *cv, P_Lock *l, i64 timeout_ns);
void P_SignalCv(P_Cv *cv, i32 count);
////////////////////////////////
//~ Counter operations
void P_CounterAdd(Counter *counter, i64 x);
void P_WaitOnCounter(Counter *counter);

View File

@ -72,7 +72,7 @@ P_W32_Window *P_W32_AllocWindow(void)
P_W32_SharedCtx *g = &P_W32_shared_ctx;
P_W32_Window *window = 0;
{
P_Lock lock = P_LockE(&g->windows_mutex);
Lock lock = LockE(&g->windows_mutex);
if (g->first_free_window)
{
window = g->first_free_window;
@ -82,7 +82,7 @@ P_W32_Window *P_W32_AllocWindow(void)
{
window = PushStructNoZero(g->windows_arena, P_W32_Window);
}
P_Unlock(&lock);
Unlock(&lock);
}
ZeroStruct(window);
@ -93,9 +93,9 @@ P_W32_Window *P_W32_AllocWindow(void)
/* NOTE: This thread must finish building for the window to actually be
* created and receive a HWND, because on Windows a the event proc must run on
* the same thread that created the window. */
P_CounterAdd(&window->ready_fence, 1);
window->window_thread = P_W32_AllocThread(&W32_WindowThreadEntryFunc, window, Lit("Window thread"), PROF_THREAD_GROUP_WINDOW);
P_WaitOnCounter(&window->ready_fence);
AddCounter(&window->ready_fence, 1);
window->window_thread = W32_AllocThread(&P_W32_WindowThreadEntryFunc, window, Lit("Window thread"), PROF_THREAD_GROUP_WINDOW);
WaitOnCounter(&window->ready_fence);
return window;
}
@ -106,14 +106,14 @@ void P_W32_ReleaseWindow(P_W32_Window *window)
Atomic32FetchSet(&window->shutdown, 1);
P_W32_SharedCtx *g = &P_W32_shared_ctx;
P_W32_WakeWindow(window);
P_W32_WaitReleaseThread(window->window_thread);
W32_WaitReleaseThread(window->window_thread);
P_Lock lock = P_LockE(&g->windows_mutex);
Lock lock = LockE(&g->windows_mutex);
{
window->next_free = g->first_free_window;
g->first_free_window = window;
}
P_Unlock(&lock);
Unlock(&lock);
}
HWND P_W32_InitWindow(P_W32_Window *window)
@ -302,7 +302,7 @@ void P_W32_UpdateWindowFromSettings(P_W32_Window *window, P_WindowSettings *sett
////////////////////////////////
//~ Win32 window thread
W32_ThreadDef(W32_WindowThreadEntryFunc, arg)
W32_ThreadDef(P_W32_WindowThreadEntryFunc, arg)
{
P_W32_Window *window = (P_W32_Window *)arg;
@ -310,7 +310,7 @@ W32_ThreadDef(W32_WindowThreadEntryFunc, arg)
window->hwnd = P_W32_InitWindow(window);
P_W32_UpdateWindowFromSystem(window);
BringWindowToTop(window->hwnd);
P_CounterAdd(&window->ready_fence, -1);
AddCounter(&window->ready_fence, -1);
while (!Atomic32Fetch(&window->shutdown))
{
@ -335,11 +335,11 @@ W32_ThreadDef(W32_WindowThreadEntryFunc, arg)
void P_W32_ProcessWindowEvent(P_W32_Window *window, P_WindowEvent event)
{
__prof;
P_Lock lock = P_LockE(&window->event_arena_swp_mutex);
Lock lock = LockE(&window->event_arena_swp_mutex);
{
*PushStruct(window->event_arenas[window->current_event_arena_index], P_WindowEvent) = event;
}
P_Unlock(&lock);
Unlock(&lock);
}
void P_W32_WakeWindow(P_W32_Window *window)
@ -785,15 +785,6 @@ P_DateTime P_LocalTime(void)
return P_W32_DateTimeFromWin32SystemTime(lt);
}
i64 P_TimeNs(void)
{
struct P_W32_SharedCtx *g = &P_W32_shared_ctx;
LARGE_INTEGER qpc;
QueryPerformanceCounter(&qpc);
i64 result = (qpc.QuadPart - g->timer_start_qpc) * g->ns_per_qpc;
return result;
}
////////////////////////////////
//~ @hookdef File system hooks
@ -1166,7 +1157,7 @@ P_Watch *P_AllocWatch(String dir_path)
P_W32_Watch *w32_watch = 0;
{
P_Lock lock = P_LockE(&g->watches_mutex);
Lock lock = LockE(&g->watches_mutex);
{
if (g->watches_first_free)
{
@ -1178,7 +1169,7 @@ P_Watch *P_AllocWatch(String dir_path)
w32_watch = PushStructNoZero(g->watches_arena, P_W32_Watch);
}
}
P_Unlock(&lock);
Unlock(&lock);
}
ZeroStruct(w32_watch);
@ -1206,12 +1197,12 @@ void P_ReleaseWatch(P_Watch *dw)
CloseHandle(w32_watch->dir_handle);
CloseHandle(w32_watch->wake_handle);
P_Lock lock = P_LockE(&g->watches_mutex);
Lock lock = LockE(&g->watches_mutex);
{
w32_watch->next_free = g->watches_first_free;
g->watches_first_free = w32_watch;
}
P_Unlock(&lock);
Unlock(&lock);
}
P_WatchInfoList P_ReadWatchWait(Arena *arena, P_Watch *dw)
@ -1369,10 +1360,10 @@ P_WindowEventArray P_PopWindowEvents(Arena *arena, P_Window *p_window)
i32 event_arena_index = 0;
{
/* Swap event buffers */
P_Lock lock = P_LockE(&window->event_arena_swp_mutex);
Lock lock = LockE(&window->event_arena_swp_mutex);
event_arena_index = window->current_event_arena_index;
window->current_event_arena_index = 1 - window->current_event_arena_index;
P_Unlock(&lock);
Unlock(&lock);
}
Arena *events_arena = window->event_arenas[event_arena_index];
P_WindowEventArray events = ZI;
@ -1388,11 +1379,11 @@ void P_UpdateWindowSettings(P_Window *p_window, P_WindowSettings *settings)
{
__prof;
P_W32_Window *window = (P_W32_Window *)p_window;
P_Lock lock = P_LockE(&window->settings_mutex);
Lock lock = LockE(&window->settings_mutex);
{
P_W32_UpdateWindowFromSettings(window, settings);
}
P_Unlock(&lock);
Unlock(&lock);
}
/* FIXME: Lock settings mutex for these functions */
@ -1407,7 +1398,7 @@ void P_ShowWindow(P_Window *p_window)
{
P_W32_Window *window = (P_W32_Window *)p_window;
HWND hwnd = window->hwnd;
P_Lock lock = P_LockE(&window->settings_mutex);
Lock lock = LockE(&window->settings_mutex);
{
i32 show_cmd = SW_NORMAL;
P_WindowSettings *settings = &window->settings;
@ -1423,7 +1414,7 @@ void P_ShowWindow(P_Window *p_window)
ShowWindow(hwnd, show_cmd);
BringWindowToTop(hwnd);
}
P_Unlock(&lock);
Unlock(&lock);
}
void P_SetWindowCursorPos(P_Window *p_window, Vec2 pos)
@ -1699,7 +1690,7 @@ P_Sock *P_AllocSock(u16 listen_port, u64 sndbuf_size, u64 rcvbuf_size)
P_W32_SharedCtx *g = &P_W32_shared_ctx;
P_W32_Sock *ws = 0;
{
P_Lock lock = P_LockE(&g->socks_mutex);
Lock lock = LockE(&g->socks_mutex);
if (g->first_free_sock)
{
ws = g->first_free_sock;
@ -1709,7 +1700,7 @@ P_Sock *P_AllocSock(u16 listen_port, u64 sndbuf_size, u64 rcvbuf_size)
{
ws = PushStructNoZero(g->socks_arena, P_W32_Sock);
}
P_Unlock(&lock);
Unlock(&lock);
}
ZeroStruct(ws);
@ -1734,12 +1725,12 @@ void P_ReleaseSock(P_Sock *sock)
P_W32_SharedCtx *g = &P_W32_shared_ctx;
P_W32_Sock *ws = (P_W32_Sock *)sock;
closesocket(ws->sock);
P_Lock lock = P_LockE(&g->socks_mutex);
Lock lock = LockE(&g->socks_mutex);
{
ws->next_free = g->first_free_sock;
g->first_free_sock = ws;
}
P_Unlock(&lock);
Unlock(&lock);
}
P_SockReadResult P_ReadSock(Arena *arena, P_Sock *sock)
@ -1885,22 +1876,6 @@ String P_GetClipboardText(Arena *arena)
return result;
}
u32 P_GetLogicalProcessorCount(void)
{
return GetActiveProcessorCount(ALL_PROCESSOR_GROUPS);
}
u32 P_GetThreadId(void)
{
return GetCurrentThreadId();
}
i64 P_GetCurrentSchedulerPeriodNs(void)
{
P_W32_SharedCtx *g = &P_W32_shared_ctx;
return Atomic64Fetch(&g->current_scheduler_cycle_period_ns.v);
}
////////////////////////////////
//~ @hookdef Sleep hooks
@ -1908,19 +1883,19 @@ void P_SleepPrecise(i64 sleep_time_ns)
{
__prof;
i64 big_sleep = P_GetCurrentSchedulerPeriodNs();
i64 big_sleep = GetCurrentSchedulerPeriodNs();
i64 tolerance = (f64)big_sleep * 0.5;
//i64 tolerance = 1000000000;
i64 now_ns = P_TimeNs();
i64 now_ns = TimeNs();
i64 target_ns = now_ns + sleep_time_ns;
/* Sleep */
while (now_ns < target_ns - big_sleep - tolerance)
{
__profn("Sleep part");
P_Wait(0, 0, 0, big_sleep);
now_ns = P_TimeNs();
FutexWait(0, 0, 0, big_sleep);
now_ns = TimeNs();
}
/* Spin */
@ -1929,7 +1904,7 @@ void P_SleepPrecise(i64 sleep_time_ns)
while (now_ns < target_ns)
{
_mm_pause();
now_ns = P_TimeNs();
now_ns = TimeNs();
}
}
}
@ -1938,7 +1913,7 @@ void P_SleepFrame(i64 last_frame_time_ns, i64 target_dt_ns)
{
if (last_frame_time_ns != 0 && target_dt_ns > 0)
{
i64 now_ns = P_TimeNs();
i64 now_ns = TimeNs();
i64 last_frame_dt_ns = now_ns - last_frame_time_ns;
i64 sleep_time_ns = target_dt_ns - last_frame_dt_ns;
if (sleep_time_ns > 0)
@ -2073,7 +2048,7 @@ void P_W32_InitBtnTable(void)
g->vk_btn_table[VK_OEM_1] = P_Btn_Semicolon;
}
JobDef(P_W32_AppStartupJob, UNUSED job)
JobDef(P_W32_AppStartupJob, UNUSED sig, UNUSED id)
{
P_W32_SharedCtx *g = &P_W32_shared_ctx;
TempArena scratch = BeginScratchNoConflict();
@ -2085,7 +2060,7 @@ JobDef(P_W32_AppStartupJob, UNUSED job)
EndScratch(scratch);
}
JobDef(P_W32_AppShutdownJob, _)
JobDef(P_W32_AppShutdownJob, UNUSED sig, UNUSED id)
{
__prof;
P_W32_SharedCtx *g = &P_W32_shared_ctx;
@ -2188,18 +2163,6 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
g->exit_begin_event = CreateEventW(0, 1, 0, 0);
g->exit_end_event = CreateEventW(0, 1, 0, 0);
/* Init timer */
{
LARGE_INTEGER qpf;
QueryPerformanceFrequency(&qpf);
g->ns_per_qpc = 1000000000 / qpf.QuadPart;
}
{
LARGE_INTEGER qpc;
QueryPerformanceCounter(&qpc);
g->timer_start_qpc = qpc.QuadPart;
}
/* Convert main thread to fiber */
W32_AllocFiber(0);
@ -2253,9 +2216,6 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
LAX success;
}
/* Init threads pool */
g->threads_arena = AllocArena(Gibi(64));
/* Init watches pool */
g->watches_arena = AllocArena(Gibi(64));
@ -2271,7 +2231,7 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
/* Run app start job */
if (!Atomic32Fetch(&g->panicking))
{
P_Run(1, P_W32_AppStartupJob, 0, PoolKind_Floating, PriorityKind_High, 0);
RunJob(1, P_W32_AppStartupJob, 0, PoolKind_Floating, PriorityKind_High, 0);
}
/* Wait for startup end or panic */
@ -2299,7 +2259,7 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
/* Run exit callbacks job */
if (!Atomic32Fetch(&g->panicking))
{
P_Run(1, P_W32_AppShutdownJob, 0, PoolKind_Floating, PriorityKind_High, 0);
RunJob(1, P_W32_AppShutdownJob, 0, PoolKind_Floating, PriorityKind_High, 0);
}
/* Wait for exit end or panic */

View File

@ -39,7 +39,7 @@ Struct(P_W32_Window)
u16 utf16_high_surrogate_last_input;
P_Mutex settings_mutex;
Mutex settings_mutex;
P_WindowSettings settings;
i32 monitor_width;
@ -57,7 +57,7 @@ Struct(P_W32_Window)
Atomic32 topmost_toggles;
b32 is_topmost;
P_Mutex event_arena_swp_mutex;
Mutex event_arena_swp_mutex;
i32 current_event_arena_index;
Arena *event_arenas[2];
@ -113,8 +113,6 @@ Struct(P_W32_Sock)
Struct(P_W32_SharedCtx)
{
SYSTEM_INFO info;
i64 timer_start_qpc;
i64 ns_per_qpc;
u32 main_thread_id;
Atomic32 shutdown;
@ -132,20 +130,20 @@ Struct(P_W32_SharedCtx)
P_Btn vk_btn_table[256];
//- Watches pool
P_Mutex watches_mutex;
Mutex watches_mutex;
Arena *watches_arena;
P_W32_Watch *watches_first_free;
//- Windows pool
WNDCLASSEXW window_class;
P_Mutex windows_mutex;
Mutex windows_mutex;
Arena *windows_arena;
P_W32_Window *first_free_window;
//- Socket pool
WSADATA wsa_data;
Arena *socks_arena;
P_Mutex socks_mutex;
Mutex socks_mutex;
P_W32_Sock *first_free_sock;
//- Exit funcs

View File

@ -16,7 +16,7 @@ PB_StartupReceipt PB_Startup(MIX_StartupReceipt *mixer_sr)
LAX mixer_sr;
PB_WSP_InitializeWasapi();
/* Start playback job */
P_Run(1, PB_WSP_PlaybackJob, 0, PoolKind_Audio, PriorityKind_High, &g->PB_WSP_PlaybackJob_counter);
RunJob(1, PB_WSP_PlaybackJob, 0, PoolKind_Audio, PriorityKind_High, &g->PB_WSP_PlaybackJob_counter);
P_OnExit(&PB_WSP_Shutdown);
return (PB_StartupReceipt) { 0 };
@ -27,7 +27,7 @@ P_ExitFuncDef(PB_WSP_Shutdown)
__prof;
PB_WSP_SharedState *g = &PB_WSP_shared_state;
Atomic32FetchSet(&g->shutdown, 1);
P_WaitOnCounter(&g->PB_WSP_PlaybackJob_counter);
WaitOnCounter(&g->PB_WSP_PlaybackJob_counter);
}
void PB_WSP_InitializeWasapi(void)
@ -184,7 +184,7 @@ void PB_WSP_EndUpdate(PB_WSP_Buff *wspbuf, MIX_PcmF32 src)
////////////////////////////////
//~ Playback job
JobDef(PB_WSP_PlaybackJob, _)
JobDef(PB_WSP_PlaybackJob, UNUSED sig, UNUSED id)
{
__prof;
PB_WSP_SharedState *g = &PB_WSP_shared_state;

View File

@ -11,11 +11,9 @@ UserStartupReceipt StartupUser(S_StartupReceipt *sprite_sr,
String connect_address_str)
{
__prof;
LAX font_sr;
LAX sprite_sr;
LAX draw_sr;
LAX asset_cache_sr;
LAX sound_sr;
LAX mixer_sr;
LAX sim_sr;
SharedUserState *g = &shared_user_state;
@ -23,7 +21,7 @@ UserStartupReceipt StartupUser(S_StartupReceipt *sprite_sr,
SetGstat(GSTAT_DEBUG_STEPS, U64Max);
g->arena = AllocArena(Gibi(64));
g->real_time_ns = P_TimeNs();
g->real_time_ns = TimeNs();
/* TODO: Remove this */
g->connect_address_str = PushString(g->arena, connect_address_str);
@ -55,8 +53,8 @@ UserStartupReceipt StartupUser(S_StartupReceipt *sprite_sr,
P_ShowWindow(g->window);
/* Start jobs */
P_Run(1, UpdateUserJob, 0, PoolKind_User, PriorityKind_High, &g->shutdown_job_counters);
P_Run(1, SimJob, 0, PoolKind_Sim, PriorityKind_High, &g->shutdown_job_counters);
RunJob(1, UpdateUserJob, 0, PoolKind_User, PriorityKind_High, &g->shutdown_job_counters);
RunJob(1, SimJob, 0, PoolKind_Sim, PriorityKind_High, &g->shutdown_job_counters);
P_OnExit(&ShutdownUser);
return (UserStartupReceipt) { 0 };
@ -70,7 +68,7 @@ P_ExitFuncDef(ShutdownUser)
__prof;
SharedUserState *g = &shared_user_state;
Atomic32FetchSet(&g->shutdown, 1);
P_WaitOnCounter(&g->shutdown_job_counters);
WaitOnCounter(&g->shutdown_job_counters);
P_ReleaseWindow(g->window);
}
@ -234,7 +232,7 @@ P_LogEventCallbackFuncDef(ConsoleLogCallback, log)
{
__prof;
SharedUserState *g = &shared_user_state;
P_Lock lock = P_LockE(&g->console_logs_mutex);
Lock lock = LockE(&g->console_logs_mutex);
{
ConsoleLog *clog = PushStruct(g->console_logs_arena, ConsoleLog);
clog->level = log.level;
@ -257,7 +255,7 @@ P_LogEventCallbackFuncDef(ConsoleLogCallback, log)
}
g->last_console_log = clog;
}
P_Unlock(&lock);
Unlock(&lock);
}
//- Draw console
@ -298,11 +296,11 @@ void DrawDebugConsole(i32 level, b32 minimized)
}
g->console_logs_height = 0;
i64 now_ns = P_TimeNs();
i64 now_ns = TimeNs();
F_Font *font = F_LoadFontAsync(Lit("font/fixedsys.ttf"), 12.0f);
if (font)
{
P_Lock lock = P_LockE(&g->console_logs_mutex);
Lock lock = LockE(&g->console_logs_mutex);
{
for (ConsoleLog *log = g->last_console_log; log; log = log->prev)
{
@ -356,7 +354,7 @@ void DrawDebugConsole(i32 level, b32 minimized)
}
}
}
P_Unlock(&lock);
Unlock(&lock);
}
if (bounds_top < F32Infinity && bounds_bottom > -F32Infinity)
{
@ -417,7 +415,7 @@ void UpdateUser(P_Window *window)
TempArena scratch = BeginScratchNoConflict();
//- Begin frame
g->real_dt_ns = P_TimeNs() - g->real_time_ns;
g->real_dt_ns = TimeNs() - g->real_time_ns;
g->real_time_ns += g->real_dt_ns;
g->screen_size = P_GetWindowSize(window);
S_Scope *sprite_frame_scope = S_BeginScope();
@ -426,7 +424,7 @@ void UpdateUser(P_Window *window)
{
__profn("Pull snapshot");
P_Lock lock = P_LockE(&g->local_to_user_client_mutex);
Lock lock = LockE(&g->local_to_user_client_mutex);
u64 old_last_tick = g->user_unblended_client->last_tick;
u64 last_tick = g->local_to_user_client->last_tick;
if (last_tick > old_last_tick)
@ -437,7 +435,7 @@ void UpdateUser(P_Window *window)
g->average_local_to_user_snapshot_publish_dt_ns -= g->average_local_to_user_snapshot_publish_dt_ns / 50;
g->average_local_to_user_snapshot_publish_dt_ns += g->local_to_user_client_publish_dt_ns / 50;
}
P_Unlock(&lock);
Unlock(&lock);
}
//- Create user world from blended snapshots
@ -1832,7 +1830,7 @@ void UpdateUser(P_Window *window)
/* Set user sim control */
{
P_Lock lock = P_LockE(&g->user_sim_cmd_mutex);
Lock lock = LockE(&g->user_sim_cmd_mutex);
/* Reset flags */
if (g->user_sim_cmd_gen != g->last_user_sim_cmd_gen)
@ -1845,7 +1843,7 @@ void UpdateUser(P_Window *window)
g->user_sim_cmd_control = control;
g->user_sim_cmd_control.flags |= old_flags;
g->user_hovered_ent = hovered_ent->id;
P_Unlock(&lock);
Unlock(&lock);
}
}
@ -1869,7 +1867,7 @@ void UpdateUser(P_Window *window)
{
/* Update network usage stats */
i64 stat_now_ns = P_TimeNs();
i64 stat_now_ns = TimeNs();
g->net_bytes_read.last_second_end = GetGstat(GSTAT_SOCK_BYTES_RECEIVED);
g->net_bytes_sent.last_second_end = GetGstat(GSTAT_SOCK_BYTES_SENT);
if (stat_now_ns - g->last_second_reset_ns > NsFromSeconds(1))
@ -2066,10 +2064,10 @@ void UpdateUser(P_Window *window)
//- User update job
JobDef(UpdateUserJob, _)
JobDef(UpdateUserJob, UNUSED sig, UNUSED id)
{
SharedUserState *g = &shared_user_state;
i64 time_ns = P_TimeNs();
i64 time_ns = TimeNs();
while (!Atomic32Fetch(&g->shutdown))
{
P_Window *window = g->window;
@ -2082,7 +2080,7 @@ JobDef(UpdateUserJob, _)
{
__profn("Frame limiter wait");
P_SleepFrame(time_ns, 1000000000 / FPS_LIMIT);
time_ns = P_TimeNs();
time_ns = TimeNs();
}
}
UpdateUser(window);
@ -2109,7 +2107,7 @@ void GenerateuserInputCmds(Client *user_input_client, u64 tick)
sim_ent_activate(control_cmd, user_input_ss->tick);
}
{
P_Lock lock = P_LockE(&g->user_sim_cmd_mutex);
Lock lock = LockE(&g->user_sim_cmd_mutex);
/* Update control cmd */
{
control_cmd->cmd_control = g->user_sim_cmd_control;
@ -2125,14 +2123,14 @@ void GenerateuserInputCmds(Client *user_input_client, u64 tick)
}
#endif
++g->user_sim_cmd_gen;
P_Unlock(&lock);
Unlock(&lock);
}
}
////////////////////////////////
//~ Sim update
JobDef(SimJob, UNUSED job)
JobDef(SimJob, UNUSED sig, UNUSED id)
{
SharedUserState *g = &shared_user_state;
#if 0
@ -2221,7 +2219,7 @@ JobDef(SimJob, UNUSED job)
{
__profn("Sim update");
real_dt_ns = P_TimeNs() - real_time_ns;
real_dt_ns = TimeNs() - real_time_ns;
real_time_ns += real_dt_ns;
N_EventList host_events = N_BeginUpdate(scratch.arena, host);
@ -2798,9 +2796,9 @@ JobDef(SimJob, UNUSED job)
if (local_ss->valid)
{
/* TODO: Double buffer */
P_Lock lock = P_LockE(&g->local_to_user_client_mutex);
Lock lock = LockE(&g->local_to_user_client_mutex);
sim_snapshot_alloc(g->local_to_user_client, local_ss, local_ss->tick);
i64 publish_ns = P_TimeNs();
i64 publish_ns = TimeNs();
if (last_publish_to_user_ns == 0)
{
last_publish_to_user_ns = publish_ns - g->average_local_to_user_snapshot_publish_dt_ns;
@ -2809,7 +2807,7 @@ JobDef(SimJob, UNUSED job)
g->local_to_user_client_publish_time_ns = publish_ns;
last_publish_to_user_ns = publish_ns;
sim_snapshot_release_ticks_in_range(g->local_to_user_client, 0, local_ss->tick - 1);
P_Unlock(&lock);
Unlock(&lock);
}
}

View File

@ -185,7 +185,7 @@ Struct(SharedUserState)
b32 debug_draw;
//- Debug console
P_Mutex console_logs_mutex;
Mutex console_logs_mutex;
Arena *console_logs_arena;
ConsoleLog *first_console_log;
ConsoleLog *last_console_log;
@ -194,11 +194,11 @@ Struct(SharedUserState)
b32 debug_console;
//- Window -> user
P_Mutex sys_window_events_mutex;
Mutex sys_window_events_mutex;
Arena *sys_window_events_arena;
//- User -> sim
P_Mutex user_sim_cmd_mutex;
Mutex user_sim_cmd_mutex;
ControlData user_sim_cmd_control;
EntityId user_hovered_ent;
u64 last_user_sim_cmd_gen;
@ -208,7 +208,7 @@ Struct(SharedUserState)
Atomic32 user_paused_steps;
//- Sim -> user
P_Mutex local_to_user_client_mutex;
Mutex local_to_user_client_mutex;
ClientStore *local_to_user_client_store;
Client *local_to_user_client;
i64 local_to_user_client_publish_dt_ns;

View File

@ -329,14 +329,14 @@ Snapshot *sim_snapshot_alloc(Client *client, Snapshot *src, u64 tick)
if (ss->num_ents_reserved == 0) {
/* Copying from nil snapshot, need to create blank & root entity */
/* PushStruct blank ent at index 0 (because index 0 is never valid anyway since it maps to sim_ent_nil()) */
/* Push blank ent at index 0 (because index 0 is never valid anyway since it maps to sim_ent_nil()) */
{
PushStruct(ss->ents_arena, Entity);
++ss->num_ents_allocated;
++ss->num_ents_reserved;
}
/* PushStruct root ent with constant id */
/* Push root ent with constant id */
{
Entity *root = PushStructNoZero(ss->ents_arena, Entity);
*root = *sim_ent_nil();

View File

@ -1,17 +1,16 @@
////////////////////////////////
//~ Load job
JobDef(SND_LoadAssetJob, job)
JobDef(SND_LoadJob, sig, UNUSED id)
{
__prof;
SND_LoadAssetJobSig *params = job.sig;
TempArena scratch = BeginScratchNoConflict();
String path = STRING(params->path_len, (u8 *)params->path_cstr);
AC_Asset *asset = params->asset;
SND_SoundFlag flags = params->flags;
String path = sig->path;
AC_Asset *asset = sig->asset;
SND_SoundFlag flags = sig->flags;
P_LogInfoF("Loading sound \"%F\"", FmtString(path));
i64 start_ns = P_TimeNs();
i64 start_ns = TimeNs();
String error_msg = Lit("Unknown error");
@ -61,7 +60,7 @@ JobDef(SND_LoadAssetJob, job)
sound->samples = samples;
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)));
P_LogSuccessF("Loaded sound \"%F\" in %F seconds", FmtString(path), FmtFloat(SecondsFromNs(TimeNs() - start_ns)));
AC_MarkReady(asset, sound);
}
else
@ -101,22 +100,12 @@ AC_Asset *SND_LoadAsset(String path, SND_SoundFlag flags, b32 wait)
if (is_first_touch)
{
/* Assemble task params */
SND_LoadAssetJobSig *params = SND_AllocJobSig();
if (path.len > (sizeof(params->path_cstr) - 1))
{
P_Panic(StringFormat(scratch.arena,
Lit("Sound path \"%F\" too long!"),
FmtString(path)));
}
CstrBuffFromStringToBuff(StringFromArray(params->path_cstr), path);
params->path_len = path.len;
params->asset = asset;
params->flags = flags;
/* PushStruct task */
AC_MarkLoading(asset);
P_Run(1, SND_LoadAssetJob, params, PoolKind_Background, PriorityKind_Low, &asset->counter);
SND_LoadJob_Desc *desc = PushJobDesc(SND_LoadJob, .pool = PoolKind_Background, .priority = PriorityKind_Low, .counter = &asset->counter);
desc->sig->path = PushString(desc->arena, path);
desc->sig->asset = asset;
desc->sig->flags = flags;
RunJobEx((GenericJobDesc *)desc);
if (wait)
{
AC_WaitOnAssetReady(asset);

View File

@ -19,7 +19,7 @@ Struct(SND_Sound)
////////////////////////////////
//~ Sound load operations
JobDecl(SND_LoadAssetJob, { SND_SoundFlag flags; AC_Asset *asset; String path; });
JobDecl(SND_LoadJob, { SND_SoundFlag flags; AC_Asset *asset; String path; });
AC_Asset *SND_LoadAsset(String path, SND_SoundFlag flags, b32 wait);
SND_Sound *SND_LoadSoundAsync(String path, SND_SoundFlag flags);
SND_Sound *SND_LoadSoundWait(String path, SND_SoundFlag flags);

View File

@ -40,11 +40,9 @@ S_StartupReceipt S_Startup(void)
g->cache.arena = AllocArena(Gibi(64));
g->cache.bins = PushStructs(g->cache.arena, S_CacheEntryBin, S_CacheBinsCount);
g->cmds_arena = AllocArena(Gibi(64));
g->scopes_arena = AllocArena(Gibi(64));
P_Run(1, S_EvictorJob, 0, PoolKind_Background, PriorityKind_Low, &g->shutdown_counter);
RunJob(1, S_EvictorJob, 0, PoolKind_Background, PriorityKind_Low, &g->shutdown_counter);
P_OnExit(&S_Shutdown);
#if RESOURCE_RELOADING
@ -63,13 +61,13 @@ P_ExitFuncDef(S_Shutdown)
S_SharedState *g = &S_shared_state;
/* Signal evictor shutdown */
{
P_Lock lock = P_LockE(&g->evictor_scheduler_mutex);
Lock lock = LockE(&g->evictor_scheduler_mutex);
g->evictor_scheduler_shutdown = 1;
P_SignalCv(&g->evictor_scheduler_shutdown_cv, I32Max);
P_Unlock(&lock);
SignalCv(&g->evictor_scheduler_shutdown_cv, I32Max);
Unlock(&lock);
}
/* Wait for evictor shutdown */
P_WaitOnCounter(&g->shutdown_counter);
WaitOnCounter(&g->shutdown_counter);
}
////////////////////////////////
@ -421,69 +419,35 @@ S_Sheet S_SheetFromAseResult(Arena *arena, ASE_DecodedSheet ase)
////////////////////////////////
//~ Load job
//- Job def
JobDef(S_LoadSpriteJob, job)
JobDef(S_LoadSpriteJob, sig, UNUSED id)
{
__prof;
S_SharedState *g = &S_shared_state;
S_Cmd *cmd = job.sig;
S_CacheEntryRef ref = cmd->ref;
S_CacheEntryRef ref = sig->ref;
S_Tag tag = sig->tag;
S_Scope *scope = sig->scope;
switch (ref.e->kind)
{
case S_CacheEntryKind_Texture:
{
S_LoadCacheEntryTexture(ref, cmd->tag);
S_LoadCacheEntryTexture(ref, tag);
} break;
case S_CacheEntryKind_Sheet:
{
S_LoadCacheEntrySheet(ref, cmd->tag);
S_LoadCacheEntrySheet(ref, tag);
} break;
default: { P_Panic(Lit("Unknown sprite cache node kind")); } break;
}
/* Free cmd */
P_Lock lock = P_LockE(&g->cmds_mutex);
{
S_EndScope(cmd->scope);
cmd->next_free = g->first_free_cmd;
g->first_free_cmd = cmd;
}
P_Unlock(&lock);
S_EndScope(scope);
}
//- Push
void S_PushLoadJob(S_CacheEntryRef ref, S_Tag tag)
{
S_SharedState *g = &S_shared_state;
S_Cmd *cmd = 0;
{
P_Lock lock = P_LockE(&g->cmds_mutex);
if (g->first_free_cmd)
{
cmd = g->first_free_cmd;
g->first_free_cmd = cmd->next_free;
}
else
{
cmd = PushStructNoZero(g->cmds_arena, S_Cmd);
}
P_Unlock(&lock);
}
ZeroStruct(cmd);
/* Initialize cmd */
cmd->scope = S_BeginScope();
cmd->ref = S_EnsureRefFromRef(cmd->scope, ref)->ref;
cmd->tag = tag;
{
u64 copy_len = MinU64(tag.path.len, countof(cmd->tag_path_buff));
cmd->tag.path.text = cmd->tag_path_buff;
CopyBytes(cmd->tag.path.text, tag.path.text, copy_len);
}
/* PushStruct work */
P_Run(1, S_LoadSpriteJob, cmd, PoolKind_Background, PriorityKind_Inherit, 0);
S_LoadSpriteJob_Desc *desc = PushJobDesc(S_LoadSpriteJob, .pool = PoolKind_Background, .priority = PriorityKind_Inherit);
desc->sig->scope = S_BeginScope(); /* Scope ended by job */
desc->sig->ref = S_EnsureRefFromRef(desc->sig->scope, ref)->ref;
desc->sig->tag = tag;
tag.path = PushString(desc->arena, tag.path);
RunJobEx((GenericJobDesc *)desc);
}
////////////////////////////////
@ -501,7 +465,7 @@ void S_LoadCacheEntryTexture(S_CacheEntryRef ref, S_Tag tag)
P_LogInfoF("Loading sprite texture [%F] \"%F\"", FmtHex(e->hash.v), FmtString(path));
b32 success = 0;
i64 start_ns = P_TimeNs();
i64 start_ns = TimeNs();
Assert(StringEndsWith(path, Lit(".ase")));
Assert(e->kind == S_CacheEntryKind_Texture);
@ -549,7 +513,7 @@ void S_LoadCacheEntryTexture(S_CacheEntryRef ref, S_Tag tag)
P_LogSuccessF("Loaded sprite texture [%F] \"%F\" in %F seconds (cache size: %F bytes).",
FmtHex(e->hash.v),
FmtString(path),
FmtFloat(SecondsFromNs(P_TimeNs() - start_ns)),
FmtFloat(SecondsFromNs(TimeNs() - start_ns)),
FmtUint(e->memory_usage));
}
@ -557,7 +521,7 @@ void S_LoadCacheEntryTexture(S_CacheEntryRef ref, S_Tag tag)
#if RESOURCE_RELOADING
S_CacheEntryBin *bin = &g->cache.bins[e->hash.v % S_CacheBinsCount];
P_Lock bin_lock = P_LockE(&bin->mutex);
Lock bin_lock = LockE(&bin->mutex);
{
for (S_CacheEntry *old_entry = bin->first; old_entry; old_entry = old_entry->next_in_bin)
{
@ -566,9 +530,9 @@ void S_LoadCacheEntryTexture(S_CacheEntryRef ref, S_Tag tag)
Atomic32FetchSet(&old_entry->out_of_date, 1);
}
}
e->load_time_ns = P_TimeNs();
e->load_time_ns = TimeNs();
}
P_Unlock(&bin_lock);
Unlock(&bin_lock);
#endif
EndScratch(scratch);
@ -586,7 +550,7 @@ void S_LoadCacheEntrySheet(S_CacheEntryRef ref, S_Tag tag)
P_LogInfoF("Loading sprite sheet [%F] \"%F\"", FmtHex(e->hash.v), FmtString(path));
b32 success = 0;
i64 start_ns = P_TimeNs();
i64 start_ns = TimeNs();
Assert(e->kind == S_CacheEntryKind_Sheet);
@ -632,7 +596,7 @@ void S_LoadCacheEntrySheet(S_CacheEntryRef ref, S_Tag tag)
P_LogSuccessF("Loaded sprite sheet [%F] \"%F\" in %F seconds (cache size: %F bytes).",
FmtHex(e->hash.v),
FmtString(path),
FmtFloat(SecondsFromNs(P_TimeNs() - start_ns)),
FmtFloat(SecondsFromNs(TimeNs() - start_ns)),
FmtUint(e->memory_usage));
}
@ -640,7 +604,7 @@ void S_LoadCacheEntrySheet(S_CacheEntryRef ref, S_Tag tag)
#if RESOURCE_RELOADING
S_CacheEntryBin *bin = &g->cache.bins[e->hash.v % S_CacheBinsCount];
P_Lock bin_lock = P_LockE(&bin->mutex);
Lock bin_lock = LockE(&bin->mutex);
{
for (S_CacheEntry *old_entry = bin->first; old_entry; old_entry = old_entry->next_in_bin)
{
@ -649,9 +613,9 @@ void S_LoadCacheEntrySheet(S_CacheEntryRef ref, S_Tag tag)
Atomic32FetchSet(&old_entry->out_of_date, 1);
}
}
e->load_time_ns = P_TimeNs();
e->load_time_ns = TimeNs();
}
P_Unlock(&bin_lock);
Unlock(&bin_lock);
#endif
EndScratch(scratch);
@ -720,11 +684,11 @@ S_ScopeCacheEntryRef *S_EnsureRefUnsafely(S_Scope *scope, S_CacheEntry *e)
return *slot;
}
S_ScopeCacheEntryRef *S_EnsureRefFromEntryLocked(S_Scope *scope, S_CacheEntry *e, P_Lock *bin_lock)
S_ScopeCacheEntryRef *S_EnsureRefFromEntryLocked(S_Scope *scope, S_CacheEntry *e, Lock *bin_lock)
{
S_SharedState *g = &S_shared_state;
/* Guaranteed safe if caller has lock on entry's bin, since entry may not have an existing reference and could otherwise be evicted while ensuring this reference */
P_AssertLockedES(bin_lock, &g->cache.bins[e->hash.v % S_CacheBinsCount].mutex);
AssertLockedES(bin_lock, &g->cache.bins[e->hash.v % S_CacheBinsCount].mutex);
return S_EnsureRefUnsafely(scope, e);
}
@ -745,7 +709,7 @@ S_Scope *S_BeginScope(void)
S_ScopeCacheEntryRef **bins = 0;
S_ScopeCacheEntryRef *pool = 0;
{
P_Lock lock = P_LockE(&g->scopes_mutex);
Lock lock = LockE(&g->scopes_mutex);
{
if (g->first_free_scope)
{
@ -761,7 +725,7 @@ S_Scope *S_BeginScope(void)
pool = PushStructsNoZero(g->scopes_arena, S_ScopeCacheEntryRef, S_MaxScopeReferences);
}
}
P_Unlock(&lock);
Unlock(&lock);
}
ZeroStruct(result);
ZeroBytes(bins, sizeof(*bins) * S_CacheBinsCount);
@ -782,12 +746,12 @@ void S_EndScope(S_Scope *scope)
}
/* Release scope */
P_Lock lock = P_LockE(&g->scopes_mutex);
Lock lock = LockE(&g->scopes_mutex);
{
scope->next_free = g->first_free_scope;
g->first_free_scope = scope;
}
P_Unlock(&lock);
Unlock(&lock);
}
////////////////////////////////
@ -795,13 +759,13 @@ void S_EndScope(S_Scope *scope)
//- Locked lookup
S_ScopeCacheEntryRef *S_EntryFromHashLocked(S_Scope *scope, S_Hash hash, P_Lock *bin_lock)
S_ScopeCacheEntryRef *S_EntryFromHashLocked(S_Scope *scope, S_Hash hash, Lock *bin_lock)
{
S_SharedState *g = &S_shared_state;
S_ScopeCacheEntryRef *scope_ref = 0;
S_CacheEntryBin *bin = &g->cache.bins[hash.v % S_CacheBinsCount];
P_AssertLockedES(bin_lock, &bin->mutex); /* Lock required for iterating bin */
AssertLockedES(bin_lock, &bin->mutex); /* Lock required for iterating bin */
#if RESOURCE_RELOADING
/* If resource reloading is enabled, then we want to find the
@ -870,17 +834,17 @@ S_ScopeCacheEntryRef *S_EntryFromTag(S_Scope *scope, S_Tag tag, S_CacheEntryKind
/* Search in cache */
if (!force_new)
{
P_Lock bin_lock = P_LockS(&bin->mutex);
Lock bin_lock = LockS(&bin->mutex);
{
scope_ref = S_EntryFromHashLocked(scope, hash, &bin_lock);
}
P_Unlock(&bin_lock);
Unlock(&bin_lock);
}
/* If not in cache, allocate new entry */
if (!scope_ref)
{
P_Lock bin_lock = P_LockE(&bin->mutex);
Lock bin_lock = LockE(&bin->mutex);
{
/* Search cache one more time in case an entry was allocated between locks */
if (!force_new)
@ -893,7 +857,7 @@ S_ScopeCacheEntryRef *S_EntryFromTag(S_Scope *scope, S_Tag tag, S_CacheEntryKind
/* Cache entry still absent, allocate new entry */
S_CacheEntry *entry = 0;
{
P_Lock pool_lock = P_LockE(&g->cache.entry_pool_mutex);
Lock pool_lock = LockE(&g->cache.entry_pool_mutex);
if (g->cache.entry_pool_first_free)
{
entry = g->cache.entry_pool_first_free;
@ -903,7 +867,7 @@ S_ScopeCacheEntryRef *S_EntryFromTag(S_Scope *scope, S_Tag tag, S_CacheEntryKind
{
entry = PushStructNoZero(g->cache.arena, S_CacheEntry);
}
P_Unlock(&pool_lock);
Unlock(&pool_lock);
}
ZeroStruct(entry);
@ -928,7 +892,7 @@ S_ScopeCacheEntryRef *S_EntryFromTag(S_Scope *scope, S_Tag tag, S_CacheEntryKind
scope_ref = S_EnsureRefFromEntryLocked(scope, entry, &bin_lock);
}
}
P_Unlock(&bin_lock);
Unlock(&bin_lock);
}
}
@ -1132,11 +1096,11 @@ void S_ReloadSpriteFromTag(S_Scope *scope, S_Tag tag, S_CacheEntryKind kind)
S_Hash hash = S_CacheEntryFromTagHash(tag.hash, kind);
S_CacheEntryBin *bin = &g->cache.bins[hash.v % S_CacheBinsCount];
S_ScopeCacheEntryRef *existing_ref = 0;
P_Lock bin_lock = P_LockS(&bin->mutex);
Lock bin_lock = LockS(&bin->mutex);
{
existing_ref = S_EntryFromHashLocked(scope, hash, &bin_lock);
}
P_Unlock(&bin_lock);
Unlock(&bin_lock);
if (existing_ref)
{
@ -1189,7 +1153,7 @@ MergesortCompareFuncDef(S_EvictorSortCmp, arg_a, arg_b, _)
* - The cache is over its memory budget and the node's last reference is longer ago than the grace period
* - Resource reloading is enabled and the node is out of date due to a change to its original resource file
*/
JobDef(S_EvictorJob, _)
JobDef(S_EvictorJob, UNUSED sig, UNUSED job_id)
{
S_SharedState *g = &S_shared_state;
b32 shutdown = 0;
@ -1211,7 +1175,7 @@ JobDef(S_EvictorJob, _)
for (u64 i = 0; i < S_CacheBinsCount; ++i)
{
S_CacheEntryBin *bin = &g->cache.bins[i];
P_Lock bin_lock = P_LockS(&bin->mutex);
Lock bin_lock = LockS(&bin->mutex);
{
S_CacheEntry *n = bin->first;
while (n)
@ -1244,7 +1208,7 @@ JobDef(S_EvictorJob, _)
n = n->next_in_bin;
}
}
P_Unlock(&bin_lock);
Unlock(&bin_lock);
}
}
@ -1269,7 +1233,7 @@ JobDef(S_EvictorJob, _)
S_CacheEntry *entry = en->cache_entry;
i32 last_ref_cycle = en->last_ref_cycle;
b32 cache_over_budget_target = Atomic64Fetch(&g->cache.memory_usage.v) > (i64)S_CacheMemoryBudgetTarget;
P_Lock bin_lock = P_LockE(&bin->mutex);
Lock bin_lock = LockE(&bin->mutex);
{
u64 refcount_uncast = Atomic64Fetch(&entry->refcount_struct.v);
S_Refcount refcount = *(S_Refcount *)&refcount_uncast;
@ -1311,7 +1275,7 @@ JobDef(S_EvictorJob, _)
stop_evicting = 1;
}
}
P_Unlock(&bin_lock);
Unlock(&bin_lock);
}
}
@ -1334,14 +1298,14 @@ JobDef(S_EvictorJob, _)
/* Add evicted nodes to free list */
{
__profn("Evictor free list append");
P_Lock pool_lock = P_LockE(&g->cache.entry_pool_mutex);
Lock pool_lock = LockE(&g->cache.entry_pool_mutex);
for (S_EvictorNode *en = first_evicted; en; en = en->next_evicted)
{
S_CacheEntry *n = en->cache_entry;
n->next_free = g->cache.entry_pool_first_free;
g->cache.entry_pool_first_free = n;
}
P_Unlock(&pool_lock);
Unlock(&pool_lock);
}
}
}
@ -1351,15 +1315,15 @@ JobDef(S_EvictorJob, _)
/* Evictor sleep */
{
P_Lock lock = P_LockE(&g->evictor_scheduler_mutex);
Lock lock = LockE(&g->evictor_scheduler_mutex);
{
if (!g->evictor_scheduler_shutdown)
{
P_WaitOnCvTime(&g->evictor_scheduler_shutdown_cv, &lock, S_EvictorCycleIntervalNs);
WaitOnCvTime(&g->evictor_scheduler_shutdown_cv, &lock, S_EvictorCycleIntervalNs);
}
shutdown = g->evictor_scheduler_shutdown;
}
P_Unlock(&lock);
Unlock(&lock);
}
}
}

View File

@ -150,7 +150,7 @@ Struct(S_CacheEntry)
Struct(S_CacheEntryBin)
{
P_Mutex mutex;
Mutex mutex;
S_CacheEntry *first;
S_CacheEntry *last;
};
@ -160,7 +160,7 @@ Struct(S_Cache)
Atomic64Padded memory_usage;
Arena *arena;
S_CacheEntryBin *bins;
P_Mutex entry_pool_mutex;
Mutex entry_pool_mutex;
S_CacheEntry *entry_pool_first_free;
};
@ -238,7 +238,7 @@ Struct(S_SharedState)
S_Cache cache;
/* Scopes */
P_Mutex scopes_mutex;
Mutex scopes_mutex;
Arena *scopes_arena;
S_Scope *first_free_scope;
@ -246,8 +246,8 @@ Struct(S_SharedState)
Atomic32Padded evictor_cycle;
Counter shutdown_counter;
b32 evictor_scheduler_shutdown;
P_Mutex evictor_scheduler_mutex;
P_Cv evictor_scheduler_shutdown_cv;
Mutex evictor_scheduler_mutex;
Cv evictor_scheduler_shutdown_cv;
};
extern S_SharedState S_shared_state;
@ -298,7 +298,7 @@ void S_LoadCacheEntrySheet(S_CacheEntryRef ref, S_Tag tag);
void S_AddRef(S_CacheEntry *e, i32 amount);
S_ScopeCacheEntryRef *S_EnsureRefUnsafely(S_Scope *scope, S_CacheEntry *e);
S_ScopeCacheEntryRef *S_EnsureRefFromEntryLocked(S_Scope *scope, S_CacheEntry *e, P_Lock *bin_lock);
S_ScopeCacheEntryRef *S_EnsureRefFromEntryLocked(S_Scope *scope, S_CacheEntry *e, Lock *bin_lock);
S_ScopeCacheEntryRef *S_EnsureRefFromRef(S_Scope *scope, S_CacheEntryRef ref);
////////////////////////////////
@ -310,7 +310,7 @@ void S_EndScope(S_Scope *scope);
////////////////////////////////
//~ Cache lookup operations
S_ScopeCacheEntryRef *S_EntryFromHashLocked(S_Scope *scope, S_Hash hash, P_Lock *bin_lock);
S_ScopeCacheEntryRef *S_EntryFromHashLocked(S_Scope *scope, S_Hash hash, Lock *bin_lock);
S_ScopeCacheEntryRef *S_EntryFromTag(S_Scope *scope, S_Tag tag, S_CacheEntryKind kind, b32 force_new);
void *S_DataFromTag(S_Scope *scope, S_Tag tag, S_CacheEntryKind kind, b32 await);

View File

@ -10,8 +10,8 @@ void W_Startup(void)
g->watch_events_arena = AllocArena(Gibi(64));
P_Run(1, W_MonitorJob, 0, PoolKind_Floating, PriorityKind_Low, &g->watch_jobs_counter);
P_Run(1, W_DispatcherJob, 0, PoolKind_Background, PriorityKind_Low, &g->watch_jobs_counter);
RunJob(1, W_MonitorJob, 0, PoolKind_Floating, PriorityKind_Low, &g->watch_jobs_counter);
RunJob(1, W_DispatcherJob, 0, PoolKind_Background, PriorityKind_Low, &g->watch_jobs_counter);
P_OnExit(&W_Shutdown);
}
@ -21,12 +21,12 @@ P_ExitFuncDef(W_Shutdown)
W_SharedState *g = &W_shared_state;
Atomic32FetchSet(&g->W_Shutdown, 1);
{
P_Lock lock = P_LockE(&g->watch_dispatcher_mutex);
P_SignalCv(&g->watch_dispatcher_cv, I32Max);
Lock lock = LockE(&g->watch_dispatcher_mutex);
SignalCv(&g->watch_dispatcher_cv, I32Max);
P_WakeWatch(g->watch);
P_Unlock(&lock);
Unlock(&lock);
}
P_WaitOnCounter(&g->watch_jobs_counter);
WaitOnCounter(&g->watch_jobs_counter);
}
////////////////////////////////
@ -35,7 +35,7 @@ P_ExitFuncDef(W_Shutdown)
void W_RegisterCallback(W_CallbackFunc *callback)
{
W_SharedState *g = &W_shared_state;
P_Lock lock = P_LockE(&g->watch_callbacks_mutex);
Lock lock = LockE(&g->watch_callbacks_mutex);
{
if (g->num_watch_callbacks < countof(g->watch_callbacks))
{
@ -46,15 +46,14 @@ void W_RegisterCallback(W_CallbackFunc *callback)
P_Panic(Lit("Max resource watch callbacks reached"));
}
}
P_Unlock(&lock);
Unlock(&lock);
}
JobDef(W_RunCallbackJob, job)
JobDef(W_RunCallbacksJob , sig, id)
{
__prof;
W_RunCallbackJobSig *sig = job.sig;
String name = sig->name;
W_CallbackFunc *callback = sig->callbacks[job.id];
W_CallbackFunc *callback = sig->callbacks[id];
callback(name);
}
@ -65,7 +64,7 @@ JobDef(W_RunCallbackJob, job)
* & dispatching watch callbacks into two separate jobs so that we can delay
* the dispatch, allowing for deduplication of file modification notifications. */
JobDef(W_MonitorJob, _)
JobDef(W_MonitorJob, UNUSED sig, UNUSED job_id)
{
TempArena scratch = BeginScratchNoConflict();
W_SharedState *g = &W_shared_state;
@ -81,7 +80,7 @@ JobDef(W_MonitorJob, _)
P_WatchInfoList info_list = P_ReadWatchWait(temp.arena, g->watch);
if (info_list.first && !Atomic32Fetch(&g->W_Shutdown))
{
P_Lock lock = P_LockE(&g->watch_dispatcher_mutex);
Lock lock = LockE(&g->watch_dispatcher_mutex);
{
for (P_WatchInfo *info = info_list.first; info; info = info->next)
{
@ -111,8 +110,8 @@ JobDef(W_MonitorJob, _)
}
}
}
P_SignalCv(&g->watch_dispatcher_cv, I32Max);
P_Unlock(&lock);
SignalCv(&g->watch_dispatcher_cv, I32Max);
Unlock(&lock);
}
EndTempArena(temp);
}
@ -123,7 +122,7 @@ JobDef(W_MonitorJob, _)
////////////////////////////////
//~ Dispatcher job
JobDef(W_DispatcherJob, _)
JobDef(W_DispatcherJob, UNUSED sig, UNUSED job_id)
{
W_SharedState *g = &W_shared_state;
@ -138,12 +137,12 @@ JobDef(W_DispatcherJob, _)
/* Delay so that duplicate events pile up */
{
__profn("Delay");
P_Wait(0, 0, 0, NsFromSeconds(W_DispatcherDelaySeconds));
FutexWait(0, 0, 0, NsFromSeconds(W_DispatcherDelaySeconds));
}
/* Pull watch events from queue */
{
P_Lock lock = P_LockE(&g->watch_dispatcher_mutex);
Lock lock = LockE(&g->watch_dispatcher_mutex);
for (W_Event *src_event = g->first_watch_event; src_event; src_event = src_event->next)
{
W_Event *e = PushStruct(scratch.arena, W_Event);
@ -161,13 +160,13 @@ JobDef(W_DispatcherJob, _)
g->first_watch_event = 0;
g->last_watch_event = 0;
ResetArena(g->watch_events_arena);
P_Unlock(&lock);
Unlock(&lock);
}
/* Build callbacks array */
u64 num_callbacks = 0;
W_CallbackFunc **callbacks = 0;
P_Lock callbacks_lock = P_LockS(&g->watch_callbacks_mutex);
Lock callbacks_lock = LockS(&g->watch_callbacks_mutex);
{
num_callbacks = g->num_watch_callbacks;
callbacks = PushStructsNoZero(scratch.arena, W_CallbackFunc *, num_callbacks);
@ -176,7 +175,7 @@ JobDef(W_DispatcherJob, _)
callbacks[i] = g->watch_callbacks[i];
}
}
P_Unlock(&callbacks_lock);
Unlock(&callbacks_lock);
/* Run callbacks */
{
@ -197,12 +196,9 @@ JobDef(W_DispatcherJob, _)
}
if (!skip)
{
W_RunCallbackJobSig sig = ZI;
sig.name = e->name;
sig.callbacks = callbacks;
Counter counter = ZI;
P_Run(num_callbacks, W_RunCallbackJob, &sig, PoolKind_Background, PriorityKind_Low, &counter);
P_WaitOnCounter(&counter);
RunJob(num_callbacks, W_RunCallbacksJob, PoolKind_Background, PriorityKind_Low, &counter, .name = e->name, .callbacks = callbacks);
WaitOnCounter(&counter);
}
}
}
@ -211,15 +207,15 @@ JobDef(W_DispatcherJob, _)
}
/* Wait for event */
P_Lock lock = P_LockS(&g->watch_dispatcher_mutex);
Lock lock = LockS(&g->watch_dispatcher_mutex);
{
shutdown = Atomic32Fetch(&g->W_Shutdown);
while (!shutdown && !g->first_watch_event)
{
P_WaitOnCv(&g->watch_dispatcher_cv, &lock);
WaitOnCv(&g->watch_dispatcher_cv, &lock);
shutdown = Atomic32Fetch(&g->W_Shutdown);
}
}
P_Unlock(&lock);
Unlock(&lock);
}
}

View File

@ -4,12 +4,6 @@
#define W_CallbackFuncDef(func_name, arg_name) void func_name(String arg_name)
typedef W_CallbackFuncDef(W_CallbackFunc, name);
Struct(W_RunCallbackJobSig)
{
String name;
W_CallbackFunc **callbacks;
};
////////////////////////////////
//~ Event types
@ -31,13 +25,13 @@ Struct(W_SharedState)
Atomic32 W_Shutdown;
Counter watch_jobs_counter;
P_Mutex watch_dispatcher_mutex;
Mutex watch_dispatcher_mutex;
Arena *watch_events_arena;
W_Event *first_watch_event;
W_Event *last_watch_event;
P_Cv watch_dispatcher_cv;
Cv watch_dispatcher_cv;
P_Mutex watch_callbacks_mutex;
Mutex watch_callbacks_mutex;
W_CallbackFunc *watch_callbacks[64];
u64 num_watch_callbacks;
};
@ -58,7 +52,7 @@ void W_RegisterCallback(W_CallbackFunc *callback);
////////////////////////////////
//~ Callback job
JobDecl(W_RunCallbackJob, EmptySig);
JobDecl(W_RunCallbacksJob, { String name; W_CallbackFunc **callbacks; });
////////////////////////////////
//~ Long running jobs