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

View File

@ -34,7 +34,7 @@ Struct(AC_Store)
Arena *arena; Arena *arena;
/* internal */ /* internal */
P_Lock lock; Lock lock;
}; };
//////////////////////////////// ////////////////////////////////
@ -45,18 +45,18 @@ Struct(AC_Store)
Struct(AC_SharedState) Struct(AC_SharedState)
{ {
P_Mutex lookup_mutex; Mutex lookup_mutex;
AC_Asset lookup[AC_AssetLookupTableCapacity]; AC_Asset lookup[AC_AssetLookupTableCapacity];
u64 num_assets; u64 num_assets;
P_Mutex store_mutex; Mutex store_mutex;
Arena *store_arena; Arena *store_arena;
#if RtcIsEnabled #if RtcIsEnabled
/* Array of len `num_assets` pointing into populated entries of `lookup`. */ /* Array of len `num_assets` pointing into populated entries of `lookup`. */
AC_Asset *dbg_table[AC_AssetLookupTableCapacity]; AC_Asset *dbg_table[AC_AssetLookupTableCapacity];
u64 dbg_table_count; u64 dbg_table_count;
P_Mutex dbg_table_mutex; Mutex dbg_table_mutex;
#endif #endif
}; };
@ -77,7 +77,7 @@ u64 AC_HashFromKey(String key);
//~ Cache operations //~ Cache operations
void AC_RefreshDebugTable(void); 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); AC_Asset *AC_TouchCache(String key, u64 hash, b32 *is_first_touch);
//////////////////////////////// ////////////////////////////////

View File

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

View File

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

View File

@ -548,6 +548,23 @@ ForceInline void UnlockTicketMutex(TicketMutex *tm)
} }
#endif #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 //~ Config

View File

@ -33,30 +33,59 @@ typedef i32 PriorityKind; enum
}; };
//////////////////////////////// ////////////////////////////////
//~ @hookdecl Fiber helpers //~ @hookdecl Futex
#define MaxFibers 4096 /* Futex-like wait & wake */
void FutexWait(volatile void *addr, void *cmp, u32 size, i64 timeout_ns);
i16 FiberId(void); void FutexWake(void *addr, i32 count);
StaticAssert(MaxFibers < I16Max); /* Fiber id type should fit max fibers */
//////////////////////////////// ////////////////////////////////
//~ @hookdecl Job helpers //~ @hookdecl Job helpers
#define EmptySig { i32 _; } #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) \ #define JobDecl(job, sigdef) \
typedef struct job##_Sig sigdef job##_Sig; \ typedef struct job##_Sig sigdef job##_Sig; \
Struct(job##_Desc) { Counter *counter; Arena *job_arena; job##_Sig *sig; }; \ Struct(job##_Desc) { Arena *arena; job##_Sig *sig; GenericJobFunc *func; i32 count; PoolKind pool; PriorityKind priority; Counter *counter;}; \
void job(job##_Sig *) 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 */ i64 TimeNs(void);
void P_Wait(volatile void *addr, void *cmp, u32 size, i64 timeout_ns);
void P_Wake(void *addr, i32 count); u32 GetLogicalProcessorCount(void);
u32 ThreadId(void);
i64 GetCurrentSchedulerPeriodNs(void);

View File

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

View File

@ -2,7 +2,7 @@
//~ Mutex //~ Mutex
//- Exclusive mutex lock //- Exclusive mutex lock
P_Lock P_LockSpinE(P_Mutex *m, i32 spin) Lock LockSpinE(Mutex *m, i32 spin)
{ {
b32 locked = 0; b32 locked = 0;
i32 spin_cnt = 0; i32 spin_cnt = 0;
@ -49,7 +49,7 @@ P_Lock P_LockSpinE(P_Mutex *m, i32 spin)
} }
else else
{ {
P_Wait(&m->v, &v, 4, I64Max); FutexWait(&m->v, &v, 4, I64Max);
spin_cnt = 0; spin_cnt = 0;
} }
} }
@ -59,14 +59,14 @@ P_Lock P_LockSpinE(P_Mutex *m, i32 spin)
Atomic32FetchSet(&m->exclusive_fiber_id, FiberId()); Atomic32FetchSet(&m->exclusive_fiber_id, FiberId());
#endif #endif
P_Lock lock = ZI; Lock lock = ZI;
lock.exclusive = 1; lock.exclusive = 1;
lock.mutex = m; lock.mutex = m;
return lock; return lock;
} }
//- Shared mutex lock //- Shared mutex lock
P_Lock P_LockSpinS(P_Mutex *m, i32 spin) Lock LockSpinS(Mutex *m, i32 spin)
{ {
b32 locked = 0; b32 locked = 0;
i32 spin_cnt = 0; i32 spin_cnt = 0;
@ -96,30 +96,30 @@ P_Lock P_LockSpinS(P_Mutex *m, i32 spin)
} }
else else
{ {
P_Wait(&m->v, &v, 4, I64Max); FutexWait(&m->v, &v, 4, I64Max);
spin_cnt = 0; spin_cnt = 0;
} }
} }
} }
P_Lock lock = ZI; Lock lock = ZI;
lock.mutex = m; lock.mutex = m;
return lock; return lock;
} }
//- Mutex lock wrappers //- 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 (l->exclusive)
{ {
#if RtcIsEnabled #if RtcIsEnabled
@ -131,64 +131,64 @@ void P_Unlock(P_Lock *l)
{ {
Atomic32FetchAdd(&m->v, -1); Atomic32FetchAdd(&m->v, -1);
} }
P_Wake(&m->v, I32Max); FutexWake(&m->v, I32Max);
ZeroStruct(l); ZeroStruct(l);
} }
//////////////////////////////// ////////////////////////////////
//~ Condition variable //~ 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); u64 old_wake_gen = Atomic64Fetch(&cv->wake_gen);
P_Mutex *mutex = l->mutex; Mutex *mutex = l->mutex;
b32 exclusive = l->exclusive; 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) if (exclusive)
{ {
*l = P_LockE(mutex); *l = LockE(mutex);
} }
else 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); Atomic64FetchAdd(&cv->wake_gen, 1);
P_Wake(&cv->wake_gen, count); FutexWake(&cv->wake_gen, count);
} }
//////////////////////////////// ////////////////////////////////
//~ Counter //~ Counter
void P_CounterAdd(Counter *counter, i64 x) void AddCounter(Counter *counter, i64 x)
{ {
i64 old_v = Atomic64FetchAdd(&counter->v, x); i64 old_v = Atomic64FetchAdd(&counter->v, x);
i64 new_v = old_v + x; i64 new_v = old_v + x;
if (old_v > 0 && new_v <= 0) 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); i64 v = Atomic64Fetch(&counter->v);
while (v > 0) while (v > 0)
{ {
P_Wait(&counter->v, &v, sizeof(v), I64Max); FutexWait(&counter->v, &v, sizeof(v), I64Max);
v = Atomic64Fetch(&counter->v); 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; u8 len = 0;
if (n < 0) if (n < 0)
{ {
/* PushStruct sign */ /* Push sign */
StringFromChar(arena, '-'); StringFromChar(arena, '-');
len = 1; len = 1;
n = -n; n = -n;
} }
/* PushStruct unsigned number */ /* Push unsigned number */
String uint_str = StringFromU64(arena, n, base, zfill); String uint_str = StringFromU64(arena, n, base, zfill);
return (String) return (String)
{ {

View File

@ -1,5 +1,7 @@
W32_SharedCtx W32_shared_ctx = ZI; W32_SharedCtx W32_shared_ctx = ZI;
/* FIXME: Enable logs, panic, shutdown */
//////////////////////////////// ////////////////////////////////
//~ Win32 libs //~ Win32 libs
@ -21,6 +23,19 @@ void StartupJobs(void)
{ {
W32_SharedCtx *g = &W32_shared_ctx; 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 */ /* Init fibers */
g->num_fibers = 1; /* Fiber at index 0 always nil */ g->num_fibers = 1; /* Fiber at index 0 always nil */
g->fiber_names_arena = AllocArena(Gibi(64)); g->fiber_names_arena = AllocArena(Gibi(64));
@ -47,6 +62,7 @@ void StartupJobs(void)
/* Start job scheduler */ /* Start job scheduler */
Atomic64FetchSet(&g->current_scheduler_cycle_period_ns.v, W32_DefaultSchedulerPeriodNs); 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); W32_Thread *scheduler_thread = W32_AllocThread(W32_JobSchedulerEntryFunc, 0, Lit("Scheduler thread"), PROF_THREAD_GROUP_SCHEDULER);
LAX scheduler_thread;
//- Start job workers //- Start job workers
/* TODO: Heuristic worker counts & affinities */ /* TODO: Heuristic worker counts & affinities */
@ -114,12 +130,12 @@ void StartupJobs(void)
} }
} }
P_OnExit(ShutdownJobs); //P_OnExit(ShutdownJobs);
} }
//////////////////////////////// ////////////////////////////////
//~ Shutdown //~ Shutdown
#if 0
void ShutdownJobs(void) void ShutdownJobs(void)
{ {
/* Signal shutdown */ /* Signal shutdown */
@ -162,7 +178,7 @@ void ShutdownJobs(void)
/* Find any dangling threads that haven't exited gracefully by now */ /* Find any dangling threads that haven't exited gracefully by now */
if (!Atomic32Fetch(&g->panicking)) if (!Atomic32Fetch(&g->panicking))
{ {
P_Lock lock = P_LockS(&g->threads_mutex); LockTicketMutex(&g->threads_tm);
if (g->first_thread) if (g->first_thread)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
@ -176,29 +192,13 @@ void ShutdownJobs(void)
++num_dangling_threads; ++num_dangling_threads;
} }
threads_msg = StringFormat(scratch.arena, Lit("%F dangling thread(s):\n%F"), FmtUint(num_dangling_threads), FmtString(threads_msg)); 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); EndScratch(scratch);
} }
P_Unlock(&lock); UnlockTicketMutex(&g->threads_tm);
} }
} }
#endif
////////////////////////////////
//~ 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);
}
//////////////////////////////// ////////////////////////////////
//~ Win32 thread //~ Win32 thread
@ -219,7 +219,7 @@ DWORD WINAPI W32_Win32ThreadProc(LPVOID vt)
SetThreadDescription(GetCurrentThread(), t->thread_name_wstr); 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 */ /* Enter thread entry point */
t->entry_point(t->thread_data); 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(); TempArena scratch = BeginScratchNoConflict();
W32_SharedCtx *g = &W32_shared_ctx; W32_SharedCtx *g = &W32_shared_ctx;
Assert(entry_point != 0); Assert(entry_point != 0);
P_LogInfoF("Creating thread \"%F\"", FmtString(thread_name)); //P_LogInfoF("Creating thread \"%F\"", FmtString(thread_name));
/* Allocate thread object */ /* Allocate thread object */
W32_Thread *t = 0; W32_Thread *t = 0;
{ {
P_Lock lock = P_LockE(&g->threads_mutex); LockTicketMutex(&g->threads_tm);
if (g->first_free_thread) if (g->first_free_thread)
{ {
t = 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->first_thread = t;
} }
g->last_thread = t; g->last_thread = t;
P_Unlock(&lock); UnlockTicketMutex(&g->threads_tm);
} }
t->entry_point = entry_point; t->entry_point = entry_point;
@ -293,7 +293,7 @@ W32_Thread *W32_AllocThread(W32_ThreadFunc *entry_point, void *thread_data, Stri
if (!t->handle) if (!t->handle)
{ {
P_Panic(Lit("Failed to create thread")); //P_Panic(Lit("Failed to create thread"));
} }
EndScratch(scratch); EndScratch(scratch);
@ -319,7 +319,7 @@ b32 W32_TryReleaseThread(W32_Thread *thread, f32 timeout_seconds)
success = 1; success = 1;
CloseHandle(handle); CloseHandle(handle);
{ {
P_Lock lock = P_LockE(&g->threads_mutex); LockTicketMutex(&g->threads_tm);
{ {
W32_Thread *prev = t->prev; W32_Thread *prev = t->prev;
W32_Thread *next = t->next; W32_Thread *next = t->next;
@ -342,7 +342,7 @@ b32 W32_TryReleaseThread(W32_Thread *thread, f32 timeout_seconds)
t->next = g->first_free_thread; t->next = g->first_free_thread;
g->first_free_thread = t; 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) if (pool != 0)
{ {
LockTicketMutex(&pool->free_fibers_lock); LockTicketMutex(&pool->free_fibers_tm);
if (pool->first_free_fiber_id) if (pool->first_free_fiber_id)
{ {
fiber_id = pool->first_free_fiber_id; fiber_id = pool->first_free_fiber_id;
fiber = &g->fibers[fiber_id]; fiber = &g->fibers[fiber_id];
pool->first_free_fiber_id = fiber->parent_id; pool->first_free_fiber_id = fiber->parent_id;
} }
UnlockTicketMutex(&pool->free_fibers_lock); UnlockTicketMutex(&pool->free_fibers_tm);
} }
if (!fiber_id) if (!fiber_id)
{ {
LockTicketMutex(&g->fibers_lock); LockTicketMutex(&g->fibers_tm);
{ {
{ {
fiber_id = g->num_fibers++; fiber_id = g->num_fibers++;
if (fiber_id >= MaxFibers) if (fiber_id >= MaxFibers)
{ {
P_Panic(Lit("Max fibers reached")); //P_Panic(Lit("Max fibers reached"));
} }
fiber = &g->fibers[fiber_id]; fiber = &g->fibers[fiber_id];
new_name_cstr = PushStructs(g->fiber_names_arena, char, W32_FiberNameMaxSize); 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 //- Release fiber
void W32_ReleaseFiber(W32_JobPool *pool, W32_Fiber *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; i16 fiber_id = fiber->id;
fiber->parent_id = pool->first_free_fiber_id; fiber->parent_id = pool->first_free_fiber_id;
pool->first_free_fiber_id = 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 //- Fiber entry
void W32_FiberEntryPoint(void *id_ptr) void W32_FiberEntryPoint(void *id_ptr)
{ {
i16 id = (i32)(i64)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; W32_YieldParam *yield_param = fiber->yield_param;
yield_param->kind = W32_YieldKind_None; yield_param->kind = W32_YieldKind_None;
P_JobData data = ZI;
data.id = fiber->job_id;
data.sig = fiber->job_sig;
{ {
MemoryBarrier(); MemoryBarrier();
fiber->job_func(data); GenericJobFunc *job_func = fiber->job_func;
job_func(fiber->job_sig, fiber->job_id);
MemoryBarrier(); MemoryBarrier();
} }
} }
@ -881,7 +880,7 @@ void W32_FiberEntryPoint(void *id_ptr)
Counter *job_counter = fiber->job_counter; Counter *job_counter = fiber->job_counter;
if (job_counter) if (job_counter)
{ {
P_CounterAdd(job_counter, -1); AddCounter(job_counter, -1);
} }
/* Yield to worker */ /* Yield to worker */
fiber->yield_param->kind = W32_YieldKind_Done; fiber->yield_param->kind = W32_YieldKind_Done;
@ -959,7 +958,7 @@ W32_ThreadDef(W32_JobWorkerEntryFunc, worker_ctx_arg)
PriorityKind job_priority = 0; PriorityKind job_priority = 0;
i16 job_fiber_id = 0; i16 job_fiber_id = 0;
i32 job_id = 0; i32 job_id = 0;
P_JobFunc *job_func = 0; GenericJobFunc *job_func = 0;
void *job_sig = 0; void *job_sig = 0;
Counter *job_counter = 0; Counter *job_counter = 0;
{ {
@ -1064,7 +1063,7 @@ W32_ThreadDef(W32_JobWorkerEntryFunc, worker_ctx_arg)
{ {
/* Invalid yield kind */ /* Invalid yield kind */
TempArena scratch = BeginScratchNoConflict(); 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); EndScratch(scratch);
} break; } break;
@ -1133,11 +1132,11 @@ W32_ThreadDef(W32_JobWorkerEntryFunc, worker_ctx_arg)
} }
else else
{ {
LockTicketMutex(&g->wait_lists_arena_lock); LockTicketMutex(&g->wait_lists_arena_tm);
{ {
wait_addr_list = PushStructNoZero(g->wait_lists_arena, W32_WaitList); 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); ZeroStruct(wait_addr_list);
wait_addr_list->value = (u64)wait_addr; wait_addr_list->value = (u64)wait_addr;
@ -1187,11 +1186,11 @@ W32_ThreadDef(W32_JobWorkerEntryFunc, worker_ctx_arg)
} }
else else
{ {
LockTicketMutex(&g->wait_lists_arena_lock); LockTicketMutex(&g->wait_lists_arena_tm);
{ {
wait_time_list = PushStructNoZero(g->wait_lists_arena, W32_WaitList); 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); ZeroStruct(wait_time_list);
wait_time_list->value = wait_time; 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); HANDLE timer = CreateWaitableTimerExW(0, 0, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS);
if (!timer) 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 */ /* Create rolling buffer of scheduler cycles initialized to default value */
@ -1319,7 +1318,7 @@ W32_ThreadDef(W32_JobSchedulerEntryFunc, UNUSED arg)
} }
/* Calculate mean period */ /* 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; i64 period_ns = last_cycle_ns == 0 ? W32_DefaultSchedulerPeriodNs : now_ns - last_cycle_ns;
last_cycle_ns = now_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()); W32_Fiber *fiber = W32_FiberFromId(FiberId());
i16 parent_id = fiber->parent_id; 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); 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;
} }
//////////////////////////////// #if 1
//~ Job void RunJobEx(GenericJobDesc *desc)
void P_Run(i32 count, P_JobFunc *func, void *sig, PoolKind pool_kind, PriorityKind priority, Counter *counter)
{ {
__prof; __prof;
struct W32_SharedCtx *g = &W32_shared_ctx; 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 (count > 0)
{ {
if (counter) if (counter)
{ {
P_CounterAdd(counter, count); AddCounter(counter, count);
} }
W32_Fiber *fiber = W32_FiberFromId(FiberId()); 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 */ 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 UNICODE
# define WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN
# include <Windows.h> # include <Windows.h>
#if 0
# include <WinSock2.h> # include <WinSock2.h>
# include <TlHelp32.h> # include <TlHelp32.h>
# include <WS2tcpip.h> # include <WS2tcpip.h>
@ -16,7 +15,6 @@
# include <bcrypt.h> # include <bcrypt.h>
# include <avrt.h> # include <avrt.h>
# include <shellapi.h> # include <shellapi.h>
#endif
#pragma warning(pop) #pragma warning(pop)
//////////////////////////////// ////////////////////////////////
@ -123,7 +121,7 @@ AlignedStruct(W32_Fiber, 64)
/* ---------------------------------------------------- */ /* ---------------------------------------------------- */
/* -------------------- Cache line -------------------- */ /* -------------------- Cache line -------------------- */
/* ---------------------------------------------------- */ /* ---------------------------------------------------- */
void *job_func; /* 08 bytes */ GenericJobFunc *job_func; /* 08 bytes */
/* ---------------------------------------------------- */ /* ---------------------------------------------------- */
void *job_sig; /* 08 bytes */ void *job_sig; /* 08 bytes */
/* ---------------------------------------------------- */ /* ---------------------------------------------------- */
@ -158,7 +156,7 @@ Struct(W32_JobInfo)
i32 num_dispatched; i32 num_dispatched;
i32 count; i32 count;
void *func; GenericJobFunc *func;
void *sig; void *sig;
struct Counter *counter; struct Counter *counter;
@ -217,6 +215,8 @@ AlignedStruct(W32_JobPool, 64)
Struct(W32_SharedCtx) Struct(W32_SharedCtx)
{ {
i64 timer_start_qpc;
i64 ns_per_qpc;
Atomic32 shutdown; Atomic32 shutdown;
//- Worker thread pool //- Worker thread pool

View File

@ -1,7 +1,7 @@
//////////////////////////////// ////////////////////////////////
//~ Load job //~ Load job
JobDef(F_LoadAssetJob, job) JobDef(F_LoadJob, sig, _)
{ {
__prof; __prof;
TempArena scratch = BeginScratchNoConflict(); 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 0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
}; };
F_LoadJobSig *params = job.sig; String path = sig->path;
String path = STRING(params->path_len, (u8 *)params->path_cstr); f32 point_size = sig->point_size;
f32 point_size = params->point_size; AC_Asset *asset = sig->asset;
AC_Asset *asset = params->asset;
P_LogInfoF("Loading font \"%F\" (point size %F)", FmtString(path), FmtFloat((f64)point_size)); 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(StringEndsWith(path, Lit(".ttf")));
Assert(countof(font_codes) < F_LookupTableSize); Assert(countof(font_codes) < F_LookupTableSize);
@ -87,7 +86,7 @@ JobDef(F_LoadAssetJob, job)
font->lookup[codepoint] = result.cache_indices[i]; 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); AC_MarkReady(asset, font);
EndScratch(scratch); EndScratch(scratch);
@ -113,22 +112,12 @@ AC_Asset *F_LoadAsset(String path, f32 point_size, b32 wait)
if (is_first_touch) 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); 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) if (wait)
{ {
AC_WaitOnAssetReady(asset); AC_WaitOnAssetReady(asset);

View File

@ -27,7 +27,7 @@ Struct(F_Font)
//////////////////////////////// ////////////////////////////////
//~ Font load job //~ 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 //~ Font load operations

View File

@ -71,7 +71,7 @@ void GPU_Startup(void)
P_OnExit(GPU_D12_Shutdown); P_OnExit(GPU_D12_Shutdown);
/* Start evictor job */ /* 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) P_ExitFuncDef(GPU_D12_Shutdown)
@ -92,12 +92,12 @@ P_ExitFuncDef(GPU_D12_Shutdown)
#endif #endif
{ {
P_Lock lock = P_LockE(&g->evictor_wake_mutex); Lock lock = LockE(&g->evictor_wake_mutex);
g->evictor_shutdown = 1; g->evictor_shutdown = 1;
P_SignalCv(&g->evictor_wake_cv, I32Max); SignalCv(&g->evictor_wake_cv, I32Max);
P_Unlock(&lock); 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_HIGH, .dbg_name = Lit("Copy queue") },
{.type = D3D12_COMMAND_LIST_TYPE_COPY, .priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, .dbg_name = Lit("Background 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; Counter counter = ZI;
P_Run(DX12_NUM_QUEUES, GPU_D12_AllocCommandQueueJob, &sig, PoolKind_Inherit, PriorityKind_Inherit, &counter); RunJob(DX12_NUM_QUEUES, GPU_D12_AllocCommandQueueJob, PoolKind_Inherit, PriorityKind_Low, &counter, .descs_in = params, .cqs_out = g->command_queues);
P_WaitOnCounter(&counter); WaitOnCounter(&counter);
} }
#if ProfilingIsEnabled #if ProfilingIsEnabled
{ {
@ -418,12 +415,9 @@ void GPU_InitPipelines(void)
GPU_D12_Pipeline **pipelines = PushStructs(scratch.arena, GPU_D12_Pipeline *, num_pipelines); GPU_D12_Pipeline **pipelines = PushStructs(scratch.arena, GPU_D12_Pipeline *, num_pipelines);
{ {
__profn("Allocate pipelines"); __profn("Allocate pipelines");
GPU_D12_AllocPipelineJobSig sig = ZI;
sig.descs_in = descs;
sig.pipelines_out = pipelines;
Counter counter = ZI; Counter counter = ZI;
P_Run(num_pipelines, GPU_D12_AllocPipelineJob, &sig, PoolKind_Inherit, PriorityKind_Inherit, &counter); RunJob(num_pipelines, GPU_D12_AllocPipelineJob, PoolKind_Inherit, PriorityKind_Inherit, &counter, .descs_in = descs, .pipelines_out = pipelines);
P_WaitOnCounter(&counter); WaitOnCounter(&counter);
} }
for (u32 i = 0; i < num_pipelines; ++i) for (u32 i = 0; i < num_pipelines; ++i)
{ {
@ -502,11 +496,8 @@ void GPU_D12_InitNoise(void)
/* Upload texture */ /* Upload texture */
{ {
Counter counter = ZI; Counter counter = ZI;
GPU_D12_UploadJobSig sig = ZI; RunJob(1, GPU_D12_UploadJob, PoolKind_Inherit, PriorityKind_Low, &counter, .resource = r, .data = data.text);
sig.resource = r; WaitOnCounter(&counter);
sig.data = data.text;
P_Run(1, GPU_D12_UploadJob, &sig, PoolKind_Inherit, PriorityKind_Inherit, &counter);
P_WaitOnCounter(&counter);
} }
} }
} }
@ -526,17 +517,16 @@ void GPU_D12_InitNoise(void)
#if RESOURCE_RELOADING #if RESOURCE_RELOADING
JobDef(GPU_D12_CompileShaderJob, job) JobDef(GPU_D12_CompileShaderJob, sig, id)
{ {
__prof; __prof;
GPU_D12_CompileShaderJobSig *sig = job.sig;
Arena *arena = sig->arena; Arena *arena = sig->arena;
GPU_D12_ShaderDesc *desc = &sig->descs[job.id]; GPU_D12_ShaderDesc *desc = &sig->descs[id];
GPU_D12_CompiledShaderResult *result = &sig->results[job.id]; GPU_D12_CompiledShaderResult *result = &sig->results[id];
TempArena scratch = BeginScratch(arena); TempArena scratch = BeginScratch(arena);
{ {
i64 start_ns = P_TimeNs(); i64 start_ns = TimeNs();
DXC_Result dxc_result = ZI; DXC_Result dxc_result = ZI;
{ {
__profn("Compile shader"); __profn("Compile shader");
@ -565,7 +555,7 @@ JobDef(GPU_D12_CompileShaderJob, job)
result->success = dxc_result.success; result->success = dxc_result.success;
result->dxc = dxc_result.dxc; result->dxc = dxc_result.dxc;
result->errors = dxc_result.errors; result->errors = dxc_result.errors;
result->elapsed_ns = P_TimeNs() - start_ns; result->elapsed_ns = TimeNs() - start_ns;
} }
EndScratch(scratch); EndScratch(scratch);
@ -577,17 +567,16 @@ JobDef(GPU_D12_CompileShaderJob, job)
* Pipeline * Pipeline
* ========================== */ * ========================== */
JobDef(GPU_D12_AllocPipelineJob, job) JobDef(GPU_D12_AllocPipelineJob, sig, id)
{ {
__prof; __prof;
GPU_D12_SharedState *g = &GPU_D12_shared_state; GPU_D12_SharedState *g = &GPU_D12_shared_state;
GPU_D12_AllocPipelineJobSig *sig = job.sig; GPU_D12_PipelineDesc *desc = &sig->descs_in[id];
GPU_D12_PipelineDesc *desc = &sig->descs_in[job.id];
GPU_D12_Pipeline **pipelines_out = sig->pipelines_out; GPU_D12_Pipeline **pipelines_out = sig->pipelines_out;
GPU_D12_Pipeline *pipeline = 0; GPU_D12_Pipeline *pipeline = 0;
{ {
P_Lock lock = P_LockE(&g->pipelines_mutex); Lock lock = LockE(&g->pipelines_mutex);
if (g->first_free_pipeline) if (g->first_free_pipeline)
{ {
pipeline = 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); pipeline = PushStructNoZero(g->pipelines_arena, GPU_D12_Pipeline);
} }
P_Unlock(&lock); Unlock(&lock);
} }
ZeroStruct(pipeline); ZeroStruct(pipeline);
pipelines_out[job.id] = pipeline; pipelines_out[id] = pipeline;
pipeline->desc = *desc; pipeline->desc = *desc;
pipeline->name = desc->name; pipeline->name = desc->name;
pipeline->hash = HashFnv64(Fnv64Basis, pipeline->name); pipeline->hash = HashFnv64(Fnv64Basis, pipeline->name);
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
{ {
i64 start_ns = P_TimeNs(); i64 start_ns = TimeNs();
String pipeline_name = pipeline->name; String pipeline_name = pipeline->name;
P_LogInfoF("Loading pipeline \"%F\"", FmtString(pipeline_name)); P_LogInfoF("Loading pipeline \"%F\"", FmtString(pipeline_name));
b32 success = 1; b32 success = 1;
@ -880,7 +869,7 @@ JobDef(GPU_D12_AllocPipelineJob, job)
pipeline->pso = pso; pipeline->pso = pso;
pipeline->rootsig = rootsig; pipeline->rootsig = rootsig;
pipeline->compilation_time_ns = P_TimeNs() - start_ns; pipeline->compilation_time_ns = TimeNs() - start_ns;
pipeline->success = success; pipeline->success = success;
pipeline->is_gfx = cs_dxc.len == 0; pipeline->is_gfx = cs_dxc.len == 0;
pipeline->error = error_str; pipeline->error = error_str;
@ -913,12 +902,12 @@ void GPU_D12_ReleasePipelineNow(GPU_D12_Pipeline *pipeline)
{ {
ID3D12PipelineState_Release(pipeline->pso); ID3D12PipelineState_Release(pipeline->pso);
} }
P_Lock lock = P_LockE(&g->pipelines_mutex); Lock lock = LockE(&g->pipelines_mutex);
{ {
pipeline->next = g->first_free_pipeline; pipeline->next = g->first_free_pipeline;
g->first_free_pipeline = 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_SharedState *g = &GPU_D12_shared_state;
GPU_D12_PipelineScope *scope = 0; 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) if (g->first_free_pipeline_scope)
{ {
scope = g->first_free_pipeline_scope; scope = g->first_free_pipeline_scope;
g->first_free_pipeline_scope = scope->next_free; g->first_free_pipeline_scope = scope->next_free;
} }
P_Unlock(&lock); Unlock(&lock);
} }
Arena *arena = 0; Arena *arena = 0;
if (scope) if (scope)
@ -959,7 +948,7 @@ void GPU_D12_EndPipelineScope(GPU_D12_PipelineScope *scope)
{ {
__prof; __prof;
GPU_D12_SharedState *g = &GPU_D12_shared_state; 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) 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; scope->next_free = g->first_free_pipeline_scope;
g->first_free_pipeline_scope = scope; g->first_free_pipeline_scope = scope;
} }
P_Unlock(&lock); Unlock(&lock);
} }
Readonly GPU_D12_Pipeline GPU_D12_nil_pipeline = ZI; 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 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); tmp = (GPU_D12_Pipeline *)DictValueFromHash(g->top_successful_pipelines, hash);
if (tmp) if (tmp)
{ {
++tmp->refcount; ++tmp->refcount;
} }
P_Unlock(&lock); Unlock(&lock);
} }
if (tmp) if (tmp)
{ {
@ -1013,7 +1002,7 @@ void GPU_D12_RegisterPipeline(u64 num_pipelines, GPU_D12_Pipeline **pipelines)
{ {
__prof; __prof;
GPU_D12_SharedState *g = &GPU_D12_shared_state; 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) 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 #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; pipeline_name = split.count > 1 ? split.strings[split.count - 2] : pipeline_name;
} }
{ {
GPU_D12_CompileShaderJobSig sig = ZI; GPU_D12_CompileShaderJob_Desc *job_desc = PushJobDesc(GPU_D12_CompileShaderJob, .count = 0);
sig.arena = scratch.arena; job_desc->sig->arena = scratch.arena;
if (is_rs) if (is_rs)
{ {
num_shaders = 2; num_shaders = 2;
shader_descs = PushStructs(scratch.arena, GPU_D12_ShaderDesc, num_shaders); shader_descs = PushStructs(scratch.arena, GPU_D12_ShaderDesc, num_shaders);
shader_results = PushStructs(scratch.arena, GPU_D12_CompiledShaderResult, num_shaders); shader_results = PushStructs(scratch.arena, GPU_D12_CompiledShaderResult, num_shaders);
sig.descs = shader_descs; job_desc->sig->descs = shader_descs;
sig.results = shader_results; job_desc->sig->results = shader_results;
sig.descs[0].src = data; job_desc->sig->descs[0].src = data;
sig.descs[0].friendly_name = friendly_name; job_desc->sig->descs[0].friendly_name = friendly_name;
sig.descs[0].entry = Lit("vs"); job_desc->sig->descs[0].entry = Lit("vs");
sig.descs[0].target = Lit("vs_6_6"); job_desc->sig->descs[0].target = Lit("vs_6_6");
sig.descs[1].src = data; job_desc->sig->descs[1].src = data;
sig.descs[1].friendly_name = friendly_name; job_desc->sig->descs[1].friendly_name = friendly_name;
sig.descs[1].entry = Lit("ps"); job_desc->sig->descs[1].entry = Lit("ps");
sig.descs[1].target = Lit("ps_6_6"); job_desc->sig->descs[1].target = Lit("ps_6_6");
} }
else if (is_cs) else if (is_cs)
{ {
num_shaders = 1; num_shaders = 1;
shader_descs = PushStructs(scratch.arena, GPU_D12_ShaderDesc, num_shaders); shader_descs = PushStructs(scratch.arena, GPU_D12_ShaderDesc, num_shaders);
shader_results = PushStructs(scratch.arena, GPU_D12_CompiledShaderResult, num_shaders); shader_results = PushStructs(scratch.arena, GPU_D12_CompiledShaderResult, num_shaders);
sig.descs = shader_descs; job_desc->sig->descs = shader_descs;
sig.results = shader_results; job_desc->sig->results = shader_results;
sig.descs[0].src = data; job_desc->sig->descs[0].src = data;
sig.descs[0].friendly_name = friendly_name; job_desc->sig->descs[0].friendly_name = friendly_name;
sig.descs[0].entry = Lit("cs"); job_desc->sig->descs[0].entry = Lit("cs");
sig.descs[0].target = Lit("cs_6_6"); job_desc->sig->descs[0].target = Lit("cs_6_6");
} }
{ {
Counter counter = ZI; Counter counter = ZI;
P_Run(num_shaders, GPU_D12_CompileShaderJob, &sig, PoolKind_Inherit, PriorityKind_Inherit, &counter); job_desc->count = num_shaders;
P_WaitOnCounter(&counter); job_desc->counter = &counter;
RunJobEx((GenericJobDesc *)job_desc);
WaitOnCounter(&counter);
} }
} }
P_CloseFIle(file); P_CloseFIle(file);
@ -1177,15 +1168,12 @@ W_CallbackFuncDef(GPU_D12_WatchPipelineCallback, name)
__profn("Compile dirty pipelines"); __profn("Compile dirty pipelines");
GPU_D12_Pipeline **pipelines = PushStructs(scratch.arena, GPU_D12_Pipeline *, num_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; Counter counter = ZI;
P_Run(num_pipelines, GPU_D12_AllocPipelineJob, &sig, PoolKind_Inherit, PriorityKind_Inherit, &counter); RunJob(num_pipelines, GPU_D12_AllocPipelineJob, PoolKind_Inherit, PriorityKind_Low, &counter, .descs_in = pipeline_descs, .pipelines_out = pipelines);
P_WaitOnCounter(&counter); WaitOnCounter(&counter);
} }
{ {
P_Lock lock = P_LockS(&g->pipelines_mutex); Lock lock = LockS(&g->pipelines_mutex);
for (u32 i = 0; i < num_pipelines; ++i) for (u32 i = 0; i < num_pipelines; ++i)
{ {
GPU_D12_Pipeline *pipeline = 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); GPU_D12_RegisterPipeline(num_pipelines, pipelines);
} }
@ -1237,7 +1225,7 @@ GPU_D12_Descriptor *GPU_D12_AllocDescriptor(GPU_D12_CpuDescriptorHeap *dh)
u32 index = 0; u32 index = 0;
D3D12_CPU_DESCRIPTOR_HANDLE handle = ZI; D3D12_CPU_DESCRIPTOR_HANDLE handle = ZI;
{ {
P_Lock lock = P_LockE(&dh->mutex); Lock lock = LockE(&dh->mutex);
if (dh->first_free_descriptor) if (dh->first_free_descriptor)
{ {
d = 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++; index = dh->num_descriptors_reserved++;
handle.ptr = dh->handle.ptr + (index * dh->descriptor_size); handle.ptr = dh->handle.ptr + (index * dh->descriptor_size);
} }
P_Unlock(&lock); Unlock(&lock);
} }
ZeroStruct(d); ZeroStruct(d);
d->heap = dh; 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) void GPU_D12_ReleaseDescriptor(GPU_D12_Descriptor *descriptor)
{ {
GPU_D12_CpuDescriptorHeap *dh = descriptor->heap; 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; descriptor->next_free = dh->first_free_descriptor;
dh->first_free_descriptor = 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) for (u32 i = 0; i < countof(g->command_queues); ++i)
{ {
GPU_D12_CommandQueue *cq = 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; 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; *PushStruct(g->fenced_releases_arena, GPU_D12_FencedReleaseData) = fr;
CopyBytes(g->fenced_release_targets, fr_targets, sizeof(fr_targets)); CopyBytes(g->fenced_release_targets, fr_targets, sizeof(fr_targets));
} }
P_Unlock(&lock); Unlock(&lock);
} }
/* Wake evictor */ /* Wake evictor */
{ {
P_Lock lock = P_LockE(&g->evictor_wake_mutex); Lock lock = LockE(&g->evictor_wake_mutex);
{ {
++g->evictor_wake_gen; ++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_SharedState *g = &GPU_D12_shared_state;
GPU_D12_Resource *r = 0; GPU_D12_Resource *r = 0;
{ {
P_Lock lock = P_LockE(&g->resources_mutex); Lock lock = LockE(&g->resources_mutex);
if (g->first_free_resource) if (g->first_free_resource)
{ {
r = 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); r = PushStructNoZero(g->resources_arena, GPU_D12_Resource);
} }
P_Unlock(&lock); Unlock(&lock);
} }
ZeroStruct(r); ZeroStruct(r);
@ -1441,10 +1429,10 @@ void GPU_D12_ReleaseResourceNow(GPU_D12_Resource *t)
ID3D12Resource_Release(t->resource); ID3D12Resource_Release(t->resource);
/* Add to free list */ /* 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; t->next_free = g->first_free_resource;
g->first_free_resource = t; g->first_free_resource = t;
P_Unlock(&lock); Unlock(&lock);
} }
void GPU_ReleaseResourceFenced(GPU_Resource *resource) 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); GPU_D12_CommandListPool *GPU_D12_AllocCommandListPool(GPU_D12_CommandQueue *cq);
JobDef(GPU_D12_AllocCommandQueueJob, job) JobDef(GPU_D12_AllocCommandQueueJob, sig, id)
{ {
__prof; __prof;
GPU_D12_SharedState *g = &GPU_D12_shared_state; GPU_D12_SharedState *g = &GPU_D12_shared_state;
GPU_D12_AllocCommandQueueJobSig *sig = job.sig; GPU_D12_CommandQueueDesc *desc = &sig->descs_in[id];
GPU_D12_CommandQueueDesc *desc = &sig->descs_in[job.id];
{ {
GPU_D12_CommandQueue *cq = 0; GPU_D12_CommandQueue *cq = 0;
{ {
@ -1548,7 +1535,7 @@ JobDef(GPU_D12_AllocCommandQueueJob, job)
cq->cl_pool = GPU_D12_AllocCommandListPool(cq); 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 ID3D12GraphicsCommandList *old_cl = 0;
struct ID3D12CommandAllocator *old_ca = 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 */ /* Find first command list ready for reuse */
for (GPU_D12_CommandList *tmp = pool->first_submitted_command_list; tmp; tmp = tmp->next_submitted) 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); cl = PushStructNoZero(pool->arena, GPU_D12_CommandList);
} }
P_Unlock(&lock); Unlock(&lock);
} }
ZeroStruct(cl); ZeroStruct(cl);
cl->cq = cq; cl->cq = cq;
cl->pool = pool; 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; HRESULT hr = 0;
if (old_cl) if (old_cl)
@ -1698,20 +1685,20 @@ u64 GPU_D12_EndCommandList(GPU_D12_CommandList *cl)
u64 submit_fence_target = 0; u64 submit_fence_target = 0;
{ {
__profn("Execute"); __profn("Execute");
P_Lock submit_lock = P_LockS(&g->global_submit_mutex); Lock submit_lock = LockS(&g->global_submit_mutex);
P_Lock fence_lock = P_LockE(&cq->submit_fence_mutex); Lock fence_lock = LockE(&cq->submit_fence_mutex);
{ {
submit_fence_target = ++cq->submit_fence_target; submit_fence_target = ++cq->submit_fence_target;
ID3D12CommandQueue_ExecuteCommandLists(cq->cq, 1, (ID3D12CommandList **)&cl->cl); ID3D12CommandQueue_ExecuteCommandLists(cq->cq, 1, (ID3D12CommandList **)&cl->cl);
ID3D12CommandQueue_Signal(cq->cq, cq->submit_fence, submit_fence_target); ID3D12CommandQueue_Signal(cq->cq, cq->submit_fence, submit_fence_target);
} }
P_Unlock(&fence_lock); Unlock(&fence_lock);
P_Unlock(&submit_lock); Unlock(&submit_lock);
} }
/* Add descriptor heaps to submitted list */ /* 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) for (GPU_D12_CommandDescriptorHeap *cdh = cl->first_command_descriptor_heap; cdh; cdh = cdh->next_in_command_list)
{ {
cdh->submitted_cq = cq; cdh->submitted_cq = cq;
@ -1726,12 +1713,12 @@ u64 GPU_D12_EndCommandList(GPU_D12_CommandList *cl)
} }
g->last_submitted_command_descriptor_heap = cdh; g->last_submitted_command_descriptor_heap = cdh;
} }
P_Unlock(&lock); Unlock(&lock);
} }
/* Add command buffers to submitted list */ /* 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) for (GPU_D12_CommandBuffer *cb = cl->first_command_buffer; cb; cb = cb->next_in_command_list)
{ {
GPU_D12_CommandBufferGroup *group = cb->group; GPU_D12_CommandBufferGroup *group = cb->group;
@ -1747,14 +1734,14 @@ u64 GPU_D12_EndCommandList(GPU_D12_CommandList *cl)
} }
group->last_submitted = cb; group->last_submitted = cb;
} }
P_Unlock(&lock); Unlock(&lock);
} }
/* Add command list to pool submitted list */ /* 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; 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) if (pool->last_submitted_command_list)
{ {
pool->last_submitted_command_list->next_submitted = cl; 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->first_submitted_command_list = cl;
} }
pool->last_submitted_command_list = cl; pool->last_submitted_command_list = cl;
P_Unlock(&lock); Unlock(&lock);
} }
return submit_fence_target; 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_CPU_DESCRIPTOR_HANDLE old_start_cpu_handle = ZI;
D3D12_GPU_DESCRIPTOR_HANDLE old_start_gpu_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 */ /* Find first heap ready for reuse */
for (GPU_D12_CommandDescriptorHeap *tmp = g->first_submitted_command_descriptor_heap; tmp; tmp = tmp->next_submitted) 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 */ /* No available heap available for reuse, allocate new */
cdh = PushStructNoZero(g->command_descriptor_heaps_arena, GPU_D12_CommandDescriptorHeap); cdh = PushStructNoZero(g->command_descriptor_heaps_arena, GPU_D12_CommandDescriptorHeap);
} }
P_Unlock(&lock); Unlock(&lock);
} }
ZeroStruct(cdh); ZeroStruct(cdh);
@ -1855,9 +1842,9 @@ GPU_D12_CommandDescriptorHeap *GPU_D12_PushDescriptorHeap(GPU_D12_CommandList *c
/* Copy CPU heap */ /* 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); 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 */ /* 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_CommandBuffer *cb = 0;
GPU_D12_Resource *r = 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); 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 */ /* Allocate new */
cb = PushStructNoZero(g->command_buffers_arena, GPU_D12_CommandBuffer); cb = PushStructNoZero(g->command_buffers_arena, GPU_D12_CommandBuffer);
} }
P_Unlock(&lock); Unlock(&lock);
} }
ZeroStruct(cb); ZeroStruct(cb);
cb->group = cb_group; cb->group = cb_group;
@ -2017,10 +2004,9 @@ GPU_D12_CommandBuffer *GPU_D12__PushCommandBuffer(GPU_D12_CommandList *cl, u64 d
* Wait job * Wait job
* ========================== */ * ========================== */
JobDef(GPU_D12_WaitOnFenceJob, job) JobDef(GPU_D12_WaitOnFenceJob, sig, UNUSED id)
{ {
__prof; __prof;
GPU_D12_WaitOnFenceJobSig *sig = job.sig;
ID3D12Fence *fence = sig->fence; ID3D12Fence *fence = sig->fence;
u64 target = sig->target; u64 target = sig->target;
if (ID3D12Fence_GetCompletedValue(fence) < 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 */ /* TODO: Make wait optional */
Counter counter = ZI; Counter counter = ZI;
GPU_D12_UploadJobSig sig = ZI; RunJob(1, GPU_D12_UploadJob, PoolKind_Inherit, PriorityKind_Inherit, &counter, .resource = r, .data = initial_data);
sig.resource = r; WaitOnCounter(&counter);
sig.data = initial_data;
P_Run(1, GPU_D12_UploadJob, &sig, PoolKind_Inherit, PriorityKind_Inherit, &counter);
P_WaitOnCounter(&counter);
} }
return (GPU_Resource *)r; return (GPU_Resource *)r;
@ -2120,10 +2103,9 @@ Vec2I32 GPU_GetTextureSize(GPU_Resource *resource)
* Upload * Upload
* ========================== */ * ========================== */
JobDef(GPU_D12_UploadJob, job) JobDef(GPU_D12_UploadJob, sig, UNUSED id)
{ {
GPU_D12_SharedState *g = &GPU_D12_shared_state; GPU_D12_SharedState *g = &GPU_D12_shared_state;
GPU_D12_UploadJobSig *sig = job.sig;
GPU_D12_Resource *r = sig->resource; GPU_D12_Resource *r = sig->resource;
void *data = sig->data; 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 */ /* Wait on fence so we know it's safe to release upload heap */
if (ID3D12Fence_GetCompletedValue(cq->submit_fence) < fence_target) 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; Counter counter = ZI;
P_Run(1, GPU_D12_WaitOnFenceJob, &wait_sig, PoolKind_Floating, PriorityKind_Low, &counter); RunJob(1, GPU_D12_WaitOnFenceJob, PoolKind_Floating, PriorityKind_Inherit, &counter, .fence = cq->submit_fence, .target = fence_target);
P_WaitOnCounter(&counter); WaitOnCounter(&counter);
} }
/* Release upload heap now */ /* Release upload heap now */
@ -3040,7 +3019,7 @@ GPU_Swapchain *GPU_AllocSwapchain(P_Window *window, Vec2I32 resolution)
GPU_D12_Swapchain *swapchain = 0; GPU_D12_Swapchain *swapchain = 0;
{ {
P_Lock lock = P_LockE(&g->swapchains_mutex); Lock lock = LockE(&g->swapchains_mutex);
if (g->first_free_swapchain) if (g->first_free_swapchain)
{ {
swapchain = 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); swapchain = PushStruct(g->swapchains_arena, GPU_D12_Swapchain);
} }
P_Unlock(&lock); Unlock(&lock);
} }
/* Create swapchain1 */ /* 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]; GPU_D12_CommandQueue *cq = g->command_queues[DX12_QUEUE_DIRECT];
/* Lock direct queue submissions (in case any write to backbuffer) */ /* 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 */ /* 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; //DEBUGBREAKABLE;
//P_Lock lock = P_LockE(&g->global_command_list_record_mutex); //Lock lock = LockE(&g->global_command_list_record_mutex);
{ {
/* Flush direct queue */ /* Flush direct queue */
//ID3D12CommandQueue_Signal(cq->cq, cq->submit_fence, ++cq->submit_fence_target); //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_Panic(Lit("Failed to resize swapchain"));
} }
} }
P_Unlock(&lock); Unlock(&lock);
GPU_D12_InitSwapchainResources(swapchain); GPU_D12_InitSwapchainResources(swapchain);
@ -3309,7 +3288,7 @@ void GPU_PresentSwapchain(GPU_Swapchain *gp_swapchain, Vec2I32 backbuffer_resolu
__profn("Mark queue frames"); __profn("Mark queue frames");
/* Lock because frame marks shouldn't occur while command lists are recording */ /* 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) 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); __prof_dx12_new_frame(cq->prof);
} }
} }
P_Unlock(&lock); Unlock(&lock);
} }
{ {
__profn("Collect queues"); __profn("Collect queues");
@ -3334,7 +3313,7 @@ void GPU_PresentSwapchain(GPU_Swapchain *gp_swapchain, Vec2I32 backbuffer_resolu
* Evictor job * Evictor job
* ========================== */ * ========================== */
JobDef(GPU_D12_EvictorJob, _) JobDef(GPU_D12_EvictorJob, UNUSED sig, UNUSED id)
{ {
GPU_D12_SharedState *g = &GPU_D12_shared_state; GPU_D12_SharedState *g = &GPU_D12_shared_state;
u64 completed_targets[DX12_NUM_QUEUES] = ZI; u64 completed_targets[DX12_NUM_QUEUES] = ZI;
@ -3352,13 +3331,13 @@ JobDef(GPU_D12_EvictorJob, _)
GPU_D12_FencedReleaseData *fenced_releases = 0; GPU_D12_FencedReleaseData *fenced_releases = 0;
{ {
__profn("Copy queued releases"); __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); num_fenced_releases = g->fenced_releases_arena->pos / sizeof(GPU_D12_FencedReleaseData);
fenced_releases = PushStructsNoZero(scratch.arena, GPU_D12_FencedReleaseData, num_fenced_releases); fenced_releases = PushStructsNoZero(scratch.arena, GPU_D12_FencedReleaseData, num_fenced_releases);
CopyBytes(fenced_releases, ArenaBase(g->fenced_releases_arena), g->fenced_releases_arena->pos); CopyBytes(fenced_releases, ArenaBase(g->fenced_releases_arena), g->fenced_releases_arena->pos);
ResetArena(g->fenced_releases_arena); ResetArena(g->fenced_releases_arena);
CopyBytes(targets, g->fenced_release_targets, sizeof(targets)); CopyBytes(targets, g->fenced_release_targets, sizeof(targets));
P_Unlock(&lock); Unlock(&lock);
} }
/* Wait until fences reach target */ /* Wait until fences reach target */
@ -3374,14 +3353,9 @@ JobDef(GPU_D12_EvictorJob, _)
{ {
__profn("Wait on fence"); __profn("Wait on fence");
{ {
GPU_D12_WaitOnFenceJobSig sig = ZI; Counter counter = ZI;
sig.fence = cq->submit_fence; RunJob(1, GPU_D12_WaitOnFenceJob, PoolKind_Floating, PriorityKind_Inherit, &counter, .fence = cq->submit_fence, .target = targets[i]);
sig.target = targets[i]; WaitOnCounter(&counter);
{
Counter counter = ZI;
P_Run(1, GPU_D12_WaitOnFenceJob, &sig, PoolKind_Floating, PriorityKind_Low, &counter);
P_WaitOnCounter(&counter);
}
} }
} }
} }
@ -3415,15 +3389,15 @@ JobDef(GPU_D12_EvictorJob, _)
} }
EndScratch(scratch); 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) 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; shutdown = g->evictor_shutdown;
g->evictor_wake_gen = 0; g->evictor_wake_gen = 0;
} }
P_Unlock(&lock); Unlock(&lock);
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -246,7 +246,7 @@ Struct(N_Host)
u64 num_msg_assembler_lookup_bins; u64 num_msg_assembler_lookup_bins;
/* Double buffer for incoming data */ /* 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_read;
N_RcvBuffer *rcv_buffer_write; N_RcvBuffer *rcv_buffer_write;

View File

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

View File

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

View File

@ -311,7 +311,6 @@ typedef P_ExitFuncDef(P_ExitFunc);
//~ @hookdecl Time helper operations //~ @hookdecl Time helper operations
P_DateTime P_LocalTime(void); P_DateTime P_LocalTime(void);
i64 P_TimeNs(void);
//////////////////////////////// ////////////////////////////////
//~ @hookdecl File system operations //~ @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_MessageBox(P_MessageBoxKind kind, String message);
void P_SetClipboardText(String str); void P_SetClipboardText(String str);
String P_GetClipboardText(Arena *arena); String P_GetClipboardText(Arena *arena);
u32 P_GetLogicalProcessorCount(void);
u32 P_GetThreadId(void);
i64 P_GetCurrentSchedulerPeriodNs(void);
//////////////////////////////// ////////////////////////////////
//~ @hookdecl Sleep //~ @hookdecl Sleep

View File

@ -32,7 +32,7 @@ void P_RegisterLogCallback(P_LogEventCallbackFunc *func, i32 level)
{ {
P_SharedLogState *ctx = &P_shared_log_state; P_SharedLogState *ctx = &P_shared_log_state;
if (!Atomic32Fetch(&ctx->initialized)) { return; } 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); LogEventCallback *callback = PushStruct(ctx->callbacks_arena, LogEventCallback);
callback->func = func; callback->func = func;
@ -47,7 +47,7 @@ void P_RegisterLogCallback(P_LogEventCallbackFunc *func, i32 level)
} }
ctx->last_callback = callback; 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 //- Format message
P_DateTime datetime = P_LocalTime(); P_DateTime datetime = P_LocalTime();
i64 time_ns = P_TimeNs(); i64 time_ns = TimeNs();
String shorthand = settings.shorthand; String shorthand = settings.shorthand;
#if P_IncludeLogSourceLocation #if P_IncludeLogSourceLocation
@ -217,7 +217,7 @@ void P_Log_(i32 level, String msg)
event.line = line; event.line = line;
#endif #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) for (LogEventCallback *callback = ctx->first_callback; callback; callback = callback->next)
{ {
if (level <= callback->level) if (level <= callback->level)
@ -226,7 +226,7 @@ void P_Log_(i32 level, String msg)
callback->func(event); callback->func(event);
} }
} }
P_Unlock(&lock); Unlock(&lock);
} }
EndScratch(scratch); EndScratch(scratch);

View File

@ -63,7 +63,7 @@ Struct(P_SharedLogState)
{ {
Atomic32 initialized; Atomic32 initialized;
P_Mutex callbacks_mutex; Mutex callbacks_mutex;
Arena *callbacks_arena; Arena *callbacks_arena;
LogEventCallback *first_callback; LogEventCallback *first_callback;
LogEventCallback *last_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_SharedCtx *g = &P_W32_shared_ctx;
P_W32_Window *window = 0; P_W32_Window *window = 0;
{ {
P_Lock lock = P_LockE(&g->windows_mutex); Lock lock = LockE(&g->windows_mutex);
if (g->first_free_window) if (g->first_free_window)
{ {
window = 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); window = PushStructNoZero(g->windows_arena, P_W32_Window);
} }
P_Unlock(&lock); Unlock(&lock);
} }
ZeroStruct(window); 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 /* 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 * created and receive a HWND, because on Windows a the event proc must run on
* the same thread that created the window. */ * the same thread that created the window. */
P_CounterAdd(&window->ready_fence, 1); AddCounter(&window->ready_fence, 1);
window->window_thread = P_W32_AllocThread(&W32_WindowThreadEntryFunc, window, Lit("Window thread"), PROF_THREAD_GROUP_WINDOW); window->window_thread = W32_AllocThread(&P_W32_WindowThreadEntryFunc, window, Lit("Window thread"), PROF_THREAD_GROUP_WINDOW);
P_WaitOnCounter(&window->ready_fence); WaitOnCounter(&window->ready_fence);
return window; return window;
} }
@ -106,14 +106,14 @@ void P_W32_ReleaseWindow(P_W32_Window *window)
Atomic32FetchSet(&window->shutdown, 1); Atomic32FetchSet(&window->shutdown, 1);
P_W32_SharedCtx *g = &P_W32_shared_ctx; P_W32_SharedCtx *g = &P_W32_shared_ctx;
P_W32_WakeWindow(window); 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; window->next_free = g->first_free_window;
g->first_free_window = window; g->first_free_window = window;
} }
P_Unlock(&lock); Unlock(&lock);
} }
HWND P_W32_InitWindow(P_W32_Window *window) 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 //~ Win32 window thread
W32_ThreadDef(W32_WindowThreadEntryFunc, arg) W32_ThreadDef(P_W32_WindowThreadEntryFunc, arg)
{ {
P_W32_Window *window = (P_W32_Window *)arg; P_W32_Window *window = (P_W32_Window *)arg;
@ -310,7 +310,7 @@ W32_ThreadDef(W32_WindowThreadEntryFunc, arg)
window->hwnd = P_W32_InitWindow(window); window->hwnd = P_W32_InitWindow(window);
P_W32_UpdateWindowFromSystem(window); P_W32_UpdateWindowFromSystem(window);
BringWindowToTop(window->hwnd); BringWindowToTop(window->hwnd);
P_CounterAdd(&window->ready_fence, -1); AddCounter(&window->ready_fence, -1);
while (!Atomic32Fetch(&window->shutdown)) while (!Atomic32Fetch(&window->shutdown))
{ {
@ -335,11 +335,11 @@ W32_ThreadDef(W32_WindowThreadEntryFunc, arg)
void P_W32_ProcessWindowEvent(P_W32_Window *window, P_WindowEvent event) void P_W32_ProcessWindowEvent(P_W32_Window *window, P_WindowEvent event)
{ {
__prof; __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; *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) void P_W32_WakeWindow(P_W32_Window *window)
@ -785,15 +785,6 @@ P_DateTime P_LocalTime(void)
return P_W32_DateTimeFromWin32SystemTime(lt); 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 //~ @hookdef File system hooks
@ -1166,7 +1157,7 @@ P_Watch *P_AllocWatch(String dir_path)
P_W32_Watch *w32_watch = 0; 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) 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); w32_watch = PushStructNoZero(g->watches_arena, P_W32_Watch);
} }
} }
P_Unlock(&lock); Unlock(&lock);
} }
ZeroStruct(w32_watch); ZeroStruct(w32_watch);
@ -1206,12 +1197,12 @@ void P_ReleaseWatch(P_Watch *dw)
CloseHandle(w32_watch->dir_handle); CloseHandle(w32_watch->dir_handle);
CloseHandle(w32_watch->wake_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; w32_watch->next_free = g->watches_first_free;
g->watches_first_free = w32_watch; g->watches_first_free = w32_watch;
} }
P_Unlock(&lock); Unlock(&lock);
} }
P_WatchInfoList P_ReadWatchWait(Arena *arena, P_Watch *dw) 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; i32 event_arena_index = 0;
{ {
/* Swap event buffers */ /* 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; event_arena_index = window->current_event_arena_index;
window->current_event_arena_index = 1 - 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]; Arena *events_arena = window->event_arenas[event_arena_index];
P_WindowEventArray events = ZI; P_WindowEventArray events = ZI;
@ -1388,11 +1379,11 @@ void P_UpdateWindowSettings(P_Window *p_window, P_WindowSettings *settings)
{ {
__prof; __prof;
P_W32_Window *window = (P_W32_Window *)p_window; 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_W32_UpdateWindowFromSettings(window, settings);
} }
P_Unlock(&lock); Unlock(&lock);
} }
/* FIXME: Lock settings mutex for these functions */ /* 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; P_W32_Window *window = (P_W32_Window *)p_window;
HWND hwnd = window->hwnd; HWND hwnd = window->hwnd;
P_Lock lock = P_LockE(&window->settings_mutex); Lock lock = LockE(&window->settings_mutex);
{ {
i32 show_cmd = SW_NORMAL; i32 show_cmd = SW_NORMAL;
P_WindowSettings *settings = &window->settings; P_WindowSettings *settings = &window->settings;
@ -1423,7 +1414,7 @@ void P_ShowWindow(P_Window *p_window)
ShowWindow(hwnd, show_cmd); ShowWindow(hwnd, show_cmd);
BringWindowToTop(hwnd); BringWindowToTop(hwnd);
} }
P_Unlock(&lock); Unlock(&lock);
} }
void P_SetWindowCursorPos(P_Window *p_window, Vec2 pos) 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_SharedCtx *g = &P_W32_shared_ctx;
P_W32_Sock *ws = 0; P_W32_Sock *ws = 0;
{ {
P_Lock lock = P_LockE(&g->socks_mutex); Lock lock = LockE(&g->socks_mutex);
if (g->first_free_sock) if (g->first_free_sock)
{ {
ws = 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); ws = PushStructNoZero(g->socks_arena, P_W32_Sock);
} }
P_Unlock(&lock); Unlock(&lock);
} }
ZeroStruct(ws); ZeroStruct(ws);
@ -1734,12 +1725,12 @@ void P_ReleaseSock(P_Sock *sock)
P_W32_SharedCtx *g = &P_W32_shared_ctx; P_W32_SharedCtx *g = &P_W32_shared_ctx;
P_W32_Sock *ws = (P_W32_Sock *)sock; P_W32_Sock *ws = (P_W32_Sock *)sock;
closesocket(ws->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; ws->next_free = g->first_free_sock;
g->first_free_sock = ws; g->first_free_sock = ws;
} }
P_Unlock(&lock); Unlock(&lock);
} }
P_SockReadResult P_ReadSock(Arena *arena, P_Sock *sock) P_SockReadResult P_ReadSock(Arena *arena, P_Sock *sock)
@ -1885,22 +1876,6 @@ String P_GetClipboardText(Arena *arena)
return result; 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 //~ @hookdef Sleep hooks
@ -1908,19 +1883,19 @@ void P_SleepPrecise(i64 sleep_time_ns)
{ {
__prof; __prof;
i64 big_sleep = P_GetCurrentSchedulerPeriodNs(); i64 big_sleep = GetCurrentSchedulerPeriodNs();
i64 tolerance = (f64)big_sleep * 0.5; i64 tolerance = (f64)big_sleep * 0.5;
//i64 tolerance = 1000000000; //i64 tolerance = 1000000000;
i64 now_ns = P_TimeNs(); i64 now_ns = TimeNs();
i64 target_ns = now_ns + sleep_time_ns; i64 target_ns = now_ns + sleep_time_ns;
/* Sleep */ /* Sleep */
while (now_ns < target_ns - big_sleep - tolerance) while (now_ns < target_ns - big_sleep - tolerance)
{ {
__profn("Sleep part"); __profn("Sleep part");
P_Wait(0, 0, 0, big_sleep); FutexWait(0, 0, 0, big_sleep);
now_ns = P_TimeNs(); now_ns = TimeNs();
} }
/* Spin */ /* Spin */
@ -1929,7 +1904,7 @@ void P_SleepPrecise(i64 sleep_time_ns)
while (now_ns < target_ns) while (now_ns < target_ns)
{ {
_mm_pause(); _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) 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 last_frame_dt_ns = now_ns - last_frame_time_ns;
i64 sleep_time_ns = target_dt_ns - last_frame_dt_ns; i64 sleep_time_ns = target_dt_ns - last_frame_dt_ns;
if (sleep_time_ns > 0) if (sleep_time_ns > 0)
@ -2073,7 +2048,7 @@ void P_W32_InitBtnTable(void)
g->vk_btn_table[VK_OEM_1] = P_Btn_Semicolon; 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; P_W32_SharedCtx *g = &P_W32_shared_ctx;
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
@ -2085,7 +2060,7 @@ JobDef(P_W32_AppStartupJob, UNUSED job)
EndScratch(scratch); EndScratch(scratch);
} }
JobDef(P_W32_AppShutdownJob, _) JobDef(P_W32_AppShutdownJob, UNUSED sig, UNUSED id)
{ {
__prof; __prof;
P_W32_SharedCtx *g = &P_W32_shared_ctx; 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_begin_event = CreateEventW(0, 1, 0, 0);
g->exit_end_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 */ /* Convert main thread to fiber */
W32_AllocFiber(0); W32_AllocFiber(0);
@ -2253,9 +2216,6 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
LAX success; LAX success;
} }
/* Init threads pool */
g->threads_arena = AllocArena(Gibi(64));
/* Init watches pool */ /* Init watches pool */
g->watches_arena = AllocArena(Gibi(64)); 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 */ /* Run app start job */
if (!Atomic32Fetch(&g->panicking)) 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 */ /* 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 */ /* Run exit callbacks job */
if (!Atomic32Fetch(&g->panicking)) 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 */ /* Wait for exit end or panic */

View File

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

View File

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

View File

@ -11,11 +11,9 @@ UserStartupReceipt StartupUser(S_StartupReceipt *sprite_sr,
String connect_address_str) String connect_address_str)
{ {
__prof; __prof;
LAX font_sr;
LAX sprite_sr; LAX sprite_sr;
LAX draw_sr; LAX draw_sr;
LAX asset_cache_sr; LAX asset_cache_sr;
LAX sound_sr;
LAX mixer_sr; LAX mixer_sr;
LAX sim_sr; LAX sim_sr;
SharedUserState *g = &shared_user_state; SharedUserState *g = &shared_user_state;
@ -23,7 +21,7 @@ UserStartupReceipt StartupUser(S_StartupReceipt *sprite_sr,
SetGstat(GSTAT_DEBUG_STEPS, U64Max); SetGstat(GSTAT_DEBUG_STEPS, U64Max);
g->arena = AllocArena(Gibi(64)); g->arena = AllocArena(Gibi(64));
g->real_time_ns = P_TimeNs(); g->real_time_ns = TimeNs();
/* TODO: Remove this */ /* TODO: Remove this */
g->connect_address_str = PushString(g->arena, connect_address_str); g->connect_address_str = PushString(g->arena, connect_address_str);
@ -55,8 +53,8 @@ UserStartupReceipt StartupUser(S_StartupReceipt *sprite_sr,
P_ShowWindow(g->window); P_ShowWindow(g->window);
/* Start jobs */ /* Start jobs */
P_Run(1, UpdateUserJob, 0, PoolKind_User, PriorityKind_High, &g->shutdown_job_counters); RunJob(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, SimJob, 0, PoolKind_Sim, PriorityKind_High, &g->shutdown_job_counters);
P_OnExit(&ShutdownUser); P_OnExit(&ShutdownUser);
return (UserStartupReceipt) { 0 }; return (UserStartupReceipt) { 0 };
@ -70,7 +68,7 @@ P_ExitFuncDef(ShutdownUser)
__prof; __prof;
SharedUserState *g = &shared_user_state; SharedUserState *g = &shared_user_state;
Atomic32FetchSet(&g->shutdown, 1); Atomic32FetchSet(&g->shutdown, 1);
P_WaitOnCounter(&g->shutdown_job_counters); WaitOnCounter(&g->shutdown_job_counters);
P_ReleaseWindow(g->window); P_ReleaseWindow(g->window);
} }
@ -234,7 +232,7 @@ P_LogEventCallbackFuncDef(ConsoleLogCallback, log)
{ {
__prof; __prof;
SharedUserState *g = &shared_user_state; 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); ConsoleLog *clog = PushStruct(g->console_logs_arena, ConsoleLog);
clog->level = log.level; clog->level = log.level;
@ -257,7 +255,7 @@ P_LogEventCallbackFuncDef(ConsoleLogCallback, log)
} }
g->last_console_log = clog; g->last_console_log = clog;
} }
P_Unlock(&lock); Unlock(&lock);
} }
//- Draw console //- Draw console
@ -298,11 +296,11 @@ void DrawDebugConsole(i32 level, b32 minimized)
} }
g->console_logs_height = 0; 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); F_Font *font = F_LoadFontAsync(Lit("font/fixedsys.ttf"), 12.0f);
if (font) 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) 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) if (bounds_top < F32Infinity && bounds_bottom > -F32Infinity)
{ {
@ -417,7 +415,7 @@ void UpdateUser(P_Window *window)
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
//- Begin frame //- 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->real_time_ns += g->real_dt_ns;
g->screen_size = P_GetWindowSize(window); g->screen_size = P_GetWindowSize(window);
S_Scope *sprite_frame_scope = S_BeginScope(); S_Scope *sprite_frame_scope = S_BeginScope();
@ -426,7 +424,7 @@ void UpdateUser(P_Window *window)
{ {
__profn("Pull snapshot"); __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 old_last_tick = g->user_unblended_client->last_tick;
u64 last_tick = g->local_to_user_client->last_tick; u64 last_tick = g->local_to_user_client->last_tick;
if (last_tick > old_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->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; 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 //- Create user world from blended snapshots
@ -1832,7 +1830,7 @@ void UpdateUser(P_Window *window)
/* Set user sim control */ /* Set user sim control */
{ {
P_Lock lock = P_LockE(&g->user_sim_cmd_mutex); Lock lock = LockE(&g->user_sim_cmd_mutex);
/* Reset flags */ /* Reset flags */
if (g->user_sim_cmd_gen != g->last_user_sim_cmd_gen) 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 = control;
g->user_sim_cmd_control.flags |= old_flags; g->user_sim_cmd_control.flags |= old_flags;
g->user_hovered_ent = hovered_ent->id; 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 */ /* 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_read.last_second_end = GetGstat(GSTAT_SOCK_BYTES_RECEIVED);
g->net_bytes_sent.last_second_end = GetGstat(GSTAT_SOCK_BYTES_SENT); g->net_bytes_sent.last_second_end = GetGstat(GSTAT_SOCK_BYTES_SENT);
if (stat_now_ns - g->last_second_reset_ns > NsFromSeconds(1)) if (stat_now_ns - g->last_second_reset_ns > NsFromSeconds(1))
@ -2066,10 +2064,10 @@ void UpdateUser(P_Window *window)
//- User update job //- User update job
JobDef(UpdateUserJob, _) JobDef(UpdateUserJob, UNUSED sig, UNUSED id)
{ {
SharedUserState *g = &shared_user_state; SharedUserState *g = &shared_user_state;
i64 time_ns = P_TimeNs(); i64 time_ns = TimeNs();
while (!Atomic32Fetch(&g->shutdown)) while (!Atomic32Fetch(&g->shutdown))
{ {
P_Window *window = g->window; P_Window *window = g->window;
@ -2082,7 +2080,7 @@ JobDef(UpdateUserJob, _)
{ {
__profn("Frame limiter wait"); __profn("Frame limiter wait");
P_SleepFrame(time_ns, 1000000000 / FPS_LIMIT); P_SleepFrame(time_ns, 1000000000 / FPS_LIMIT);
time_ns = P_TimeNs(); time_ns = TimeNs();
} }
} }
UpdateUser(window); UpdateUser(window);
@ -2109,7 +2107,7 @@ void GenerateuserInputCmds(Client *user_input_client, u64 tick)
sim_ent_activate(control_cmd, user_input_ss->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 */ /* Update control cmd */
{ {
control_cmd->cmd_control = g->user_sim_cmd_control; control_cmd->cmd_control = g->user_sim_cmd_control;
@ -2125,14 +2123,14 @@ void GenerateuserInputCmds(Client *user_input_client, u64 tick)
} }
#endif #endif
++g->user_sim_cmd_gen; ++g->user_sim_cmd_gen;
P_Unlock(&lock); Unlock(&lock);
} }
} }
//////////////////////////////// ////////////////////////////////
//~ Sim update //~ Sim update
JobDef(SimJob, UNUSED job) JobDef(SimJob, UNUSED sig, UNUSED id)
{ {
SharedUserState *g = &shared_user_state; SharedUserState *g = &shared_user_state;
#if 0 #if 0
@ -2221,7 +2219,7 @@ JobDef(SimJob, UNUSED job)
{ {
__profn("Sim update"); __profn("Sim update");
real_dt_ns = P_TimeNs() - real_time_ns; real_dt_ns = TimeNs() - real_time_ns;
real_time_ns += real_dt_ns; real_time_ns += real_dt_ns;
N_EventList host_events = N_BeginUpdate(scratch.arena, host); N_EventList host_events = N_BeginUpdate(scratch.arena, host);
@ -2798,9 +2796,9 @@ JobDef(SimJob, UNUSED job)
if (local_ss->valid) if (local_ss->valid)
{ {
/* TODO: Double buffer */ /* 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); 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) if (last_publish_to_user_ns == 0)
{ {
last_publish_to_user_ns = publish_ns - g->average_local_to_user_snapshot_publish_dt_ns; 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; g->local_to_user_client_publish_time_ns = publish_ns;
last_publish_to_user_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); 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; b32 debug_draw;
//- Debug console //- Debug console
P_Mutex console_logs_mutex; Mutex console_logs_mutex;
Arena *console_logs_arena; Arena *console_logs_arena;
ConsoleLog *first_console_log; ConsoleLog *first_console_log;
ConsoleLog *last_console_log; ConsoleLog *last_console_log;
@ -194,11 +194,11 @@ Struct(SharedUserState)
b32 debug_console; b32 debug_console;
//- Window -> user //- Window -> user
P_Mutex sys_window_events_mutex; Mutex sys_window_events_mutex;
Arena *sys_window_events_arena; Arena *sys_window_events_arena;
//- User -> sim //- User -> sim
P_Mutex user_sim_cmd_mutex; Mutex user_sim_cmd_mutex;
ControlData user_sim_cmd_control; ControlData user_sim_cmd_control;
EntityId user_hovered_ent; EntityId user_hovered_ent;
u64 last_user_sim_cmd_gen; u64 last_user_sim_cmd_gen;
@ -208,7 +208,7 @@ Struct(SharedUserState)
Atomic32 user_paused_steps; Atomic32 user_paused_steps;
//- Sim -> user //- Sim -> user
P_Mutex local_to_user_client_mutex; Mutex local_to_user_client_mutex;
ClientStore *local_to_user_client_store; ClientStore *local_to_user_client_store;
Client *local_to_user_client; Client *local_to_user_client;
i64 local_to_user_client_publish_dt_ns; 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) { if (ss->num_ents_reserved == 0) {
/* Copying from nil snapshot, need to create blank & root entity */ /* 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); PushStruct(ss->ents_arena, Entity);
++ss->num_ents_allocated; ++ss->num_ents_allocated;
++ss->num_ents_reserved; ++ss->num_ents_reserved;
} }
/* PushStruct root ent with constant id */ /* Push root ent with constant id */
{ {
Entity *root = PushStructNoZero(ss->ents_arena, Entity); Entity *root = PushStructNoZero(ss->ents_arena, Entity);
*root = *sim_ent_nil(); *root = *sim_ent_nil();

View File

@ -1,17 +1,16 @@
//////////////////////////////// ////////////////////////////////
//~ Load job //~ Load job
JobDef(SND_LoadAssetJob, job) JobDef(SND_LoadJob, sig, UNUSED id)
{ {
__prof; __prof;
SND_LoadAssetJobSig *params = job.sig;
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
String path = STRING(params->path_len, (u8 *)params->path_cstr); String path = sig->path;
AC_Asset *asset = params->asset; AC_Asset *asset = sig->asset;
SND_SoundFlag flags = params->flags; SND_SoundFlag flags = sig->flags;
P_LogInfoF("Loading sound \"%F\"", FmtString(path)); P_LogInfoF("Loading sound \"%F\"", FmtString(path));
i64 start_ns = P_TimeNs(); i64 start_ns = TimeNs();
String error_msg = Lit("Unknown error"); String error_msg = Lit("Unknown error");
@ -61,7 +60,7 @@ JobDef(SND_LoadAssetJob, job)
sound->samples = samples; sound->samples = samples;
CopyBytes(sound->samples, decoded.samples, decoded.samples_count * sizeof(*decoded.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); AC_MarkReady(asset, sound);
} }
else else
@ -101,22 +100,12 @@ AC_Asset *SND_LoadAsset(String path, SND_SoundFlag flags, b32 wait)
if (is_first_touch) 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); 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) if (wait)
{ {
AC_WaitOnAssetReady(asset); AC_WaitOnAssetReady(asset);

View File

@ -19,7 +19,7 @@ Struct(SND_Sound)
//////////////////////////////// ////////////////////////////////
//~ Sound load operations //~ 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); AC_Asset *SND_LoadAsset(String path, SND_SoundFlag flags, b32 wait);
SND_Sound *SND_LoadSoundAsync(String path, SND_SoundFlag flags); SND_Sound *SND_LoadSoundAsync(String path, SND_SoundFlag flags);
SND_Sound *SND_LoadSoundWait(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.arena = AllocArena(Gibi(64));
g->cache.bins = PushStructs(g->cache.arena, S_CacheEntryBin, S_CacheBinsCount); g->cache.bins = PushStructs(g->cache.arena, S_CacheEntryBin, S_CacheBinsCount);
g->cmds_arena = AllocArena(Gibi(64));
g->scopes_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); P_OnExit(&S_Shutdown);
#if RESOURCE_RELOADING #if RESOURCE_RELOADING
@ -63,13 +61,13 @@ P_ExitFuncDef(S_Shutdown)
S_SharedState *g = &S_shared_state; S_SharedState *g = &S_shared_state;
/* Signal evictor shutdown */ /* Signal evictor shutdown */
{ {
P_Lock lock = P_LockE(&g->evictor_scheduler_mutex); Lock lock = LockE(&g->evictor_scheduler_mutex);
g->evictor_scheduler_shutdown = 1; g->evictor_scheduler_shutdown = 1;
P_SignalCv(&g->evictor_scheduler_shutdown_cv, I32Max); SignalCv(&g->evictor_scheduler_shutdown_cv, I32Max);
P_Unlock(&lock); Unlock(&lock);
} }
/* Wait for evictor shutdown */ /* 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 //~ Load job
//- Job def JobDef(S_LoadSpriteJob, sig, UNUSED id)
JobDef(S_LoadSpriteJob, job)
{ {
__prof; __prof;
S_SharedState *g = &S_shared_state; S_CacheEntryRef ref = sig->ref;
S_Cmd *cmd = job.sig; S_Tag tag = sig->tag;
S_CacheEntryRef ref = cmd->ref; S_Scope *scope = sig->scope;
switch (ref.e->kind) switch (ref.e->kind)
{ {
case S_CacheEntryKind_Texture: case S_CacheEntryKind_Texture:
{ {
S_LoadCacheEntryTexture(ref, cmd->tag); S_LoadCacheEntryTexture(ref, tag);
} break; } break;
case S_CacheEntryKind_Sheet: case S_CacheEntryKind_Sheet:
{ {
S_LoadCacheEntrySheet(ref, cmd->tag); S_LoadCacheEntrySheet(ref, tag);
} break; } break;
default: { P_Panic(Lit("Unknown sprite cache node kind")); } break; default: { P_Panic(Lit("Unknown sprite cache node kind")); } break;
} }
S_EndScope(scope);
/* 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);
} }
//- Push
void S_PushLoadJob(S_CacheEntryRef ref, S_Tag tag) void S_PushLoadJob(S_CacheEntryRef ref, S_Tag tag)
{ {
S_SharedState *g = &S_shared_state; S_LoadSpriteJob_Desc *desc = PushJobDesc(S_LoadSpriteJob, .pool = PoolKind_Background, .priority = PriorityKind_Inherit);
S_Cmd *cmd = 0; desc->sig->scope = S_BeginScope(); /* Scope ended by job */
{ desc->sig->ref = S_EnsureRefFromRef(desc->sig->scope, ref)->ref;
P_Lock lock = P_LockE(&g->cmds_mutex); desc->sig->tag = tag;
if (g->first_free_cmd) tag.path = PushString(desc->arena, tag.path);
{ RunJobEx((GenericJobDesc *)desc);
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);
} }
//////////////////////////////// ////////////////////////////////
@ -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)); P_LogInfoF("Loading sprite texture [%F] \"%F\"", FmtHex(e->hash.v), FmtString(path));
b32 success = 0; b32 success = 0;
i64 start_ns = P_TimeNs(); i64 start_ns = TimeNs();
Assert(StringEndsWith(path, Lit(".ase"))); Assert(StringEndsWith(path, Lit(".ase")));
Assert(e->kind == S_CacheEntryKind_Texture); 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).", P_LogSuccessF("Loaded sprite texture [%F] \"%F\" in %F seconds (cache size: %F bytes).",
FmtHex(e->hash.v), FmtHex(e->hash.v),
FmtString(path), FmtString(path),
FmtFloat(SecondsFromNs(P_TimeNs() - start_ns)), FmtFloat(SecondsFromNs(TimeNs() - start_ns)),
FmtUint(e->memory_usage)); FmtUint(e->memory_usage));
} }
@ -557,7 +521,7 @@ void S_LoadCacheEntryTexture(S_CacheEntryRef ref, S_Tag tag)
#if RESOURCE_RELOADING #if RESOURCE_RELOADING
S_CacheEntryBin *bin = &g->cache.bins[e->hash.v % S_CacheBinsCount]; 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) 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); 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 #endif
EndScratch(scratch); 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)); P_LogInfoF("Loading sprite sheet [%F] \"%F\"", FmtHex(e->hash.v), FmtString(path));
b32 success = 0; b32 success = 0;
i64 start_ns = P_TimeNs(); i64 start_ns = TimeNs();
Assert(e->kind == S_CacheEntryKind_Sheet); 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).", P_LogSuccessF("Loaded sprite sheet [%F] \"%F\" in %F seconds (cache size: %F bytes).",
FmtHex(e->hash.v), FmtHex(e->hash.v),
FmtString(path), FmtString(path),
FmtFloat(SecondsFromNs(P_TimeNs() - start_ns)), FmtFloat(SecondsFromNs(TimeNs() - start_ns)),
FmtUint(e->memory_usage)); FmtUint(e->memory_usage));
} }
@ -640,7 +604,7 @@ void S_LoadCacheEntrySheet(S_CacheEntryRef ref, S_Tag tag)
#if RESOURCE_RELOADING #if RESOURCE_RELOADING
S_CacheEntryBin *bin = &g->cache.bins[e->hash.v % S_CacheBinsCount]; 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) 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); 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 #endif
EndScratch(scratch); EndScratch(scratch);
@ -720,11 +684,11 @@ S_ScopeCacheEntryRef *S_EnsureRefUnsafely(S_Scope *scope, S_CacheEntry *e)
return *slot; 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; 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 */ /* 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); return S_EnsureRefUnsafely(scope, e);
} }
@ -745,7 +709,7 @@ S_Scope *S_BeginScope(void)
S_ScopeCacheEntryRef **bins = 0; S_ScopeCacheEntryRef **bins = 0;
S_ScopeCacheEntryRef *pool = 0; S_ScopeCacheEntryRef *pool = 0;
{ {
P_Lock lock = P_LockE(&g->scopes_mutex); Lock lock = LockE(&g->scopes_mutex);
{ {
if (g->first_free_scope) if (g->first_free_scope)
{ {
@ -761,7 +725,7 @@ S_Scope *S_BeginScope(void)
pool = PushStructsNoZero(g->scopes_arena, S_ScopeCacheEntryRef, S_MaxScopeReferences); pool = PushStructsNoZero(g->scopes_arena, S_ScopeCacheEntryRef, S_MaxScopeReferences);
} }
} }
P_Unlock(&lock); Unlock(&lock);
} }
ZeroStruct(result); ZeroStruct(result);
ZeroBytes(bins, sizeof(*bins) * S_CacheBinsCount); ZeroBytes(bins, sizeof(*bins) * S_CacheBinsCount);
@ -782,12 +746,12 @@ void S_EndScope(S_Scope *scope)
} }
/* Release scope */ /* Release scope */
P_Lock lock = P_LockE(&g->scopes_mutex); Lock lock = LockE(&g->scopes_mutex);
{ {
scope->next_free = g->first_free_scope; scope->next_free = g->first_free_scope;
g->first_free_scope = scope; g->first_free_scope = scope;
} }
P_Unlock(&lock); Unlock(&lock);
} }
//////////////////////////////// ////////////////////////////////
@ -795,13 +759,13 @@ void S_EndScope(S_Scope *scope)
//- Locked lookup //- 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_SharedState *g = &S_shared_state;
S_ScopeCacheEntryRef *scope_ref = 0; S_ScopeCacheEntryRef *scope_ref = 0;
S_CacheEntryBin *bin = &g->cache.bins[hash.v % S_CacheBinsCount]; 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
/* If resource reloading is enabled, then we want to find the /* 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 */ /* Search in cache */
if (!force_new) 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); scope_ref = S_EntryFromHashLocked(scope, hash, &bin_lock);
} }
P_Unlock(&bin_lock); Unlock(&bin_lock);
} }
/* If not in cache, allocate new entry */ /* If not in cache, allocate new entry */
if (!scope_ref) 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 */ /* Search cache one more time in case an entry was allocated between locks */
if (!force_new) 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 */ /* Cache entry still absent, allocate new entry */
S_CacheEntry *entry = 0; 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) if (g->cache.entry_pool_first_free)
{ {
entry = 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); entry = PushStructNoZero(g->cache.arena, S_CacheEntry);
} }
P_Unlock(&pool_lock); Unlock(&pool_lock);
} }
ZeroStruct(entry); 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); 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_Hash hash = S_CacheEntryFromTagHash(tag.hash, kind);
S_CacheEntryBin *bin = &g->cache.bins[hash.v % S_CacheBinsCount]; S_CacheEntryBin *bin = &g->cache.bins[hash.v % S_CacheBinsCount];
S_ScopeCacheEntryRef *existing_ref = 0; 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); existing_ref = S_EntryFromHashLocked(scope, hash, &bin_lock);
} }
P_Unlock(&bin_lock); Unlock(&bin_lock);
if (existing_ref) 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 * - 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 * - 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; S_SharedState *g = &S_shared_state;
b32 shutdown = 0; b32 shutdown = 0;
@ -1211,7 +1175,7 @@ JobDef(S_EvictorJob, _)
for (u64 i = 0; i < S_CacheBinsCount; ++i) for (u64 i = 0; i < S_CacheBinsCount; ++i)
{ {
S_CacheEntryBin *bin = &g->cache.bins[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; S_CacheEntry *n = bin->first;
while (n) while (n)
@ -1244,7 +1208,7 @@ JobDef(S_EvictorJob, _)
n = n->next_in_bin; 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; S_CacheEntry *entry = en->cache_entry;
i32 last_ref_cycle = en->last_ref_cycle; i32 last_ref_cycle = en->last_ref_cycle;
b32 cache_over_budget_target = Atomic64Fetch(&g->cache.memory_usage.v) > (i64)S_CacheMemoryBudgetTarget; 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); u64 refcount_uncast = Atomic64Fetch(&entry->refcount_struct.v);
S_Refcount refcount = *(S_Refcount *)&refcount_uncast; S_Refcount refcount = *(S_Refcount *)&refcount_uncast;
@ -1311,7 +1275,7 @@ JobDef(S_EvictorJob, _)
stop_evicting = 1; stop_evicting = 1;
} }
} }
P_Unlock(&bin_lock); Unlock(&bin_lock);
} }
} }
@ -1334,14 +1298,14 @@ JobDef(S_EvictorJob, _)
/* Add evicted nodes to free list */ /* Add evicted nodes to free list */
{ {
__profn("Evictor free list append"); __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) for (S_EvictorNode *en = first_evicted; en; en = en->next_evicted)
{ {
S_CacheEntry *n = en->cache_entry; S_CacheEntry *n = en->cache_entry;
n->next_free = g->cache.entry_pool_first_free; n->next_free = g->cache.entry_pool_first_free;
g->cache.entry_pool_first_free = n; g->cache.entry_pool_first_free = n;
} }
P_Unlock(&pool_lock); Unlock(&pool_lock);
} }
} }
} }
@ -1351,15 +1315,15 @@ JobDef(S_EvictorJob, _)
/* Evictor sleep */ /* Evictor sleep */
{ {
P_Lock lock = P_LockE(&g->evictor_scheduler_mutex); Lock lock = LockE(&g->evictor_scheduler_mutex);
{ {
if (!g->evictor_scheduler_shutdown) 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; shutdown = g->evictor_scheduler_shutdown;
} }
P_Unlock(&lock); Unlock(&lock);
} }
} }
} }

View File

@ -150,7 +150,7 @@ Struct(S_CacheEntry)
Struct(S_CacheEntryBin) Struct(S_CacheEntryBin)
{ {
P_Mutex mutex; Mutex mutex;
S_CacheEntry *first; S_CacheEntry *first;
S_CacheEntry *last; S_CacheEntry *last;
}; };
@ -160,7 +160,7 @@ Struct(S_Cache)
Atomic64Padded memory_usage; Atomic64Padded memory_usage;
Arena *arena; Arena *arena;
S_CacheEntryBin *bins; S_CacheEntryBin *bins;
P_Mutex entry_pool_mutex; Mutex entry_pool_mutex;
S_CacheEntry *entry_pool_first_free; S_CacheEntry *entry_pool_first_free;
}; };
@ -238,7 +238,7 @@ Struct(S_SharedState)
S_Cache cache; S_Cache cache;
/* Scopes */ /* Scopes */
P_Mutex scopes_mutex; Mutex scopes_mutex;
Arena *scopes_arena; Arena *scopes_arena;
S_Scope *first_free_scope; S_Scope *first_free_scope;
@ -246,8 +246,8 @@ Struct(S_SharedState)
Atomic32Padded evictor_cycle; Atomic32Padded evictor_cycle;
Counter shutdown_counter; Counter shutdown_counter;
b32 evictor_scheduler_shutdown; b32 evictor_scheduler_shutdown;
P_Mutex evictor_scheduler_mutex; Mutex evictor_scheduler_mutex;
P_Cv evictor_scheduler_shutdown_cv; Cv evictor_scheduler_shutdown_cv;
}; };
extern S_SharedState S_shared_state; 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); void S_AddRef(S_CacheEntry *e, i32 amount);
S_ScopeCacheEntryRef *S_EnsureRefUnsafely(S_Scope *scope, S_CacheEntry *e); 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); S_ScopeCacheEntryRef *S_EnsureRefFromRef(S_Scope *scope, S_CacheEntryRef ref);
//////////////////////////////// ////////////////////////////////
@ -310,7 +310,7 @@ void S_EndScope(S_Scope *scope);
//////////////////////////////// ////////////////////////////////
//~ Cache lookup operations //~ 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); 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); 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)); g->watch_events_arena = AllocArena(Gibi(64));
P_Run(1, W_MonitorJob, 0, PoolKind_Floating, PriorityKind_Low, &g->watch_jobs_counter); RunJob(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_DispatcherJob, 0, PoolKind_Background, PriorityKind_Low, &g->watch_jobs_counter);
P_OnExit(&W_Shutdown); P_OnExit(&W_Shutdown);
} }
@ -21,12 +21,12 @@ P_ExitFuncDef(W_Shutdown)
W_SharedState *g = &W_shared_state; W_SharedState *g = &W_shared_state;
Atomic32FetchSet(&g->W_Shutdown, 1); Atomic32FetchSet(&g->W_Shutdown, 1);
{ {
P_Lock lock = P_LockE(&g->watch_dispatcher_mutex); Lock lock = LockE(&g->watch_dispatcher_mutex);
P_SignalCv(&g->watch_dispatcher_cv, I32Max); SignalCv(&g->watch_dispatcher_cv, I32Max);
P_WakeWatch(g->watch); 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) void W_RegisterCallback(W_CallbackFunc *callback)
{ {
W_SharedState *g = &W_shared_state; 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)) 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_Panic(Lit("Max resource watch callbacks reached"));
} }
} }
P_Unlock(&lock); Unlock(&lock);
} }
JobDef(W_RunCallbackJob, job) JobDef(W_RunCallbacksJob , sig, id)
{ {
__prof; __prof;
W_RunCallbackJobSig *sig = job.sig;
String name = sig->name; String name = sig->name;
W_CallbackFunc *callback = sig->callbacks[job.id]; W_CallbackFunc *callback = sig->callbacks[id];
callback(name); callback(name);
} }
@ -65,7 +64,7 @@ JobDef(W_RunCallbackJob, job)
* & dispatching watch callbacks into two separate jobs so that we can delay * & dispatching watch callbacks into two separate jobs so that we can delay
* the dispatch, allowing for deduplication of file modification notifications. */ * the dispatch, allowing for deduplication of file modification notifications. */
JobDef(W_MonitorJob, _) JobDef(W_MonitorJob, UNUSED sig, UNUSED job_id)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
W_SharedState *g = &W_shared_state; W_SharedState *g = &W_shared_state;
@ -81,7 +80,7 @@ JobDef(W_MonitorJob, _)
P_WatchInfoList info_list = P_ReadWatchWait(temp.arena, g->watch); P_WatchInfoList info_list = P_ReadWatchWait(temp.arena, g->watch);
if (info_list.first && !Atomic32Fetch(&g->W_Shutdown)) 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) 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); SignalCv(&g->watch_dispatcher_cv, I32Max);
P_Unlock(&lock); Unlock(&lock);
} }
EndTempArena(temp); EndTempArena(temp);
} }
@ -123,7 +122,7 @@ JobDef(W_MonitorJob, _)
//////////////////////////////// ////////////////////////////////
//~ Dispatcher job //~ Dispatcher job
JobDef(W_DispatcherJob, _) JobDef(W_DispatcherJob, UNUSED sig, UNUSED job_id)
{ {
W_SharedState *g = &W_shared_state; W_SharedState *g = &W_shared_state;
@ -138,12 +137,12 @@ JobDef(W_DispatcherJob, _)
/* Delay so that duplicate events pile up */ /* Delay so that duplicate events pile up */
{ {
__profn("Delay"); __profn("Delay");
P_Wait(0, 0, 0, NsFromSeconds(W_DispatcherDelaySeconds)); FutexWait(0, 0, 0, NsFromSeconds(W_DispatcherDelaySeconds));
} }
/* Pull watch events from queue */ /* 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) for (W_Event *src_event = g->first_watch_event; src_event; src_event = src_event->next)
{ {
W_Event *e = PushStruct(scratch.arena, W_Event); W_Event *e = PushStruct(scratch.arena, W_Event);
@ -161,13 +160,13 @@ JobDef(W_DispatcherJob, _)
g->first_watch_event = 0; g->first_watch_event = 0;
g->last_watch_event = 0; g->last_watch_event = 0;
ResetArena(g->watch_events_arena); ResetArena(g->watch_events_arena);
P_Unlock(&lock); Unlock(&lock);
} }
/* Build callbacks array */ /* Build callbacks array */
u64 num_callbacks = 0; u64 num_callbacks = 0;
W_CallbackFunc **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; num_callbacks = g->num_watch_callbacks;
callbacks = PushStructsNoZero(scratch.arena, W_CallbackFunc *, num_callbacks); callbacks = PushStructsNoZero(scratch.arena, W_CallbackFunc *, num_callbacks);
@ -176,7 +175,7 @@ JobDef(W_DispatcherJob, _)
callbacks[i] = g->watch_callbacks[i]; callbacks[i] = g->watch_callbacks[i];
} }
} }
P_Unlock(&callbacks_lock); Unlock(&callbacks_lock);
/* Run callbacks */ /* Run callbacks */
{ {
@ -197,12 +196,9 @@ JobDef(W_DispatcherJob, _)
} }
if (!skip) if (!skip)
{ {
W_RunCallbackJobSig sig = ZI;
sig.name = e->name;
sig.callbacks = callbacks;
Counter counter = ZI; Counter counter = ZI;
P_Run(num_callbacks, W_RunCallbackJob, &sig, PoolKind_Background, PriorityKind_Low, &counter); RunJob(num_callbacks, W_RunCallbacksJob, PoolKind_Background, PriorityKind_Low, &counter, .name = e->name, .callbacks = callbacks);
P_WaitOnCounter(&counter); WaitOnCounter(&counter);
} }
} }
} }
@ -211,15 +207,15 @@ JobDef(W_DispatcherJob, _)
} }
/* Wait for event */ /* Wait for event */
P_Lock lock = P_LockS(&g->watch_dispatcher_mutex); Lock lock = LockS(&g->watch_dispatcher_mutex);
{ {
shutdown = Atomic32Fetch(&g->W_Shutdown); shutdown = Atomic32Fetch(&g->W_Shutdown);
while (!shutdown && !g->first_watch_event) while (!shutdown && !g->first_watch_event)
{ {
P_WaitOnCv(&g->watch_dispatcher_cv, &lock); WaitOnCv(&g->watch_dispatcher_cv, &lock);
shutdown = Atomic32Fetch(&g->W_Shutdown); 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) #define W_CallbackFuncDef(func_name, arg_name) void func_name(String arg_name)
typedef W_CallbackFuncDef(W_CallbackFunc, name); typedef W_CallbackFuncDef(W_CallbackFunc, name);
Struct(W_RunCallbackJobSig)
{
String name;
W_CallbackFunc **callbacks;
};
//////////////////////////////// ////////////////////////////////
//~ Event types //~ Event types
@ -31,13 +25,13 @@ Struct(W_SharedState)
Atomic32 W_Shutdown; Atomic32 W_Shutdown;
Counter watch_jobs_counter; Counter watch_jobs_counter;
P_Mutex watch_dispatcher_mutex; Mutex watch_dispatcher_mutex;
Arena *watch_events_arena; Arena *watch_events_arena;
W_Event *first_watch_event; W_Event *first_watch_event;
W_Event *last_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]; W_CallbackFunc *watch_callbacks[64];
u64 num_watch_callbacks; u64 num_watch_callbacks;
}; };
@ -58,7 +52,7 @@ void W_RegisterCallback(W_CallbackFunc *callback);
//////////////////////////////// ////////////////////////////////
//~ Callback job //~ Callback job
JobDecl(W_RunCallbackJob, EmptySig); JobDecl(W_RunCallbacksJob, { String name; W_CallbackFunc **callbacks; });
//////////////////////////////// ////////////////////////////////
//~ Long running jobs //~ Long running jobs