diff --git a/src/asset_cache/asset_cache.c b/src/asset_cache/asset_cache.c index 34ea915d..903225a9 100644 --- a/src/asset_cache/asset_cache.c +++ b/src/asset_cache/asset_cache.c @@ -135,7 +135,6 @@ AC_Asset *AC_TouchCache(String key, u64 hash, b32 *is_first_touch) .hash = hash, .key = key_stored }; - AddCounter(&asset->counter, 1); if (is_first_touch) { *is_first_touch = 1; @@ -165,12 +164,12 @@ void AC_MarkReady(AC_Asset *asset, void *store_data) { asset->store_data = store_data; asset->status = ASSET_STATUS_READY; - AddCounter(&asset->counter, -1); + SetFence(&asset->ready_fence, 1); } void AC_YieldOnAssetReady(AC_Asset *asset) { - YieldOnCounter(&asset->counter); + YieldOnFence(&asset->ready_fence, 1); } //////////////////////////////// diff --git a/src/asset_cache/asset_cache.h b/src/asset_cache/asset_cache.h index 721381e9..f8f92456 100644 --- a/src/asset_cache/asset_cache.h +++ b/src/asset_cache/asset_cache.h @@ -17,7 +17,8 @@ Struct(AC_Asset) u64 hash; String key; - Counter counter; + /* Asset is ready when fence >= 1 */ + Fence ready_fence; /* Managed via asset_cache_mark_x functions */ AC_Status status; diff --git a/src/base/base.h b/src/base/base.h index 4d4ff62c..9f692fa4 100644 --- a/src/base/base.h +++ b/src/base/base.h @@ -545,30 +545,37 @@ StaticAssert(alignof(Atomic32Padded) == CachelineSize && sizeof(Atomic32Padded) StaticAssert(alignof(Atomic64Padded) == CachelineSize && sizeof(Atomic64Padded) % CachelineSize == 0); #if PlatformIsWindows && ArchIsX64 +//- Memory barriers +# define CompilerMemoryBarrier() _ReadWriteBarrier() +# define HardwareMemoryBarrier() MemoryBarrier() //- 8 bit atomic operations -#define Atomic8Fetch(x) (x)->_v -#define Atomic8FetchSet(x, e) (i8)_InterlockedExchange8((volatile char *)&(x)->_v, (e)) -#define Atomic8FetchTestSet(x, c, e) (i8)_InterlockedCompareExchange8((volatile char *)&(x)->_v, (e), (c)) -#define Atomic8FetchXor(x, c) (i8)_InterlockedXor8((volatile char *)&(x)->_v, (c)) -#define Atomic8FetchAdd(x, a) (i8)_InterlockedExchangeAdd8((volatile char *)&(x)->_v, (a)) +ForceInline i8 Atomic8Fetch (Atomic8 *x) { i8 result = (x)->_v; CompilerMemoryBarrier(); return result; } +ForceInline void Atomic8Set (Atomic8 *x, i8 e) { CompilerMemoryBarrier(); (x)->_v = e; } +ForceInline i8 Atomic8FetchSet (Atomic8 *x, i8 e) { return (i8)_InterlockedExchange8((volatile char *)&(x)->_v, (e)); } +ForceInline i8 Atomic8FetchTestSet (Atomic8 *x, i8 c, i8 e) { return (i8)_InterlockedCompareExchange8((volatile char *)&(x)->_v, (e), (c)); } +ForceInline i8 Atomic8FetchXor (Atomic8 *x, i8 c) { return (i8)_InterlockedXor8((volatile char *)&(x)->_v, (c)); } +ForceInline i8 Atomic8FetchAdd (Atomic8 *x, i8 a) { return (i8)_InterlockedExchangeAdd8((volatile char *)&(x)->_v, (a)); } //- 16 bit atomic operations -#define Atomic16Fetch(x) (x)->_v -#define Atomic16FetchSet(x, e) (i16)_InterlockedExchange16(&(x)->_v, (e)) -#define Atomic16FetchTestSet(x, c, e) (i16)_InterlockedCompareExchange16(&(x)->_v, (e), (c)) -#define Atomic16FetchXor(x, c) (i16)_InterlockedXor16(&(x)->_v, (c)) -#define Atomic16FetchAdd(x, a) (i16)_InterlockedExchangeAdd16(&(x)->_v, (a)) +ForceInline i16 Atomic16Fetch (Atomic16 *x) { i16 result = (x)->_v; CompilerMemoryBarrier(); return result; } +ForceInline void Atomic16Set (Atomic16 *x, i16 e) { CompilerMemoryBarrier(); (x)->_v = e; } +ForceInline i16 Atomic16FetchSet (Atomic16 *x, i16 e) { return (i16)_InterlockedExchange16(&(x)->_v, (e)); } +ForceInline i16 Atomic16FetchTestSet (Atomic16 *x, i16 c, i16 e) { return (i16)_InterlockedCompareExchange16(&(x)->_v, (e), (c)); } +ForceInline i16 Atomic16FetchXor (Atomic16 *x, i16 c) { return (i16)_InterlockedXor16(&(x)->_v, (c)); } +ForceInline i16 Atomic16FetchAdd (Atomic16 *x, i16 a) { return (i16)_InterlockedExchangeAdd16(&(x)->_v, (a)); } //- 32 bit atomic operations -#define Atomic32Fetch(x) (x)->_v -#define Atomic32FetchSet(x, e) (i32)_InterlockedExchange((volatile long *)&(x)->_v, (e)) -#define Atomic32FetchTestSet(x, c, e) (i32)_InterlockedCompareExchange((volatile long *)&(x)->_v, (e), (c)) -#define Atomic32FetchXor(x, c) (i32)_InterlockedXor((volatile long *)&(x)->_v, (c)) -#define Atomic32FetchAdd(x, a) (i32)_InterlockedExchangeAdd((volatile long *)&(x)->_v, (a)) +ForceInline i32 Atomic32Fetch (Atomic32 *x) { i32 result = (x)->_v; CompilerMemoryBarrier(); return result; } +ForceInline void Atomic32Set (Atomic32 *x, i32 e) { CompilerMemoryBarrier(); (x)->_v = e; } +ForceInline i32 Atomic32FetchSet (Atomic32 *x, i32 e) { return (i32)_InterlockedExchange((volatile long *)&(x)->_v, (e)); } +ForceInline i32 Atomic32FetchTestSet (Atomic32 *x, i32 c, i32 e) { return (i32)_InterlockedCompareExchange((volatile long *)&(x)->_v, (e), (c)); } +ForceInline i32 Atomic32FetchXor (Atomic32 *x, i32 c) { return (i32)_InterlockedXor((volatile long *)&(x)->_v, (c)); } +ForceInline i32 Atomic32FetchAdd (Atomic32 *x, i32 a) { return (i32)_InterlockedExchangeAdd((volatile long *)&(x)->_v, (a)); } //- 64 bit atomic operations -#define Atomic64Fetch(x) (x)->_v -#define Atomic64FetchSet(x, e) (i64)_InterlockedExchange64(&(x)->_v, (e)) -#define Atomic64FetchTestSet(x, c, e) (i64)_InterlockedCompareExchange64(&(x)->_v, (e), (c)) -#define Atomic64FetchXor(x, c) (i64)_InterlockedXor64(&(x)->_v, (c)) -#define Atomic64FetchAdd(x, a) (i64)_InterlockedExchangeAdd64(&(x)->_v, (a)) +ForceInline i64 Atomic64Fetch (Atomic64 *x) { i16 result = (x)->_v; CompilerMemoryBarrier(); return result; } +ForceInline void Atomic64Set (Atomic64 *x, i64 e) { CompilerMemoryBarrier(); (x)->_v = e; } +ForceInline i64 Atomic64FetchSet (Atomic64 *x, i64 e) { return (i64)_InterlockedExchange64(&(x)->_v, (e)); } +ForceInline i64 Atomic64FetchTestSet (Atomic64 *x, i64 c, i64 e) { return (i64)_InterlockedCompareExchange64(&(x)->_v, (e), (c)); } +ForceInline i64 Atomic64FetchXor (Atomic64 *x, i64 c) { return (i64)_InterlockedXor64(&(x)->_v, (c)); } +ForceInline i64 Atomic64FetchAdd (Atomic64 *x, i64 a) { return (i64)_InterlockedExchangeAdd64(&(x)->_v, (a)); } #else # error Atomics not implemented #endif @@ -712,8 +719,8 @@ Struct(ComputeShader) { Resource resource; }; # else # error FiberId not implemented # endif -# define MaxFibers 1024 -StaticAssert(MaxFibers < I16Max); /* FiberId type should fit MaxFibers */ +# define MaxFibers 4096 +StaticAssert(MaxFibers < I16Max); /* MaxFibers should fit in FiberId */ #endif diff --git a/src/base/base_gstat.h b/src/base/base_gstat.h index db2243a7..4b553a7d 100644 --- a/src/base/base_gstat.h +++ b/src/base/base_gstat.h @@ -14,7 +14,7 @@ Struct(SharedGstatCtx) extern SharedGstatCtx _shared_gstat_ctx; -#define SetGstat(name, value) Atomic64FetchSet(&_shared_gstat_ctx.name.v, (value)) +#define SetGstat(name, value) Atomic64Set(&_shared_gstat_ctx.name.v, (value)) #define AddGstat(name, value) Atomic64FetchAdd(&_shared_gstat_ctx.name.v, (value)) #define GetGstat(name) Atomic64Fetch(&_shared_gstat_ctx.name.v) diff --git a/src/base/base_job.h b/src/base/base_job.h index 463c5961..8029e717 100644 --- a/src/base/base_job.h +++ b/src/base/base_job.h @@ -12,24 +12,24 @@ Enum(JobPool) { JobPool_Inherit = -1, - /* Contains worker threads affinitized over the entire CPU. - * Meant to take on high-bandwidth temporary work (e.g. loading a level). */ - JobPool_Hyper = 0, /* High-priority */ + /* Contains un-affinitized worker threads. + * Meant to take on temporary high-throughput work that is allowed to interfere with all other pools (e.g. loading a level). */ + JobPool_Hyper = 0, - /* Contains worker threads affinitized over the entire CPU. - * Meant to take on blocking work so that affinitized workers workers can continue doing actual work. */ - JobPool_Blocking = 1, /* Normal priority */ + /* Contains un-affinitized worker threads. + * Meant to take on blocking work so that affinitized workers can continue doing actual work. */ + JobPool_Blocking = 1, /* Contains worker threads affinitized to cores that don't interfere with workers in specialized pools. * Meant to consume asynchronous work from higher priority pools. */ - JobPool_Background = 2, /* Normal priority */ + JobPool_Background = 2, /* Contains worker threads affinitized to cores that don't interfere with workers in other specialized pools. * These pools are meant to only have work pushed onto them from jobs within the same pool (e.g. 100 jobs pushed onto the - * User pool will not interfere with cores running workers on the Sim pool). */ - JobPool_Audio = 3, /* Critical priority */ - JobPool_User = 4, /* Above-normal priority */ - JobPool_Sim = 5, /* Above-normal priority */ + * User pool will not interfere with cores running the Sim pool). */ + JobPool_Audio = 3, + JobPool_User = 4, + JobPool_Sim = 5, JobPool_Count }; @@ -37,26 +37,29 @@ Enum(JobPool) //////////////////////////////// //~ Job types +typedef void JobFunc(void *, i32); + Struct(JobCounter) { - Fence jobs_completed_fence; Atomic64Padded num_jobs_dispatched; + Fence num_jobs_completed_fence; }; -typedef void JobFunc(void *, i32); - Struct(Job) { + /* Internal */ Job *next; + Atomic32Padded num_tasks_completed; + /* Initialized & constant after OpenJob */ Arena *arena; JobFunc *func; JobPool pool; + + /* Configurable between OpenJob & CloseJob */ i32 count; JobCounter *counter; void *sig; - - Atomic64Padded num_tasks_completed; }; //////////////////////////////// @@ -112,4 +115,4 @@ do { Job *OpenJob(JobFunc *func, JobPool pool_kind); void CloseJob(Job *job); -#define YieldOnJobs(counter) (YieldOnFence(&(counter)->jobs_completed_fence, Atomic64Fetch(&(counter)->num_jobs_dispatched.v))) +#define YieldOnJobs(counter) (YieldOnFence(&(counter)->num_jobs_completed_fence, Atomic64Fetch(&(counter)->num_jobs_dispatched.v))) diff --git a/src/base/base_snc.c b/src/base/base_snc.c index a65f8552..1235b310 100644 --- a/src/base/base_snc.c +++ b/src/base/base_snc.c @@ -56,7 +56,7 @@ Lock LockSpinE(Mutex *m, i32 spin) } #if RtcIsEnabled - Atomic32FetchSet(&m->exclusive_fiber_id, FiberId()); + Atomic32Set(&m->exclusive_fiber_id, FiberId()); #endif Lock lock = ZI; @@ -123,9 +123,9 @@ void Unlock(Lock *l) if (l->exclusive) { #if RtcIsEnabled - Atomic32FetchSet(&m->exclusive_fiber_id, 0); + Atomic32Set(&m->exclusive_fiber_id, 0); #endif - Atomic32FetchSet(&m->v, 0); + Atomic32Set(&m->v, 0); } else { @@ -165,34 +165,6 @@ void SignalCv(Cv *cv) FutexWakeNeq(&cv->wake_gen); } -//////////////////////////////// -//~ Counter - -i64 ValueFromCounter(Counter *counter) -{ - return Atomic64Fetch(&counter->v); -} - -void AddCounter(Counter *counter, i64 x) -{ - i64 old_v = Atomic64FetchAdd(&counter->v, x); - i64 new_v = old_v + x; - if (old_v > 0 && new_v <= 0) - { - FutexWakeNeq(&counter->v); - } -} - -void YieldOnCounter(Counter *counter) -{ - i64 v = Atomic64Fetch(&counter->v); - while (v > 0) - { - FutexYieldNeq(&counter->v, &v, sizeof(v)); - v = Atomic64Fetch(&counter->v); - } -} - //////////////////////////////// //~ Fence @@ -201,13 +173,16 @@ i64 FetchFence(Fence *fence) return Atomic64Fetch(&fence->v.v); } +void SetFence(Fence *fence, i64 x) +{ + Atomic64Set(&fence->v.v, x); + FutexWakeGte(&fence->v.v); +} + i64 FetchSetFence(Fence *fence, i64 x) { i64 fetch = Atomic64FetchSet(&fence->v.v, x); - if (x > fetch) - { - FutexWakeGte(&fence->v.v); - } + FutexWakeGte(&fence->v.v); return fetch; } diff --git a/src/base/base_snc.h b/src/base/base_snc.h index 94cd1740..8f34de40 100644 --- a/src/base/base_snc.h +++ b/src/base/base_snc.h @@ -32,15 +32,6 @@ AlignedStruct(Cv, CachelineSize) }; StaticAssert(alignof(Cv) == CachelineSize && sizeof(Cv) % CachelineSize == 0); -//////////////////////////////// -//~ Counter types - -AlignedStruct(Counter, CachelineSize) -{ - Atomic64 v; -}; -StaticAssert(alignof(Counter) == CachelineSize && sizeof(Counter) % CachelineSize == 0); - //////////////////////////////// //~ Fence types @@ -75,17 +66,11 @@ void Unlock(Lock *lock); void YieldOnCv(Cv *cv, Lock *lock); void SignalCv(Cv *cv); -//////////////////////////////// -//~ Counter operations - -i64 ValueFromCounter(Counter *counter); -void AddCounter(Counter *counter, i64 x); -void YieldOnCounter(Counter *counter); - //////////////////////////////// //~ Fence operations i64 FetchFence(Fence *fence); +void SetFence(Fence *fence, i64 x); i64 FetchSetFence(Fence *fence, i64 x); i64 FetchAddFence(Fence *fence, i64 x); diff --git a/src/base/base_win32/base_win32.c b/src/base/base_win32/base_win32.c index 1f316da4..46d109ba 100644 --- a/src/base/base_win32/base_win32.c +++ b/src/base/base_win32/base_win32.c @@ -123,7 +123,7 @@ void OnExit(ExitFunc *func) void SignalExit(i32 code) { W32_SharedState *g = &W32_shared_state; - Atomic32FetchSet(&g->exit_code, code); + Atomic32Set(&g->exit_code, code); SetEvent(g->exit_begin_event); } @@ -241,13 +241,7 @@ i32 W32_Main(void) } #endif - /* Set up exit events */ - g->panic_event = CreateEventW(0, 1, 0, 0); - g->startup_end_event = CreateEventW(0, 1, 0, 0); - g->exit_begin_event = CreateEventW(0, 1, 0, 0); - g->exit_end_event = CreateEventW(0, 1, 0, 0); - - /* Query performance frequency */ + /* Init time */ { LARGE_INTEGER qpf; QueryPerformanceFrequency(&qpf); @@ -259,6 +253,12 @@ i32 W32_Main(void) g->timer_start_qpc = qpc.QuadPart; } + /* Set up exit events */ + g->panic_event = CreateEventW(0, 1, 0, 0); + g->startup_end_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->main_thread_id = GetCurrentThreadId(); SetThreadDescription(GetCurrentThread(), L"Main thread"); diff --git a/src/base/base_win32/base_win32_job.c b/src/base/base_win32/base_win32_job.c index 777ecff6..11c2a15d 100644 --- a/src/base/base_win32/base_win32_job.c +++ b/src/base/base_win32/base_win32_job.c @@ -187,19 +187,6 @@ void W32_WaitEndThread(W32_Thread *thread) Assert(success); } -//////////////////////////////// -//~ Pool operations - -W32_JobPool *W32_JobPoolFromKind(JobPool pool_kind) -{ - if (pool_kind == JobPool_Inherit) - { - W32_Fiber *fiber = W32_FiberFromId(FiberId()); - pool_kind = fiber->pool; - } - return &W32_shared_job_state.job_pools[pool_kind]; -} - //////////////////////////////// //~ Win32 fiber @@ -334,7 +321,7 @@ void W32_FiberEntryPoint(void *win32_fiber_data) { i16 fiber_id = (i16)(i64)win32_fiber_data; volatile W32_Fiber *fiber = W32_FiberFromId(fiber_id); - W32_JobPool *pool = W32_JobPoolFromKind(fiber->pool); + W32_JobPool *pool = &W32_shared_job_state.job_pools[fiber->pool]; JobPool pool_kind = fiber->pool; char *fiber_name_cstr = fiber->name_cstr; for (;;) @@ -349,10 +336,10 @@ void W32_FiberEntryPoint(void *win32_fiber_data) /* Check if we've completed the last task in the job */ if (Atomic32FetchAdd(&job->num_tasks_completed.v, 1) + 1 >= job->count) { - /* Increment fence */ + /* Increment counter */ if (job->counter) { - FetchAddFence(&job->counter->jobs_completed_fence, 1); + FetchAddFence(&job->counter->num_jobs_completed_fence, 1); } /* Free job */ LockTicketMutex(&pool->free_jobs_tm); @@ -387,7 +374,7 @@ W32_ThreadDef(W32_JobWorkerEntryFunc, worker_ctx_arg) { W32_WorkerCtx *ctx = worker_ctx_arg; JobPool pool_kind = ctx->pool_kind; - W32_JobPool *pool = W32_JobPoolFromKind(pool_kind); + W32_JobPool *pool = &W32_shared_job_state.job_pools[pool_kind]; i16 worker_fiber_id = FiberId(); @@ -514,7 +501,7 @@ void SuspendFiber(void) Assert(parent_fiber->id > 0); { __prof_fiber_leave(); - Atomic8FetchSet(&fiber->is_suspending, 1); + Atomic8Set(&fiber->is_suspending, 1); W32_SwitchToFiber(parent_fiber); __prof_fiber_enter(fiber->name_cstr, PROF_THREAD_GROUP_FIBERS - Mebi(fiber->pool) + Kibi(1) + fiber->id); } @@ -584,7 +571,12 @@ void ResumeFibers(i16 fiber_ids_count, i16 *fiber_ids) Job *OpenJob(JobFunc *func, JobPool pool_kind) { - W32_JobPool *pool = W32_JobPoolFromKind(pool_kind); + if (pool_kind == JobPool_Inherit) + { + W32_Fiber *fiber = W32_FiberFromId(FiberId()); + pool_kind = fiber->pool; + } + W32_JobPool *pool = &W32_shared_job_state.job_pools[pool_kind]; Job *job = 0; { Arena *job_arena = 0; @@ -621,7 +613,7 @@ void CloseJob(Job *job) { TempArena scratch = BeginScratchNoConflict(); - W32_JobPool *pool = W32_JobPoolFromKind(job->pool); + W32_JobPool *pool = &W32_shared_job_state.job_pools[job->pool]; u32 num_tasks = job->count; if (num_tasks > 0) @@ -684,7 +676,6 @@ void CloseJob(Job *job) { LockTicketMutex(&pool->tasks_tm); { - // QueuePush(pool->first_task, pool->last_task, tasks.first); if (pool->last_task) { pool->last_task->next = tasks.first; diff --git a/src/base/base_win32/base_win32_job.h b/src/base/base_win32/base_win32_job.h index c03b39fa..08e84f47 100644 --- a/src/base/base_win32/base_win32_job.h +++ b/src/base/base_win32/base_win32_job.h @@ -178,11 +178,6 @@ W32_Thread *W32_StartThread(W32_ThreadFunc *entry_point, void *thread_udata, Str b32 W32_TryEndThread(W32_Thread *thread, f32 timeout_seconds); void W32_WaitEndThread(W32_Thread *thread); -//////////////////////////////// -//~ Pool operations - -W32_JobPool *W32_JobPoolFromKind(JobPool pool_kind); - //////////////////////////////// //~ Fiber operations diff --git a/src/gpu/gpu.h b/src/gpu/gpu.h index f09fbf47..0bf604f3 100644 --- a/src/gpu/gpu.h +++ b/src/gpu/gpu.h @@ -283,7 +283,7 @@ GPU_Fence GPU_GetGlobalFence(void); //~ @hookdecl Resource operations GPU_Resource *GPU_AcquireResource(GPU_ResourceDesc desc); -void GPU_ReleaseResource(GPU_Resource *resource, GPU_Fence fence, GPU_ReleaseFlag flags); +void GPU_ReleaseResource(GPU_Resource *resource, GPU_ReleaseFlag flags); u32 GPU_GetResourceId(GPU_Resource *resource); Vec2I32 GPU_GetTextureSize(GPU_Resource *resource); diff --git a/src/gpu/gpu_dx12/gpu_dx12.c b/src/gpu/gpu_dx12/gpu_dx12.c index db12e920..cf202471 100644 --- a/src/gpu/gpu_dx12/gpu_dx12.c +++ b/src/gpu/gpu_dx12/gpu_dx12.c @@ -110,7 +110,7 @@ GPU_Resource *GPU_AcquireResource(GPU_ResourceDesc desc) return 0; } -void GPU_ReleaseResource(GPU_Resource *resource, GPU_Fence fence, GPU_ReleaseFlag flags) +void GPU_ReleaseResource(GPU_Resource *resource, GPU_ReleaseFlag flags) { /* TODO */ } diff --git a/src/meta/meta.c b/src/meta/meta.c index cf3b418f..67636fd8 100644 --- a/src/meta/meta.c +++ b/src/meta/meta.c @@ -529,6 +529,7 @@ JobDef(Step, sig, id) ++i; } } + JobCounter counter = ZI; RunJob(RunCommand, .count = shader_entries_count, @@ -1098,7 +1099,7 @@ JobDef(Build, _, __) EchoLine(msg); } - + EchoLine(StringF(arena, "Runtime: %Fs", FmtFloat(SecondsFromNs(TimeNs())))); ExitNow(ret); } diff --git a/src/platform/platform_log.c b/src/platform/platform_log.c index b8d0767b..930faed3 100644 --- a/src/platform/platform_log.c +++ b/src/platform/platform_log.c @@ -21,7 +21,7 @@ void P_StartupLog(void) ctx->file_valid = 1; } } - Atomic32FetchSet(&ctx->initialized, 1); + Atomic32Set(&ctx->initialized, 1); } //////////////////////////////// diff --git a/src/platform/platform_win32/platform_win32.c b/src/platform/platform_win32/platform_win32.c index 114e71fd..030d8880 100644 --- a/src/platform/platform_win32/platform_win32.c +++ b/src/platform/platform_win32/platform_win32.c @@ -183,9 +183,8 @@ P_W32_Window *P_W32_AcquireWindow(void) /* NOTE: This thread must finish building for the window to actually be * created and receive a HWND, because on Windows a the event proc must run on * the same thread that created the window. */ - AddCounter(&window->ready_fence, 1); window->window_thread = W32_StartThread(&P_W32_WindowThreadEntryFunc, window, Lit("Window thread"), PROF_THREAD_GROUP_WINDOW); - YieldOnCounter(&window->ready_fence); + YieldOnFence(&window->ready_fence, 1); return window; } @@ -193,7 +192,7 @@ P_W32_Window *P_W32_AcquireWindow(void) void P_W32_ReleaseWindow(P_W32_Window *window) { /* Stop window threads */ - Atomic32FetchSet(&window->shutdown, 1); + Atomic32Set(&window->shutdown, 1); P_W32_SharedState *g = &P_W32_shared_state; P_W32_WakeWindow(window); W32_WaitEndThread(window->window_thread); @@ -400,7 +399,7 @@ W32_ThreadDef(P_W32_WindowThreadEntryFunc, arg) window->hwnd = P_W32_InitWindow(window); P_W32_UpdateWindowFromSystem(window); BringWindowToTop(window->hwnd); - AddCounter(&window->ready_fence, -1); + SetFence(&window->ready_fence, 1); while (!Atomic32Fetch(&window->shutdown)) { @@ -887,14 +886,13 @@ JobDef(P_W32_UpdateTimer, _, __) periods[i] = P_W32_DefaultTimerPeriodNs; } - Echo(Lit("Starting timer\n")); - i64 last_cycle_ns = 0; /* FIXME: shutdown */ for (;;) { __profn("Job scheduler cycle"); { + /* TODO: Minimum timer frequency in case windows timers ever become ultra precise in the future */ __profn("Job scheduler wait"); LARGE_INTEGER due = ZI; due.QuadPart = -1; @@ -922,11 +920,11 @@ JobDef(P_W32_UpdateTimer, _, __) periods_sum_ns += (f64)periods[i]; } f64 mean_ns = periods_sum_ns / (f64)countof(periods); - Atomic64FetchSet(&g->average_timer_period_ns.v, RoundF64ToI64(mean_ns)); + Atomic64Set(&g->average_timer_period_ns.v, RoundF64ToI64(mean_ns)); } /* Update fence */ - FetchSetFence(&g->timer_fence, now_ns); + SetFence(&g->timer_fence, now_ns); } } diff --git a/src/platform/platform_win32/platform_win32.h b/src/platform/platform_win32/platform_win32.h index 560a2cd7..4c05d1d3 100644 --- a/src/platform/platform_win32/platform_win32.h +++ b/src/platform/platform_win32/platform_win32.h @@ -41,7 +41,7 @@ Struct(P_W32_Window) u32 flags; HWND hwnd; - Counter ready_fence; + Fence ready_fence; u16 utf16_high_surrogate_last_input; diff --git a/src/playback/playback_wasapi/playback_wasapi.c b/src/playback/playback_wasapi/playback_wasapi.c index 3f2e75f7..ae58210a 100644 --- a/src/playback/playback_wasapi/playback_wasapi.c +++ b/src/playback/playback_wasapi/playback_wasapi.c @@ -23,7 +23,7 @@ ExitFuncDef(PB_WSP_Shutdown) { __prof; PB_WSP_SharedState *g = &PB_WSP_shared_state; - Atomic32FetchSet(&g->shutdown, 1); + Atomic32Set(&g->shutdown, 1); YieldOnJobs(&g->shutdown_job_counter); } diff --git a/src/pp/pp.c b/src/pp/pp.c index 5e9fcb7e..0ddfa80a 100644 --- a/src/pp/pp.c +++ b/src/pp/pp.c @@ -60,7 +60,7 @@ ExitFuncDef(ShutdownUser) { __prof; SharedUserState *g = &shared_user_state; - Atomic32FetchSet(&g->shutdown, 1); + Atomic32Set(&g->shutdown, 1); YieldOnJobs(&g->shutdown_job_counter); P_ReleaseWindow(g->window); } @@ -2149,12 +2149,13 @@ void UpdateUser(P_Window *window) if (g->shade_target && !EqVec2I32(g->render_size, GPU_GetTextureSize(g->shade_target))) { __profn("Release render resources"); - GPU_ReleaseResource(g->albedo, g->render_fence, GPU_ReleaseFlag_None); - GPU_ReleaseResource(g->emittance, g->render_fence, GPU_ReleaseFlag_None); - GPU_ReleaseResource(g->emittance_flood_read, g->render_fence, GPU_ReleaseFlag_None); - GPU_ReleaseResource(g->emittance_flood_target, g->render_fence, GPU_ReleaseFlag_None); - GPU_ReleaseResource(g->shade_read, g->render_fence, GPU_ReleaseFlag_None); - GPU_ReleaseResource(g->shade_target, g->render_fence, GPU_ReleaseFlag_None); + /* FIXME: Yield on render fence */ + GPU_ReleaseResource(g->albedo, GPU_ReleaseFlag_None); + GPU_ReleaseResource(g->emittance, GPU_ReleaseFlag_None); + GPU_ReleaseResource(g->emittance_flood_read, GPU_ReleaseFlag_None); + GPU_ReleaseResource(g->emittance_flood_target, GPU_ReleaseFlag_None); + GPU_ReleaseResource(g->shade_read, GPU_ReleaseFlag_None); + GPU_ReleaseResource(g->shade_target, GPU_ReleaseFlag_None); g->shade_target = 0; } if (!g->shade_target) @@ -2171,7 +2172,8 @@ void UpdateUser(P_Window *window) /* Acquire ui buffers */ if (g->ui_target && !EqVec2I32(g->ui_size, GPU_GetTextureSize(g->ui_target))) { - GPU_ReleaseResource(g->ui_target, g->render_fence, GPU_ReleaseFlag_None); + /* FIXME: Wait on render fence */ + GPU_ReleaseResource(g->ui_target, GPU_ReleaseFlag_None); g->ui_target = 0; } if (!g->ui_target) @@ -2416,16 +2418,34 @@ void UpdateUser(P_Window *window) GPU_RasterizeMode_TriangleList); } } - g->render_fence = GPU_EndCommandList(cl); + + /* FIXME: Enable this */ +#if 0 + g->most_recent_render_counter = GPU_EndCommandList(cl); /* Release transfer buffers */ { - GPU_ReleaseResource(quad_index_buffer, g->render_fence, GPU_ReleaseFlag_Reuse); - GPU_ReleaseResource(material_instance_buffer, g->render_fence, GPU_ReleaseFlag_Reuse); - GPU_ReleaseResource(ui_rect_instance_buffer, g->render_fence, GPU_ReleaseFlag_Reuse); - GPU_ReleaseResource(ui_shape_verts_buffer, g->render_fence, GPU_ReleaseFlag_Reuse); - GPU_ReleaseResource(ui_shape_indices_buffer, g->render_fence, GPU_ReleaseFlag_Reuse); - GPU_ReleaseResource(grids_buffer, g->render_fence, GPU_ReleaseFlag_Reuse); + { + /* FIXME: Release resources */ + GPU_Resource *release_resources[] = { + quad_index_buffer, + material_instance_buffer, + ui_rect_instance_buffer, + ui_shape_verts_buffer, + ui_shape_indices_buffer, + }; + Job *job = OpenJob(ReleaseRenderResources); + { + ReleaseRenderResources_Sig *sig = PushStruct(job->arena, ReleaseRenderResources_Sig); + job->count = countof(resources); + sig->render_counter = g->most_recent_render_counter; + sig->resources = PushStructsNoZero(sig->arena, GPU_Resource *, job->count); + sig->flags = GPU_ReleaseFlag_Reuse; + CopyBytes(sig->resources, resources, sizeof(resources)); + job->sig = sig; + } + CloseJob(job); + } ResetArena(g->material_instances_arena); ResetArena(g->ui_rect_instances_arena); ResetArena(g->ui_shape_verts_arena); @@ -2437,6 +2457,7 @@ void UpdateUser(P_Window *window) g->ui_shape_indices_count = 0; g->grids_count = 0; } +#endif } EndScratch(scratch); @@ -2459,7 +2480,7 @@ JobDef(UpdateUserOrSleep, UNUSED sig, UNUSED id) GPU_WaitOnSwapchain(g->swapchain); } { - __profn("Frame limiter wait");; + __profn("Frame limiter wait"); P_SleepFrame(time_ns, 1000000000 / FPS_LIMIT); time_ns = TimeNs(); } diff --git a/src/sprite/sprite.c b/src/sprite/sprite.c index df618b87..c95ca2db 100644 --- a/src/sprite/sprite.c +++ b/src/sprite/sprite.c @@ -36,7 +36,7 @@ JobDef(S_LoadTexture, sig, _) } texture->loaded = 1; - AddCounter(&entry->texture_load_counter, -1); + SetFence(&entry->texture_ready_fence, 1); EndScratch(scratch); } @@ -224,7 +224,7 @@ JobDef(S_LoadSheet, sig, _) } sheet->loaded = 1; - AddCounter(&entry->sheet_load_counter, -1); + SetFence(&entry->sheet_ready_fence, 1); EndScratch(scratch); } @@ -273,8 +273,6 @@ S_Entry *S_FetchEntry(Resource resource, JobPool pool, S_FetchFlag flags) Arena *perm = PermArena(); entry = PushStruct(perm, S_Entry); entry->resource = resource; - AddCounter(&entry->texture_load_counter, 1); - AddCounter(&entry->sheet_load_counter, 1); QueuePushN(bin->first, bin->last, entry, next_in_bin); } } @@ -303,7 +301,7 @@ S_Entry *S_FetchEntry(Resource resource, JobPool pool, S_FetchFlag flags) S_Texture *S_TextureFromResource(Resource resource) { S_Entry *entry = S_FetchEntry(resource, JobPool_Inherit, S_FetchFlag_Texture); - YieldOnCounter(&entry->texture_load_counter); + YieldOnFence(&entry->texture_ready_fence, 1); return &entry->texture; } @@ -311,7 +309,7 @@ S_Texture *S_TextureFromResourceAsync(Resource resource) { S_Texture *result = &S_NilTexture; S_Entry *entry = S_FetchEntry(resource, JobPool_Inherit, S_FetchFlag_Texture); - if (ValueFromCounter(&entry->texture_load_counter) <= 0) + if (FetchFence(&entry->texture_ready_fence) >= 1) { result = &entry->texture; } @@ -321,7 +319,7 @@ S_Texture *S_TextureFromResourceAsync(Resource resource) S_Sheet *S_SheetFromResource(Resource resource) { S_Entry *entry = S_FetchEntry(resource, JobPool_Inherit, S_FetchFlag_Sheet); - YieldOnCounter(&entry->sheet_load_counter); + YieldOnFence(&entry->sheet_ready_fence, 1); return &entry->sheet; } @@ -329,7 +327,7 @@ S_Sheet *S_SheetFromResourceAsync(Resource resource) { S_Sheet *result = &S_NilSheet; S_Entry *entry = S_FetchEntry(resource, JobPool_Inherit, S_FetchFlag_Sheet); - if (ValueFromCounter(&entry->sheet_load_counter) <= 0) + if (FetchFence(&entry->sheet_ready_fence) >= 1) { result = &entry->sheet; } diff --git a/src/sprite/sprite.h b/src/sprite/sprite.h index 8238ab3b..2dffb9a4 100644 --- a/src/sprite/sprite.h +++ b/src/sprite/sprite.h @@ -109,8 +109,8 @@ Struct(S_Entry) Atomic32 sheet_touched; Resource resource; - Counter texture_load_counter; - Counter sheet_load_counter; + Fence texture_ready_fence; + Fence sheet_ready_fence; }; Struct(S_EntryBin)