diff --git a/src/base/base_job.h b/src/base/base_job.h index e5af11f5..23333a63 100644 --- a/src/base/base_job.h +++ b/src/base/base_job.h @@ -1,63 +1,28 @@ -//////////////////////////////////////////////////////////// -//~ Opaque types - -Struct(Job); - //////////////////////////////////////////////////////////// //~ Job pool types -/* Job pools contain worker threads with their own thread priorities - * and affinities based on the intended context of the pool. */ -Enum(JobPool) +typedef i32 JobPoolId; + +Enum(JobPoolPriority) { - JobPool_Inherit = -1, - - /* Contains un-affinitized worker threads. - * Meant to take on temporary high-throughput work that is allowed to - * interfere with all other pools (e.g. program startup, loading a level, - * etc). */ - JobPool_Hyper = 0, - - /* 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 = 1, - - /* 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 the Sim pool). */ - JobPool_Audio = 2, - JobPool_User = 3, - JobPool_Sim = 4, - - JobPool_Count + JobPoolPriority_Background, + JobPoolPriority_Async, + JobPoolPriority_Graphics, + JobPoolPriority_Simulation, + JobPoolPriority_Critical, + JobPoolPriority_Audio, }; //////////////////////////////////////////////////////////// //~ Job types +Struct(Job); + typedef void JobFunc(void *, i32); Enum(JobFlag) { - JobFlag_None = 0, - - /* A dedicated job is a heavy weight job that will receive its own OS - * thread and will never yield. When the fiber running the job suspends - * itself, the dedicated thread will perform a blocking wait rather than - * yielding the thread to another fiber. This is mainly useful for - * long-running dispatcher-esque jobs that block on OS primitives, since - * occupying a worker thread (and thereby preventing non-blocking jobs from - * running on that worker) is unwanted. - * - * For example, Win32 window message processing is required by the OS to - * occur on the same thread that initially created the window, which means - * it actually must run inside a dedicated job to prevent message processing - * from yielding & resuming on another thread. The message processing loop - * can block until messages are received from the OS without having to - * occupy a job worker while it blocks, and can then schedule yielded - * jobs onto job worker pools based on the processed messages. - */ - JobFlag_Dedicated = (1 << 0), + JobFlag_None = (0), }; Struct(Job) @@ -69,12 +34,12 @@ Struct(Job) /* Initialized & constant after OpenJob */ Arena *arena; JobFunc *func; - JobPool pool; + JobPoolId pool; /* Configurable between OpenJob & CloseJob */ - JobFlag flags; i32 count; Fence *fence; + JobFlag flags; void *sig; }; @@ -89,15 +54,35 @@ void InitJobSystem(void); void SuspendFiber(void); void ResumeFibers(i16 fiber_ids_count, i16 *fiber_ids); /* NOTE: Must only be called on fibers suspended via SuspendFiber */ +//////////////////////////////////////////////////////////// +//~ @hookdecl Job pool operations + +JobPoolId InitJobPool(u32 thread_count, String name, JobPoolPriority priority); + +//- Default job pools + +/* The current job pool */ +JobPoolId CurrentPool(void); + +/* Contains high-priority workers that span the entire CPU. + * Meant to take on temporary high-throughput work that is allowed to + * steal performance from all other pools (e.g. program startup, loading a level, + * etc). */ +JobPoolId HyperPool(void); + +/* Contains lower-priority workers affinitized to not interfere with workers in other pools. + * Meant to consume asynchronous work from higher priority pools. */ +JobPoolId AsyncPool(void); + //////////////////////////////////////////////////////////// //~ @hookdecl Job declaration operations #define EmptySig { i32 _; } -#define JobDecl(job, sigdef) \ - typedef struct job##_Sig sigdef job##_Sig; \ - Struct(job##_Desc) { JobFunc *func; JobPool pool; u32 count; Fence *fence; JobFlag flags; job##_Sig sig; }; \ - void job(job##_Sig *, i32); \ +#define JobDecl(job, sigdef) \ + typedef struct job##_Sig sigdef job##_Sig; \ + Struct(job##_Desc) { JobFunc *func; JobPoolId pool; u32 count; Fence *fence; JobFlag flags; job##_Sig sig; }; \ + void job(job##_Sig *, i32); \ StaticAssert(1) #define JobDef(job, sig_arg, id_arg) void job(job##_Sig *sig_arg, i32 id_arg) @@ -121,7 +106,7 @@ void ResumeFibers(i16 fiber_ids_count, i16 *fiber_ids); /* NOTE: Must only be c */ #define RunJob(job_func, ...) (1); \ do { \ - job_func##_Desc __desc = { .count = 1, .pool = JobPool_Inherit, .func = job_func, __VA_ARGS__ }; \ + job_func##_Desc __desc = { .count = 1, .pool = CurrentPool(), .func = job_func, __VA_ARGS__ }; \ Job *__job = OpenJob(__desc.func, __desc.pool); \ __job->count = __desc.count; \ __job->fence = __desc.fence; \ @@ -131,5 +116,5 @@ do { CloseJob(__job); \ } while (0) -Job *OpenJob(JobFunc *func, JobPool pool_kind); +Job *OpenJob(JobFunc *func, JobPoolId pool_kind); u32 CloseJob(Job *job); diff --git a/src/base/base_win32/base_win32_job.c b/src/base/base_win32/base_win32_job.c index 8259563d..4c0a0680 100644 --- a/src/base/base_win32/base_win32_job.c +++ b/src/base/base_win32/base_win32_job.c @@ -11,78 +11,13 @@ void InitJobSystem(void) W32_AcquireFiber(0); /* Convert main thread to fiber */ Arena *perm = PermArena(); - /* Init job pools */ - for (JobPool pool_kind = 0; pool_kind < (i32)countof(g->job_pools); ++pool_kind) - { - W32_JobPool *pool = &g->job_pools[pool_kind]; - /* FIXME */ - } + /* TODO: Dynamic thread counts */ + g->hyper_pool = InitJobPool(8, Lit("Hyper"), JobPoolPriority_Critical); + g->async_pool = InitJobPool(8, Lit("Async"), JobPoolPriority_Async); - //- Start job workers - /* TODO: Heuristic worker counts & affinities */ - { - __profn("Start job workers"); - for (JobPool pool_kind = 0; pool_kind < (i32)countof(g->job_pools); ++pool_kind) - { - W32_JobPool *pool = &g->job_pools[pool_kind]; - String name_fmt = ZI; - i32 prof_group = PROF_THREAD_GROUP_FIBERS - Mebi(pool_kind); - switch (pool_kind) - { - case JobPool_Sim: - { - name_fmt = Lit("Sim worker #%F"); - pool->num_worker_threads = 4; - pool->thread_affinity_mask = 0x000000000000000Full; - pool->thread_priority = THREAD_PRIORITY_ABOVE_NORMAL; - } break; - - case JobPool_User: - { - name_fmt = Lit("User worker #%F"); - pool->num_worker_threads = 4; - pool->thread_affinity_mask = 0x00000000000000F0ull; - pool->thread_priority = THREAD_PRIORITY_ABOVE_NORMAL; - } break; - - case JobPool_Audio: - { - name_fmt = Lit("Audio worker #%F"); - pool->num_worker_threads = 2; - pool->thread_affinity_mask = 0x0000000000000300ull; - pool->thread_priority = THREAD_PRIORITY_TIME_CRITICAL; - pool->thread_is_audio = 1; - } break; - - case JobPool_Background: - { - name_fmt = Lit("Background worker #%F"); - pool->num_worker_threads = 2; - pool->thread_affinity_mask = 0x0000000000000C00ull; - pool->thread_priority = THREAD_PRIORITY_NORMAL; - } break; - - case JobPool_Hyper: - { - name_fmt = Lit("Hyper worker #%F"); - pool->num_worker_threads = 8; - pool->thread_priority = THREAD_PRIORITY_HIGHEST; - } break; - } - pool->worker_threads = PushStructs(perm, W32_Thread *, pool->num_worker_threads); - pool->worker_contexts = PushStructs(perm, W32_WorkerCtx, pool->num_worker_threads); - for (i32 i = 0; i < pool->num_worker_threads; ++i) - { - W32_WorkerCtx *ctx = &pool->worker_contexts[i]; - ctx->pool_kind = pool_kind; - ctx->id = i; - String name = FormatString(perm, name_fmt, FmtSint(i)); - pool->worker_threads[i] = W32_StartThread(W32_JobWorkerEntryPoint, ctx, name, prof_group + i); - } - } - } - - //OnExit(ShutdownJobs); + /* Ensure hyper pool has id 0. + * Pool ID 0 will be used when pushing a job from outside a pool (e.g. during startup) */ + Assert(g->hyper_pool == 0); } //////////////////////////////////////////////////////////// @@ -266,7 +201,7 @@ W32_Fiber *W32_AcquireFiber(W32_JobPool *pool) if (pool != 0) { __profn("CreateFiber"); - fiber->pool = pool->kind; + fiber->pool = pool->id; #if VIRTUAL_FIBERS fiber->addr = CreateThread(0, W32_FiberStackSize, W32_VirtualFiberEntryPoint, (void *)(i64)fiber_id, 0, 0); #else @@ -338,9 +273,9 @@ void W32_FiberEntryPoint(void *_) i16 fiber_id = FiberId(); volatile W32_Fiber *fiber = W32_FiberFromId(fiber_id); W32_JobPool *pool = &W32_shared_job_state.job_pools[fiber->pool]; - JobPool pool_kind = fiber->pool; + JobPoolId pool_id = fiber->pool; char *fiber_name_cstr = fiber->name_cstr; - __prof_fiber_enter(fiber_name_cstr, PROF_THREAD_GROUP_FIBERS - Mebi(pool_kind) + Kibi(1) + fiber->id); + __prof_fiber_enter(fiber_name_cstr, PROF_THREAD_GROUP_FIBERS - Mebi(pool_id) + Kibi(1) + fiber->id); for (;;) { W32_Task *task = fiber->task; @@ -404,54 +339,49 @@ DWORD WINAPI W32_VirtualFiberEntryPoint(LPVOID arg) W32_ThreadDef(W32_JobWorkerEntryPoint, worker_ctx_arg) { W32_WorkerCtx *ctx = worker_ctx_arg; - JobPool pool_kind = ctx->pool_kind; - W32_JobPool *pool = &W32_shared_job_state.job_pools[pool_kind]; + JobPoolId pool_id = ctx->pool_id; + W32_JobPool *pool = &W32_shared_job_state.job_pools[pool_id]; i16 worker_fiber_id = FiberId(); { - /* TODO: Heuristic pinning */ - /* TODO: Pin non-worker threads to other cores */ + /* TODO: Set win32 IO priority as well */ HANDLE thread_handle = GetCurrentThread(); - -#if 0 - if (pool->thread_priority != 0) + switch (pool->priority) { - __profn("Set priority"); - b32 ok = SetThreadPriority(thread_handle, pool->thread_priority) != 0; - Assert(ok); - } -#endif - -#if 0 - if (pool->thread_affinity_mask) - { - __profn("Set affinity"); - b32 ok = SetThreadAffinityMask(thread_handle, pool->thread_affinity_mask) != 0; -#if RtcIsEnabled || ProfilingIsEnabled + case JobPoolPriority_Background: { - /* Retry until external tools can set correct process affinity */ - i32 delay_ms = 16; - while (!ok && delay_ms <= 1024) - { - __profn("Affinity retry"); - Sleep(delay_ms); - ok = SetThreadAffinityMask(thread_handle, pool->thread_affinity_mask) != 0; - delay_ms *= 2; - } - } -#endif - Assert(ok); - } -#endif + SetThreadPriority(thread_handle, THREAD_PRIORITY_BELOW_NORMAL); + } break; - if (pool->thread_is_audio) - { - /* https://learn.microsoft.com/en-us/windows/win32/procthread/multimedia-class-scheduler-service#registry-settings */ - __profn("Set mm thread characteristics"); - DWORD task = 0; - HANDLE mmc_handle = AvSetMmThreadCharacteristics(L"Pro Audio", &task); - Assert(mmc_handle); + case JobPoolPriority_Async: + { + SetThreadPriority(thread_handle, THREAD_PRIORITY_NORMAL); + } break; + + case JobPoolPriority_Graphics: + { + SetThreadPriority(thread_handle, THREAD_PRIORITY_ABOVE_NORMAL); + } break; + + case JobPoolPriority_Simulation: + { + SetThreadPriority(thread_handle, THREAD_PRIORITY_HIGHEST); + } break; + + case JobPoolPriority_Critical: + { + SetThreadPriority(thread_handle, THREAD_PRIORITY_HIGHEST); + } break; + + case JobPoolPriority_Audio: + { + /* https://learn.microsoft.com/en-us/windows/win32/procthread/multimedia-class-scheduler-service#registry-settings */ + __profn("Set mm thread characteristics"); + DWORD task = 0; + AvSetMmThreadCharacteristics(L"Pro Audio", &task); + SetThreadPriority(thread_handle, THREAD_PRIORITY_TIME_CRITICAL); + } } } @@ -546,8 +476,12 @@ void SuspendFiber(void) void ResumeFibers(i16 fiber_ids_count, i16 *fiber_ids) { __prof; + TempArena scratch = BeginScratchNoConflict(); + W32_SharedJobState *g = &W32_shared_job_state; + i32 num_pools = Atomic32Fetch(&g->num_pools); + /* Group tasks by pool */ - W32_TaskList tasks_by_pool[JobPool_Count] = ZI; + W32_TaskList *tasks_by_pool = PushStructs(scratch.arena, W32_TaskList, num_pools); for (i16 id_index = 0; id_index < fiber_ids_count; ++id_index) { i16 fiber_id = fiber_ids[id_index]; @@ -565,7 +499,8 @@ void ResumeFibers(i16 fiber_ids_count, i16 *fiber_ids) Atomic8Set(&fiber->status, W32_FiberStatus_None); W32_Task *task = fiber->task; - if (task->job->flags & JobFlag_Dedicated) + // if (task->job->flags & JobFlag_Dedicated) + if (0) { /* TODO: Wake dedicated fiber right now */ WakeByAddressSingle(&fiber->status); @@ -573,21 +508,21 @@ void ResumeFibers(i16 fiber_ids_count, i16 *fiber_ids) else { /* Group task based on pool */ - JobPool pool_kind = fiber->pool; - W32_TaskList *pool_tasks = &tasks_by_pool[pool_kind]; + JobPoolId pool_id = fiber->pool; + W32_TaskList *pool_tasks = &tasks_by_pool[pool_id]; QueuePush(pool_tasks->first, pool_tasks->last, task); ++pool_tasks->count; } } /* Submit tasks */ - for (JobPool pool_kind = 0; pool_kind < JobPool_Count; ++pool_kind) + for (JobPoolId pool_id = 0; pool_id < num_pools; ++pool_id) { - W32_TaskList *tasks = &tasks_by_pool[pool_kind]; + W32_TaskList *tasks = &tasks_by_pool[pool_id]; i16 count = tasks->count; if (count > 0) { - W32_JobPool *pool = &W32_shared_job_state.job_pools[pool_kind]; + W32_JobPool *pool = &g->job_pools[pool_id]; /* Push tasks to front of queue */ LockTicketMutex(&pool->tasks_tm); @@ -616,19 +551,62 @@ void ResumeFibers(i16 fiber_ids_count, i16 *fiber_ids) } } } + + EndScratch(scratch); } //////////////////////////////////////////////////////////// -//~ @hoodef Job operations +//~ @hookdef Job pool operations -Job *OpenJob(JobFunc *func, JobPool pool_kind) +JobPoolId InitJobPool(u32 thread_count, String name, JobPoolPriority priority) { - if (pool_kind == JobPool_Inherit) + W32_SharedJobState *g = &W32_shared_job_state; + JobPoolId pool_id = Atomic32FetchAdd(&g->num_pools, 1); + W32_JobPool *pool = &g->job_pools[pool_id]; + pool->num_worker_threads = thread_count; + pool->id = pool_id; + pool->name = name; + pool->priority = priority; + + /* TODO: Real profiler group */ + i32 profiler_group = 0; + + Arena *perm = PermArena(); + pool->worker_threads = PushStructs(perm, W32_Thread *, pool->num_worker_threads); + pool->worker_contexts = PushStructs(perm, W32_WorkerCtx, pool->num_worker_threads); + for (i32 i = 0; i < pool->num_worker_threads; ++i) { - W32_Fiber *fiber = W32_FiberFromId(FiberId()); - pool_kind = fiber->pool; + W32_WorkerCtx *ctx = &pool->worker_contexts[i]; + ctx->pool_id = pool_id; + ctx->id = i; + String worker_name = StringF(perm, "%F [%F]", FmtString(name), FmtSint(i)); + pool->worker_threads[i] = W32_StartThread(W32_JobWorkerEntryPoint, ctx, worker_name, profiler_group + i); } - W32_JobPool *pool = &W32_shared_job_state.job_pools[pool_kind]; + return pool_id; +} + +JobPoolId CurrentPool(void) +{ + W32_Fiber *fiber = W32_FiberFromId(FiberId()); + return fiber->pool; +} + +JobPoolId AsyncPool(void) +{ + return W32_shared_job_state.async_pool; +} + +JobPoolId HyperPool(void) +{ + return W32_shared_job_state.hyper_pool; +} + +//////////////////////////////////////////////////////////// +//~ @hookdef Job operations + +Job *OpenJob(JobFunc *func, JobPoolId pool_id) +{ + W32_JobPool *pool = &W32_shared_job_state.job_pools[pool_id]; Job *job = 0; { Arena *job_arena = 0; @@ -655,7 +633,7 @@ Job *OpenJob(JobFunc *func, JobPool pool_kind) job = PushStruct(job_arena, Job); job->arena = job_arena; } - job->pool = pool_kind; + job->pool = pool_id; job->func = func; job->count = 1; return job; @@ -665,8 +643,8 @@ u32 CloseJob(Job *job) { TempArena scratch = BeginScratchNoConflict(); - JobPool pool_kind = job->pool; - W32_JobPool *pool = &W32_shared_job_state.job_pools[pool_kind]; + JobPoolId pool_id = job->pool; + W32_JobPool *pool = &W32_shared_job_state.job_pools[pool_id]; u32 num_tasks = job->count; if (num_tasks == 0) diff --git a/src/base/base_win32/base_win32_job.h b/src/base/base_win32/base_win32_job.h index 7f253c9b..9a3cf23c 100644 --- a/src/base/base_win32/base_win32_job.h +++ b/src/base/base_win32/base_win32_job.h @@ -78,7 +78,7 @@ StaticAssert(alignof(W32_Fiber) == CachelineSize && sizeof(W32_Fiber) % Cachelin //- Worker ctx AlignedStruct(W32_WorkerCtx, CachelineSize) { - JobPool pool_kind; + JobPoolId pool_id; i32 id; }; @@ -99,13 +99,12 @@ Struct(W32_TaskList) }; //- Job pool -AlignedStruct(W32_JobPool, CachelineSize) +Struct(W32_JobPool) { - JobPool kind; + JobPoolId id; + String name; + JobPoolPriority priority; i32 num_worker_threads; - i32 thread_priority; - u64 thread_affinity_mask; - b32 thread_is_audio; W32_Thread **worker_threads; W32_WorkerCtx *worker_contexts; @@ -147,9 +146,13 @@ AlignedStruct(W32_JobPool, CachelineSize) /* Arbitrary threshold for determining when to use a looped WakeByAddressSingle vs a WakeByAddressAll to wake parked workers */ #define W32_WakeAllWorkersThreshold 8 +#define W32_MaxJobPools 1024 Struct(W32_SharedJobState) { + JobPoolId async_pool; + JobPoolId hyper_pool; + //- Fibers AlignedBlock(CachelineSize) { @@ -162,8 +165,10 @@ Struct(W32_SharedJobState) //- Job pools AlignedBlock(CachelineSize) { - W32_JobPool job_pools[JobPool_Count]; + Atomic32 num_pools; + W32_JobPool job_pools[W32_MaxJobPools]; }; + } extern W32_shared_job_state; //////////////////////////////////////////////////////////// diff --git a/src/font/font.c b/src/font/font.c index 52d83664..97b31068 100644 --- a/src/font/font.c +++ b/src/font/font.c @@ -182,7 +182,7 @@ AC_Asset *F_LoadAsset(ResourceKey resource, f32 point_size, b32 wait) { AC_MarkLoading(asset); { - Job *job = OpenJob(F_Load, JobPool_Background); + Job *job = OpenJob(F_Load, AsyncPool()); F_Load_Sig *sig = PushStruct(job->arena, F_Load_Sig); job->sig = sig; sig->asset = asset; diff --git a/src/gpu/gpu_dx12/gpu_dx12.c b/src/gpu/gpu_dx12/gpu_dx12.c index d2564483..0c84706e 100644 --- a/src/gpu/gpu_dx12/gpu_dx12.c +++ b/src/gpu/gpu_dx12/gpu_dx12.c @@ -111,7 +111,8 @@ void GPU_D12_Startup(void) GPU_D12_InitRootsig(); /* Start queue sync job */ - RunJob(GPU_D12_StartQueueSync, .pool = JobPool_Hyper, .flags = JobFlag_Dedicated); + JobPoolId sync_pool = InitJobPool(1, Lit("Dx12 queue sync"), JobPoolPriority_Critical); + RunJob(GPU_D12_StartQueueSync, .pool = sync_pool); } //////////////////////////////////////////////////////////// diff --git a/src/meta/meta.c b/src/meta/meta.c index 0669ea22..e88f300f 100644 --- a/src/meta/meta.c +++ b/src/meta/meta.c @@ -1142,5 +1142,5 @@ JobDef(Build, _, __) void StartupLayers(void) { OS_Startup(); - RunJob(Build, .pool = JobPool_Hyper); + RunJob(Build, .pool = HyperPool()); } diff --git a/src/platform/platform_win32/platform_win32.c b/src/platform/platform_win32/platform_win32.c index 6723e387..3110c00e 100644 --- a/src/platform/platform_win32/platform_win32.c +++ b/src/platform/platform_win32/platform_win32.c @@ -7,101 +7,16 @@ void P_Startup(void) { P_W32_SharedState *g = &P_W32_shared_state; - //- Initialize btn table - { - ZeroArray(g->vk_btn_table); - for (u32 i = 'A', j = P_Btn_A; i <= 'Z'; ++i, ++j) - { - g->vk_btn_table[i] = (P_Btn)j; - } - for (u32 i = '0', j = P_Btn_0; i <= '9'; ++i, ++j) - { - g->vk_btn_table[i] = (P_Btn)j; - } - for (u32 i = VK_F1, j = P_Btn_F1; i <= VK_F24; ++i, ++j) - { - g->vk_btn_table[i] = (P_Btn)j; - } - g->vk_btn_table[VK_ESCAPE] = P_Btn_ESC; - g->vk_btn_table[VK_OEM_3] = P_Btn_GraveAccent; - g->vk_btn_table[VK_OEM_MINUS] = P_Btn_Minus; - g->vk_btn_table[VK_OEM_PLUS] = P_Btn_Equal; - g->vk_btn_table[VK_BACK] = P_Btn_Backspace; - g->vk_btn_table[VK_TAB] = P_Btn_Tab; - g->vk_btn_table[VK_SPACE] = P_Btn_Space; - g->vk_btn_table[VK_RETURN] = P_Btn_Enter; - g->vk_btn_table[VK_CONTROL] = P_Btn_Ctrl; - g->vk_btn_table[VK_SHIFT] = P_Btn_Shift; - g->vk_btn_table[VK_MENU] = P_Btn_Alt; - g->vk_btn_table[VK_UP] = P_Btn_Up; - g->vk_btn_table[VK_LEFT] = P_Btn_Left; - g->vk_btn_table[VK_DOWN] = P_Btn_Down; - g->vk_btn_table[VK_RIGHT] = P_Btn_Right; - g->vk_btn_table[VK_DELETE] = P_Btn_Delete; - g->vk_btn_table[VK_PRIOR] = P_Btn_PageUp; - g->vk_btn_table[VK_NEXT] = P_Btn_PageDown; - g->vk_btn_table[VK_HOME] = P_Btn_Home; - g->vk_btn_table[VK_END] = P_Btn_End; - g->vk_btn_table[VK_OEM_2] = P_Btn_ForwardSlash; - g->vk_btn_table[VK_OEM_PERIOD] = P_Btn_Period; - g->vk_btn_table[VK_OEM_COMMA] = P_Btn_Comma; - g->vk_btn_table[VK_OEM_7] = P_Btn_Quote; - g->vk_btn_table[VK_OEM_4] = P_Btn_LeftBracket; - g->vk_btn_table[VK_OEM_6] = P_Btn_RightBracket; - g->vk_btn_table[VK_INSERT] = P_Btn_Insert; - g->vk_btn_table[VK_OEM_1] = P_Btn_Semicolon; - } - - //- Create window class - { - HMODULE instance = GetModuleHandle(0); - - /* Register the window class */ - WNDCLASSEXW *wc = &g->window_class; - wc->cbSize = sizeof(WNDCLASSEX); - wc->lpszClassName = P_W32_WindowClassName; - wc->hCursor = LoadCursor(0, IDC_ARROW); - wc->style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; - // wc->hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); - wc->lpfnWndProc = P_W32_Win32WindowProc; - wc->hInstance = instance; - - /* Use first icon resource as window icon (same as explorer) */ - wchar_t path[4096] = ZI; - GetModuleFileNameW(instance, path, countof(path)); - ExtractIconExW(path, 0, &wc->hIcon, &wc->hIconSm, 1); - - if (!RegisterClassExW(wc)) - { - Panic(Lit("Failed to register window class")); - } - } - - //- Register raw input - { - RAWINPUTDEVICE rid = (RAWINPUTDEVICE) { - .usUsagePage = 0x01, /* HID_USAGE_PAGE_GENERIC */ - .usUsage = 0x02, /* HID_USAGE_GENERIC_MOUSE */ - //.dwFlags = RIDEV_NOLEGACY /* Adds mouse and also ignores legacy mouse messages */ - }; - - b32 ok = RegisterRawInputDevices(&rid, 1, sizeof(rid)); - Assert(ok); - LAX ok; - } - //- Init watches pool g->watches_arena = AcquireArena(Gibi(64)); - //- Init windows pool - g->windows_arena = AcquireArena(Gibi(64)); - //- Init winsock WSAStartup(MAKEWORD(2, 2), &g->wsa_data); g->socks_arena = AcquireArena(Gibi(64)); //- Init timer - RunJob(P_W32_StartTimerSync, .pool = JobPool_Hyper, .flags = JobFlag_Dedicated); + JobPoolId timer_pool = InitJobPool(1, Lit("Timer sync"), JobPoolPriority_Critical); + RunJob(P_W32_StartTimerSync, .pool = timer_pool); } //////////////////////////////////////////////////////////// @@ -154,627 +69,6 @@ String P_W32_StringFromWin32Path(Arena *arena, wchar_t *src) return result; } -//////////////////////////////////////////////////////////// -//~ Win32 window - -P_W32_Window *P_W32_AcquireWindow(void) -{ - P_W32_SharedState *g = &P_W32_shared_state; - P_W32_Window *window = 0; - { - Lock lock = LockE(&g->windows_mutex); - if (g->first_free_window) - { - window = g->first_free_window; - g->first_free_window = window->next_free; - } - else - { - window = PushStructNoZero(g->windows_arena, P_W32_Window); - } - Unlock(&lock); - } - ZeroStruct(window); - - window->event_arenas[0] = AcquireArena(Gibi(64)); - window->event_arenas[1] = AcquireArena(Gibi(64)); - - /* Start window event job */ - /* NOTE: This job must finish starting 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. */ - RunJob(P_W32_StartWindowMsgProcessing, .pool = JobPool_Hyper, .flags = JobFlag_Dedicated, .sig.window = window); - YieldOnFence(&window->ready_fence, 1); - - return window; -} - -void P_W32_ReleaseWindow(P_W32_Window *window) -{ - /* Stop window threads */ - Atomic32Set(&window->shutdown, 1); - P_W32_SharedState *g = &P_W32_shared_state; - P_W32_WakeWindow(window); - YieldOnFence(&window->finished_fence, 1); - - Lock lock = LockE(&g->windows_mutex); - { - window->next_free = g->first_free_window; - g->first_free_window = window; - } - Unlock(&lock); -} - -HWND P_W32_InitWindow(P_W32_Window *window) -{ - struct P_W32_SharedState *g = &P_W32_shared_state; - - /* - * From martins (https://gist.github.com/mmozeiko/5e727f845db182d468a34d524508ad5f#file-win32_d3d11-c-L66-L70): - * WS_EX_NOREDIRECTIONBITMAP flag here is needed to fix ugly bug with Windows 10 - * when window is resized and DXGI swap chain uses FLIP presentation model - * DO NOT use it if you choose to use non-FLIP presentation model - * read about the bug here: https://stackoverflow.com/q/63096226 and here: https://stackoverflow.com/q/53000291 - */ - DWORD exstyle = WS_EX_APPWINDOW | WS_EX_NOREDIRECTIONBITMAP; - - /* TODO: Check for hwnd success */ - HWND hwnd = CreateWindowExW( - exstyle, - g->window_class.lpszClassName, - L"", - WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, - CW_USEDEFAULT, - CW_USEDEFAULT, - CW_USEDEFAULT, - 0, - 0, - g->window_class.hInstance, - 0 - ); - - /* Dark mode */ - BOOL dark_mode = 1; - DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, (LPCVOID)&dark_mode, sizeof(dark_mode)); - - /* Set window as userdata */ - SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)window); - - return hwnd; -} - -//////////////////////////////////////////////////////////// -//~ Win32 window settings - -void P_W32_UpdateWindowFromSystem(P_W32_Window *window) -{ - HWND hwnd = window->hwnd; - - RECT window_rect = ZI; - GetWindowRect(hwnd, &window_rect); - - RECT client_rect = ZI; - GetClientRect(hwnd, (LPRECT)&client_rect); - ClientToScreen(hwnd, (LPPOINT)&client_rect.left); - ClientToScreen(hwnd, (LPPOINT)&client_rect.right); - - /* TODO: Error if we can't get monitor info */ - /* Screen dimensions */ - MONITORINFO monitor_info = { .cbSize = sizeof(monitor_info) }; - GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY), &monitor_info); - RECT monitor_rect = monitor_info.rcMonitor; - window->monitor_width = monitor_rect.right - monitor_rect.left; - window->monitor_height = monitor_rect.bottom - monitor_rect.top; - - /* Minimized / maximized */ - if (window->flags & P_WindowFlag_Showing) - { - WINDOWPLACEMENT placement = { .length = sizeof(placement) }; - GetWindowPlacement(hwnd, &placement); - if (placement.showCmd == SW_SHOWMINIMIZED) - { - window->settings.flags |= P_WindowSettingsFlag_Minimized; - } - else - { - window->settings.flags &= ~P_WindowSettingsFlag_Minimized; - } - if (placement.showCmd == SW_SHOWMAXIMIZED - || ((window->settings.flags & P_WindowSettingsFlag_Minimized) && ((placement.flags & WPF_RESTORETOMAXIMIZED) != 0))) - { - window->settings.flags |= P_WindowSettingsFlag_Maximized; - } - else - { - window->settings.flags &= ~P_WindowSettingsFlag_Maximized; - } - } - - /* Window dimensions */ - i32 x = client_rect.left; - i32 y = client_rect.top; - i32 width = client_rect.right - client_rect.left; - i32 height = client_rect.bottom - client_rect.top; - if (!(window->settings.flags & P_WindowSettingsFlag_Minimized)) - { - window->x = x; - window->y = y; - window->width = width; - window->height = height; - if (!(window->settings.flags & (P_WindowSettingsFlag_Maximized | P_WindowSettingsFlag_Fullscreen))) - { - /* Treat a window resize in non maximized/fullscreen mode as a - * settings change. - * - * TODO: make sure we check for fullscreen here too if we ever - * allow it. */ - window->settings.floating_x = x; - window->settings.floating_y = y; - window->settings.floating_width = width; - window->settings.floating_height = height; - } - } -} - -void P_W32_UpdateWindowFromSettings(P_W32_Window *window, P_WindowSettings *settings) -{ - HWND hwnd = window->hwnd; - - P_WindowSettings old_settings = window->settings; - window->settings = *settings; - - i32 show_cmd = SW_HIDE; - if (window->flags & P_WindowFlag_Showing) - { - show_cmd = SW_NORMAL; - if (settings->flags & P_WindowSettingsFlag_Maximized) - { - show_cmd = SW_SHOWMAXIMIZED; - } - else if (settings->flags & P_WindowSettingsFlag_Minimized) - { - show_cmd = SW_MINIMIZE; - } - } - - RECT rect = ZI; - - b32 old_fullscreen = old_settings.flags & P_WindowSettingsFlag_Fullscreen; - b32 fullscreen = settings->flags & P_WindowSettingsFlag_Fullscreen; - - if (fullscreen) - { - if (!old_fullscreen) - { - /* Entering fullscreen */ - SetWindowLongPtrW(hwnd, GWL_STYLE, WS_POPUP); - } - rect = (RECT) { - .left = 0, - .top = 0, - .right = window->monitor_width, - .bottom = window->monitor_height - }; - } - else - { - if (old_fullscreen) - { - /* Leaving fullscreen */ - SetWindowLongPtrW(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW); - } - rect = (RECT) { - .left = settings->floating_x, - .top = settings->floating_y, - .right = settings->floating_x + settings->floating_width, - .bottom = settings->floating_y + settings->floating_height - }; - AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, 0); - } - - WINDOWPLACEMENT wp = { - .length = sizeof(WINDOWPLACEMENT), - .showCmd = show_cmd, - .rcNormalPosition = rect - }; - SetWindowPlacement(hwnd, &wp); - - { - TempArena scratch = BeginScratchNoConflict(); - wchar_t *title_wstr = WstrFromString(scratch.arena, StringFromCstrNoLimit(settings->title)); - SetWindowTextW(hwnd, title_wstr); - EndScratch(scratch); - } -} - -//////////////////////////////////////////////////////////// -//~ Win32 window message processing - -JobDef(P_W32_StartWindowMsgProcessing, sig, id) -{ - P_W32_Window *window = sig->window; - - /* Win32 limitation: Window must be initialized on same thread that processes events */ - window->hwnd = P_W32_InitWindow(window); - P_W32_UpdateWindowFromSystem(window); - SetFence(&window->ready_fence, 1); - SetForegroundWindow(window->hwnd); - - while (!Atomic32Fetch(&window->shutdown)) - { - SetFocus(window->hwnd); - MSG msg = ZI; - { - GetMessageW(&msg, 0, 0, 0); - } - { - __profn("Process window message"); - if (!Atomic32Fetch(&window->shutdown)) - { - TranslateMessage(&msg); - DispatchMessageW(&msg); - } - } - } - - /* Destroy window hwnd */ - DestroyWindow(window->hwnd); - SetFence(&window->finished_fence, 1); -} - -void P_W32_ProcessWindowEvent(P_W32_Window *window, P_WindowEvent event) -{ - __prof; - Lock lock = LockE(&window->event_arena_swp_mutex); - { - *PushStruct(window->event_arenas[window->current_event_arena_index], P_WindowEvent) = event; - } - Unlock(&lock); -} - -void P_W32_WakeWindow(P_W32_Window *window) -{ - /* Post a blank message to the window's thread message queue to wake it. */ - PostMessageW(window->hwnd, WM_NULL, 0, 0); -} - -LRESULT CALLBACK P_W32_Win32WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -{ - __prof; - P_W32_SharedState *g = &P_W32_shared_state; - P_W32_Window *window = (P_W32_Window *)GetWindowLongPtrW(hwnd, GWLP_USERDATA); - - if (!window) - { - return DefWindowProcW(hwnd, msg, wparam, lparam); - } - - /* Update cursor */ - if (GetFocus() == window->hwnd) - { - u32 cursor_flags = window->cursor_set_flags; - - /* Hide cursor */ - if (cursor_flags & P_W32_CursorFlag_Hide) - { - while (ShowCursor(0) >= 0); - } - - /* Show cursor */ - if (cursor_flags & P_W32_CursorFlag_Show) - { - while (ShowCursor(1) < 0); - } - - /* Update position */ - if (cursor_flags & P_W32_CursorFlag_Position) - { - Vec2 window_space_pos = window->cursor_set_position; - POINT p = { window_space_pos.x, window_space_pos.y }; - ClientToScreen(window->hwnd, &p); - SetCursorPos(p.x, p.y); - } - - /* Stop clipping cursor */ - if (cursor_flags & P_W32_CursorFlag_DisableClip) - { - ClipCursor(0); - } - - /* Clip cursor in window window */ - if (cursor_flags & P_W32_CursorFlag_EnableClip) - { - i32 left = window->x + RoundF32ToI32(window->cursor_clip_bounds.x); - i32 right = left + RoundF32ToI32(window->cursor_clip_bounds.width); - i32 top = window->y + RoundF32ToI32(window->cursor_clip_bounds.y); - i32 bottom = top + RoundF32ToI32(window->cursor_clip_bounds.height); - RECT clip = { - .left = ClampI32(left, window->x, window->x + window->width), - .right = ClampI32(right, window->x, window->x + window->width), - .top = ClampI32(top, window->y, window->y + window->height), - .bottom = ClampI32(bottom, window->y, window->y + window->height) - }; - ClipCursor(&clip); - } - - window->cursor_set_flags = 0; - } - - /* Update always on top */ - { - u32 toggles = Atomic32FetchSet(&window->topmost_toggles, 0); - if (toggles % 2 != 0) - { - b32 new_topmost = !window->is_topmost; - if (new_topmost) - { - SetWindowText(hwnd, L"============================= TOP ============================="); - } - else - { - SetWindowText(hwnd, L""); - } - SetWindowPos(hwnd, new_topmost ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); - window->is_topmost = new_topmost; - } - } - - LRESULT result = 0; - b32 is_release = 0; - switch (msg) - { - default: - { - result = DefWindowProcW(hwnd, msg, wparam, lparam); - } break; - - case WM_QUIT: - case WM_CLOSE: - case WM_DESTROY: - { - P_W32_ProcessWindowEvent(window, (P_WindowEvent) { .kind = P_WindowEventKind_Quit }); - } break; - - case WM_PAINT: - { - result = DefWindowProcW(hwnd, msg, wparam, lparam); - } break; - - case WM_ENTERSIZEMOVE: - case WM_MOVE: - case WM_MOVING: - case WM_SIZE: - case WM_SIZING: - { - P_W32_UpdateWindowFromSystem(window); - result = DefWindowProcW(hwnd, msg, wparam, lparam); - } break; - - /* Keyboard buttons */ - case WM_SYSKEYUP: - case WM_SYSKEYDOWN: - { - if (LOWORD(wparam) != VK_MENU) - { - result = DefWindowProcW(hwnd, msg, wparam, lparam); - } - } FALLTHROUGH; - case WM_KEYUP: - case WM_KEYDOWN: - { - WORD vk_code = LOWORD(wparam); - b32 is_repeat = 0; - - P_WindowEventKind event_kind = P_WindowEventKind_None; - if (msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN) - { - event_kind = P_WindowEventKind_ButtonDown; - is_repeat = (lparam & 0x40000000) != 0; - } - else if (msg == WM_KEYUP || msg == WM_SYSKEYUP) - { - event_kind = P_WindowEventKind_ButtonUp; - } - - P_Btn button = P_Btn_None; - if (vk_code < countof(g->vk_btn_table)) - { - button = g->vk_btn_table[vk_code]; - } - - P_W32_ProcessWindowEvent( - window, - (P_WindowEvent) - { - .kind = event_kind, - .button = button, - .is_repeat = is_repeat - }); - } break; - - /* Text */ - case WM_SYSCHAR: - case WM_CHAR: - { - u16 utf16_char = (u32)wparam; - - /* Decode */ - u32 codepoint = 0; - if (IsUtf16HighSurrogate(utf16_char)) - { - window->utf16_high_surrogate_last_input = utf16_char; - } - else if (IsUtf16LowSurrogate(utf16_char)) - { - u16 high = window->utf16_high_surrogate_last_input; - u16 low = utf16_char; - if (high) - { - u16 utf16_pair_bytes[2] = { high, low }; - Utf16DecodeResult decoded = DecodeUtf16((String16) { .len = countof(utf16_pair_bytes), .text = utf16_pair_bytes }); - if (decoded.advance16 == 2 && decoded.codepoint < U32Max) - { - codepoint = decoded.codepoint; - } - } - window->utf16_high_surrogate_last_input = 0; - } - else - { - window->utf16_high_surrogate_last_input = 0; - codepoint = utf16_char; - } - - if (codepoint) - { - if (codepoint == '\r') - { - codepoint = '\n'; /* Just treat all \r as newline */ - } - if ((codepoint >= 32 && codepoint != 127) || codepoint == '\t' || codepoint == '\n') - { - P_W32_ProcessWindowEvent( - window, - (P_WindowEvent) - { - .kind = P_WindowEventKind_Text, - .text_codepoint = codepoint - }); - } - } - - - } break; - - /* Mouse buttons */ - case WM_LBUTTONUP: - case WM_MBUTTONUP: - case WM_RBUTTONUP: - case WM_XBUTTONUP: - { - ReleaseCapture(); - is_release = 1; - } FALLTHROUGH; - case WM_LBUTTONDOWN: - case WM_MBUTTONDOWN: - case WM_RBUTTONDOWN: - case WM_XBUTTONDOWN: - { - if (!is_release) - { - SetCapture(hwnd); - } - - P_WindowEventKind event_kind = is_release ? P_WindowEventKind_ButtonUp : P_WindowEventKind_ButtonDown; - P_Btn button = 0; - - switch (msg) - { - case WM_LBUTTONUP: case WM_LBUTTONDOWN: button = P_Btn_M1; break; - case WM_RBUTTONUP: case WM_RBUTTONDOWN: button = P_Btn_M2; break; - case WM_MBUTTONUP: case WM_MBUTTONDOWN: button = P_Btn_M3; break; - case WM_XBUTTONUP: case WM_XBUTTONDOWN: - { - u32 wparam_xbutton = GET_XBUTTON_WPARAM(wparam); - if (wparam_xbutton == XBUTTON1) - { - button = P_Btn_M4; - } - else if (wparam_xbutton == XBUTTON2) - { - button = P_Btn_M5; - } - } break; - } - - if (button) - { - P_W32_ProcessWindowEvent( - window, - (P_WindowEvent) - { - .kind = event_kind, - .button = button - }); - } - } break; - - /* Mouse wheel */ - case WM_MOUSEWHEEL: - { - int delta = GET_WHEEL_DELTA_WPARAM(wparam); - i32 dir = delta >= 0 ? 1 : -1; - P_Btn button = dir >= 0 ? P_Btn_MWheelUp : P_Btn_MWheelDown; - for (i32 i = 0; i < (dir * delta); i += WHEEL_DELTA) - { - /* Send a button down & button up event simultaneously */ - P_W32_ProcessWindowEvent(window, (P_WindowEvent) { .kind = P_WindowEventKind_ButtonDown, .button = button }); - P_W32_ProcessWindowEvent(window, (P_WindowEvent) { .kind = P_WindowEventKind_ButtonUp, .button = button }); - } - } break; - - /* Mouse move */ - case WM_MOUSEMOVE: - { - i32 x = GET_X_LPARAM(lparam); - i32 y = GET_Y_LPARAM(lparam); - P_W32_ProcessWindowEvent( - window, - (P_WindowEvent) - { - .kind = P_WindowEventKind_CursorMove, - .cursor_position = VEC2(x, y) - }); - } break; - - /* Raw mouse move */ - case WM_INPUT: - { - TempArena scratch = BeginScratchNoConflict(); - - /* Read raw input buffer */ - UINT buff_size; - GetRawInputData((HRAWINPUT)lparam, RID_INPUT, 0, &buff_size, sizeof(RAWINPUTHEADER)); - u8 *buff = PushStructs(scratch.arena, u8, buff_size); - if (GetRawInputData((HRAWINPUT)lparam, RID_INPUT, buff, &buff_size, sizeof(RAWINPUTHEADER)) != buff_size) - { - P_LogErrorF("GetRawInputData did not return correct size"); - break; - } - RAWINPUT raw = ZI; - CopyBytes(&raw, buff, sizeof(RAWINPUT)); - - if (raw.header.dwType == RIM_TYPEMOUSE) - { - i32 x = raw.data.mouse.lLastX; - i32 y = raw.data.mouse.lLastY; - Vec2 delta = VEC2(x, y); - P_W32_ProcessWindowEvent( - window, - (P_WindowEvent) - { - .kind = P_WindowEventKind_MouseMove, - .mouse_delta = delta - }); - } - - EndScratch(scratch); - } break; - - /* Minmax info */ - case WM_GETMINMAXINFO: - { - /* Set minimum window size */ - LPMINMAXINFO mmi = (LPMINMAXINFO)lparam; - mmi->ptMinTrackSize.x = 100; - mmi->ptMinTrackSize.y = 100; - } break; - } - - return result; -} - //////////////////////////////////////////////////////////// //~ Win32 Address @@ -889,7 +183,7 @@ JobDef(P_W32_StartTimerSync, _, __) { __profn("Job scheduler cycle"); { - /* TODO: Minimum timer frequency in case windows timers ever become ultra precise in the future */ + /* TODO: Minimum timer frequency in case timers ever become ultra precise in the future */ __profn("Job scheduler wait"); LARGE_INTEGER due = ZI; due.QuadPart = -1; @@ -1297,150 +591,6 @@ String P_GetFileMapData(P_FileMap map) return map.mapped_memory; } -//////////////////////////////////////////////////////////// -//~ @hookdef Window hooks - -P_Window *P_AcquireWindow(void) -{ - __prof; - return (P_Window *)P_W32_AcquireWindow(); -} - -void P_ReleaseWindow(P_Window *p_window) -{ - __prof; - P_W32_Window *window = (P_W32_Window *)p_window; - P_W32_ReleaseWindow(window); -} - -//- Window events -P_WindowEventArray P_PopWindowEvents(Arena *arena, P_Window *p_window) -{ - __prof; - P_W32_Window *window = (P_W32_Window *)p_window; - i32 event_arena_index = 0; - { - /* Swap event buffers */ - Lock lock = LockE(&window->event_arena_swp_mutex); - event_arena_index = window->current_event_arena_index; - window->current_event_arena_index = 1 - window->current_event_arena_index; - Unlock(&lock); - } - Arena *events_arena = window->event_arenas[event_arena_index]; - P_WindowEventArray events = ZI; - events.count = ArenaCount(events_arena, P_WindowEvent); - events.events = PushStructsNoZero(arena, P_WindowEvent, events.count); - CopyBytes(events.events, ArenaBase(events_arena), events_arena->pos); - ResetArena(events_arena); - return events; -} - -//- Window settings -void P_UpdateWindowSettings(P_Window *p_window, P_WindowSettings *settings) -{ - __prof; - P_W32_Window *window = (P_W32_Window *)p_window; - Lock lock = LockE(&window->settings_mutex); - { - P_W32_UpdateWindowFromSettings(window, settings); - } - Unlock(&lock); -} - -/* FIXME: Lock settings mutex for these functions */ - -P_WindowSettings P_GetWindowSettings(P_Window *p_window) -{ - P_W32_Window *window = (P_W32_Window *)p_window; - return window->settings; -} - -void P_ShowWindow(P_Window *p_window) -{ - P_W32_Window *window = (P_W32_Window *)p_window; - HWND hwnd = window->hwnd; - Lock lock = LockE(&window->settings_mutex); - { - i32 show_cmd = SW_NORMAL; - P_WindowSettings *settings = &window->settings; - if (settings->flags & P_WindowSettingsFlag_Maximized) - { - show_cmd = SW_SHOWMAXIMIZED; - } - else if (settings->flags & P_WindowSettingsFlag_Minimized) - { - show_cmd = SW_MINIMIZE; - } - window->flags |= P_WindowFlag_Showing; - ShowWindow(hwnd, show_cmd); - BringWindowToTop(hwnd); - } - Unlock(&lock); -} - -void P_SetWindowCursorPos(P_Window *p_window, Vec2 pos) -{ - P_W32_Window *window = (P_W32_Window *)p_window; - window->cursor_set_position = pos; - window->cursor_set_flags |= P_W32_CursorFlag_Position; - P_W32_WakeWindow(window); -} - -void P_ShowWindowCursor(P_Window *p_window) -{ - P_W32_Window *window = (P_W32_Window *)p_window; - window->cursor_set_flags |= P_W32_CursorFlag_Show; - P_W32_WakeWindow(window); -} - -void P_HideWindowCursor(P_Window *p_window) -{ - P_W32_Window *window = (P_W32_Window *)p_window; - window->cursor_set_flags |= P_W32_CursorFlag_Hide; - P_W32_WakeWindow(window); -} - -void P_EnableWindoweCursorClip(P_Window *p_window, Rect bounds) -{ - P_W32_Window *window = (P_W32_Window *)p_window; - window->cursor_clip_bounds = bounds; - window->cursor_set_flags |= P_W32_CursorFlag_EnableClip; - P_W32_WakeWindow(window); -} - -void P_DisableWindoweCursorClip(P_Window *p_window) -{ - P_W32_Window *window = (P_W32_Window *)p_window; - window->cursor_set_flags |= P_W32_CursorFlag_DisableClip; - P_W32_WakeWindow(window); -} - -void P_ToggleWindowTopmost(P_Window *p_window) -{ - P_W32_Window *window = (P_W32_Window *)p_window; - Atomic32FetchAdd(&window->topmost_toggles, 1); - P_W32_WakeWindow(window); -} - -//- Window info -Vec2I32 P_GetWindowSize(P_Window *p_window) -{ - P_W32_Window *window = (P_W32_Window *)p_window; - return VEC2I32(window->width, window->height); -} - -Vec2I32 P_GetWindowMonitorSize(P_Window *p_window) -{ - P_W32_Window *window = (P_W32_Window *)p_window; - return VEC2I32(window->monitor_width, window->monitor_height); -} - -u64 P_GetInternalWindowHandle(P_Window *p_window) -{ - P_W32_Window *window = (P_W32_Window *)p_window; - return (u64)window->hwnd; -} - //////////////////////////////////////////////////////////// //~ @hookdef Address helper hooks diff --git a/src/platform/platform_win32/platform_win32.h b/src/platform/platform_win32/platform_win32.h index 2c4b67df..cf0f956a 100644 --- a/src/platform/platform_win32/platform_win32.h +++ b/src/platform/platform_win32/platform_win32.h @@ -23,55 +23,6 @@ #pragma comment(lib, "avrt") #pragma comment(lib, "ws2_32.lib") -//////////////////////////////////////////////////////////// -//~ Window types - -Enum(P_W32_CursorFlag) -{ - P_W32_CursorFlag_None = (0 << 0), - P_W32_CursorFlag_Position = (1 << 0), - P_W32_CursorFlag_Hide = (1 << 1), - P_W32_CursorFlag_Show = (1 << 2), - P_W32_CursorFlag_EnableClip = (1 << 3), - P_W32_CursorFlag_DisableClip = (1 << 4) -}; - -Struct(P_W32_Window) -{ - u32 flags; - - HWND hwnd; - Fence ready_fence; - Fence finished_fence; - - u16 utf16_high_surrogate_last_input; - - Mutex settings_mutex; - P_WindowSettings settings; - - i32 monitor_width; - i32 monitor_height; - /* NOTE: width & height are unaffected by window minimization (they retain - * their pre-minimized values) */ - i32 x, y, width, height; - - /* FIXME: Use a cmd buffer for updating cursor (and maybe also settings). - * Current setup means cursor_set calls can be applied out of order */ - u32 cursor_set_flags; - Vec2 cursor_set_position; - Rect cursor_clip_bounds; - - Atomic32 topmost_toggles; - b32 is_topmost; - - Mutex event_arena_swp_mutex; - i32 current_event_arena_index; - Arena *event_arenas[2]; - - Atomic32 shutdown; - P_W32_Window *next_free; -}; - //////////////////////////////////////////////////////////// //~ Watch types @@ -111,26 +62,16 @@ Struct(P_W32_Sock) //////////////////////////////////////////////////////////// //~ State types -#define P_W32_WindowClassName L"power_play_window_class" #define P_W32_NumRollingTimerPeriods 500 #define P_W32_DefaultTimerPeriodNs 50000000 Struct(P_W32_SharedState) { - //- Key lookup table - P_Btn vk_btn_table[256]; - //- Watches pool Mutex watches_mutex; Arena *watches_arena; P_W32_Watch *watches_first_free; - //- Windows pool - WNDCLASSEXW window_class; - Mutex windows_mutex; - Arena *windows_arena; - P_W32_Window *first_free_window; - //- Socket pool WSADATA wsa_data; Arena *socks_arena; @@ -152,27 +93,6 @@ P_DateTime P_W32_DateTimeFromWin32SystemTime(SYSTEMTIME st); String P_W32_StringFromWin32Path(Arena *arena, wchar_t *src); -//////////////////////////////////////////////////////////// -//~ Window operations - -P_W32_Window *P_W32_AcquireWindow(void); -void P_W32_ReleaseWindow(P_W32_Window *window); -HWND P_W32_InitWindow(P_W32_Window *window); - -//////////////////////////////////////////////////////////// -//~ Window settings - -void P_W32_UpdateWindowFromSystem(P_W32_Window *window); -void P_W32_UpdateWindowFromSettings(P_W32_Window *window, P_WindowSettings *settings); - -//////////////////////////////////////////////////////////// -//~ Window message processing - -JobDecl(P_W32_StartWindowMsgProcessing, { P_W32_Window *window; }); -void P_W32_ProcessWindowEvent(P_W32_Window *window, P_WindowEvent event); -void P_W32_WakeWindow(P_W32_Window *window); -LRESULT CALLBACK P_W32_Win32WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); - //////////////////////////////////////////////////////////// //~ Address operations diff --git a/src/playback/playback_wasapi/playback_wasapi.c b/src/playback/playback_wasapi/playback_wasapi.c index a34a1b6e..8ecd704a 100644 --- a/src/playback/playback_wasapi/playback_wasapi.c +++ b/src/playback/playback_wasapi/playback_wasapi.c @@ -15,7 +15,8 @@ void PB_Startup(void) PB_WSP_SharedState *g = &PB_WSP_shared_state; PB_WSP_InitializeWasapi(); /* Start playback job */ - g->shutdown_jobs_count += RunJob(PB_WSP_Playback, .pool = JobPool_Audio, .fence = &g->shutdown_jobs_fence); + JobPoolId playback_pool = InitJobPool(1, Lit("Playback"), JobPoolPriority_Audio); + g->shutdown_jobs_count += RunJob(PB_WSP_Playback, .pool = playback_pool, .fence = &g->shutdown_jobs_fence); OnExit(&PB_WSP_Shutdown); } diff --git a/src/pp/pp.c b/src/pp/pp.c index 8dd77a53..ba37c365 100644 --- a/src/pp/pp.c +++ b/src/pp/pp.c @@ -51,9 +51,13 @@ void StartupUser(void) //P_RegisterLogCallback(ConsoleLogCallback, P_LogLevel_Success); P_RegisterLogCallback(ConsoleLogCallback, P_LogLevel_Debug); + /* Create job pools */ + JobPoolId user_pool = InitJobPool(1, Lit("User"), JobPoolPriority_Graphics); + JobPoolId sim_pool = InitJobPool(4, Lit("Simulation"), JobPoolPriority_Simulation); + /* Start jobs */ - g->shutdown_jobs_count += RunJob(UpdateUserOrSleep, .pool = JobPool_User, .fence = &g->shutdown_jobs_fence); - g->shutdown_jobs_count += RunJob(UpdateSim, .pool = JobPool_Sim, .fence = &g->shutdown_jobs_fence); + g->shutdown_jobs_count += RunJob(UpdateUserOrSleep, .pool = user_pool, .fence = &g->shutdown_jobs_fence); + g->shutdown_jobs_count += RunJob(UpdateSim, .pool = sim_pool, .fence = &g->shutdown_jobs_fence); OnExit(&ShutdownUser); } diff --git a/src/sound/sound.c b/src/sound/sound.c index fe3283ff..c7e20770 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -99,7 +99,7 @@ AC_Asset *SND_LoadAsset(ResourceKey resource, SND_SoundFlag flags, b32 wait) { AC_MarkLoading(asset); { - Job *job = OpenJob(SND_Load, JobPool_Background); + Job *job = OpenJob(SND_Load, AsyncPool()); SND_Load_Sig *sig = PushStruct(job->arena, SND_Load_Sig); job->sig = sig; sig->resource = resource; diff --git a/src/sprite/sprite.c b/src/sprite/sprite.c index c025bd5c..ee179f01 100644 --- a/src/sprite/sprite.c +++ b/src/sprite/sprite.c @@ -283,7 +283,7 @@ JobDef(S_LoadSheet, sig, _) //~ Cache /* TODO: Per-fiber L1 cache */ -S_Entry *S_FetchEntry(ResourceKey resource, JobPool pool, S_FetchFlag flags) +S_Entry *S_FetchEntry(ResourceKey resource, JobPoolId pool, S_FetchFlag flags) { S_SharedState *g = &S_shared_state; S_Entry *entry = 0; @@ -351,7 +351,7 @@ S_Entry *S_FetchEntry(ResourceKey resource, JobPool pool, S_FetchFlag flags) S_Texture *S_TextureFromResource(ResourceKey resource) { - S_Entry *entry = S_FetchEntry(resource, JobPool_Inherit, S_FetchFlag_Texture); + S_Entry *entry = S_FetchEntry(resource, CurrentPool(), S_FetchFlag_Texture); YieldOnFence(&entry->texture_ready_fence, 1); return &entry->texture; } @@ -359,7 +359,7 @@ S_Texture *S_TextureFromResource(ResourceKey resource) S_Texture *S_TextureFromResourceAsync(ResourceKey resource) { S_Texture *result = &S_NilTexture; - S_Entry *entry = S_FetchEntry(resource, JobPool_Inherit, S_FetchFlag_Texture); + S_Entry *entry = S_FetchEntry(resource, AsyncPool(), S_FetchFlag_Texture); if (FetchFence(&entry->texture_ready_fence) >= 1) { result = &entry->texture; @@ -369,7 +369,7 @@ S_Texture *S_TextureFromResourceAsync(ResourceKey resource) S_Sheet *S_SheetFromResource(ResourceKey resource) { - S_Entry *entry = S_FetchEntry(resource, JobPool_Inherit, S_FetchFlag_Sheet); + S_Entry *entry = S_FetchEntry(resource, CurrentPool(), S_FetchFlag_Sheet); YieldOnFence(&entry->sheet_ready_fence, 1); return &entry->sheet; } @@ -377,7 +377,7 @@ S_Sheet *S_SheetFromResource(ResourceKey resource) S_Sheet *S_SheetFromResourceAsync(ResourceKey resource) { S_Sheet *result = &S_NilSheet; - S_Entry *entry = S_FetchEntry(resource, JobPool_Inherit, S_FetchFlag_Sheet); + S_Entry *entry = S_FetchEntry(resource, AsyncPool(), S_FetchFlag_Sheet); if (FetchFence(&entry->sheet_ready_fence) >= 1) { result = &entry->sheet; diff --git a/src/sprite/sprite.h b/src/sprite/sprite.h index 4588d197..4aa182f1 100644 --- a/src/sprite/sprite.h +++ b/src/sprite/sprite.h @@ -146,7 +146,7 @@ Enum(S_FetchFlag) S_FetchFlag_Sheet = (1 << 1), }; -S_Entry *S_FetchEntry(ResourceKey resource, JobPool pool, S_FetchFlag flags); +S_Entry *S_FetchEntry(ResourceKey resource, JobPoolId pool, S_FetchFlag flags); //////////////////////////////////////////////////////////// //~ Sprite data retrieval operations diff --git a/src/window/window_win32/window_win32.c b/src/window/window_win32/window_win32.c index 741beea9..de1ac4c7 100644 --- a/src/window/window_win32/window_win32.c +++ b/src/window/window_win32/window_win32.c @@ -86,7 +86,8 @@ void WND_Startup(void) } //- Start message processing job - RunJob(WND_W32_ProcessMessagesForever, .pool = JobPool_Hyper, .flags = JobFlag_Dedicated); + JobPoolId message_job_pool = InitJobPool(1, Lit("Win32 message loop"), JobPoolPriority_Background); + RunJob(WND_W32_ProcessMessagesForever, .pool = message_job_pool); } ////////////////////////////////////////////////////////////