diff --git a/src/app/app_core.c b/src/app/app_core.c index d8008633..51544b61 100644 --- a/src/app/app_core.c +++ b/src/app/app_core.c @@ -126,14 +126,15 @@ AppArgList ParseAppArgs(Arena *arena, String args_str) } //////////////////////////////// -//~ Entry point +//~ @hookdef Entry point -void P_AppStartup(String args_str) +void EntryPoint(void) { __prof; TempArena scratch = BeginScratchNoConflict(); SharedAppState *g = &shared_app_state; + String args_str = Lit(""); AppArgList args = ParseAppArgs(scratch.arena, args_str); String logfile_name = Lit("log.log"); String settings_file_name = Lit("settings.txt"); @@ -217,7 +218,7 @@ void P_AppStartup(String args_str) ), FmtString(settings_path), FmtString(error)); - P_Panic(msg); + Panic(msg); } P_LogInfoF("Settings file loaded successfully"); window_settings = *deser; diff --git a/src/asset_cache/asset_cache_core.c b/src/asset_cache/asset_cache_core.c index 7a0083e2..e7992683 100644 --- a/src/asset_cache/asset_cache_core.c +++ b/src/asset_cache/asset_cache_core.c @@ -119,7 +119,7 @@ AC_Asset *AC_TouchCache(String key, u64 hash, b32 *is_first_touch) { if (g->num_assets >= AC_MaxAssets) { - P_Panic(Lit("Max assets reached")); + Panic(Lit("Max assets reached")); } String key_stored = ZI; { diff --git a/src/base/base.h b/src/base/base.h index b812299f..f72a0429 100644 --- a/src/base/base.h +++ b/src/base/base.h @@ -30,6 +30,7 @@ inline void StartupBaseDeps(void) # include "base_rand.h" # include "base_util.h" # include "base_incbin.h" +# include "base_entry.h" #if PlatformIsWindows # include "win32/base_win32.h" #endif diff --git a/src/base/base_arena.c b/src/base/base_arena.c index f03d69a0..ce0b9f77 100644 --- a/src/base/base_arena.c +++ b/src/base/base_arena.c @@ -18,7 +18,7 @@ Arena *AllocArena(u64 reserve) { /* Hard fail on memory reserve failure for now */ /* FIXME: Enable this */ - //P_Panic(Lit("Failed to reserve memory")); + //Panic(Lit("Failed to reserve memory")); (*(volatile int *)0) = 0; } u64 reserved = reserve; @@ -30,7 +30,7 @@ Arena *AllocArena(u64 reserve) { /* Hard fail on commit failure */ /* FIXME: Enable this */ - //P_Panic(Lit("Failed to commit initial memory block: System may be out of memory")); + //Panic(Lit("Failed to commit initial memory block: System may be out of memory")); (*(volatile int *)0) = 0; } @@ -89,7 +89,7 @@ void *PushBytesNoZero(Arena *arena, u64 size, u64 align) { /* Hard fail if we overflow reserved memory for now */ /* FIXME: Enable this */ - //P_Panic(Lit("Failed to commit new memory block: Overflow of reserved memory")); + //Panic(Lit("Failed to commit new memory block: Overflow of reserved memory")); (*(volatile int *)0) = 0; } void *commit_address = base + arena->committed; @@ -97,7 +97,7 @@ void *PushBytesNoZero(Arena *arena, u64 size, u64 align) { /* Hard fail on memory allocation failure for now */ /* FIXME: Enable this */ - //P_Panic(Lit("Failed to commit new memory block: System may be out of memory")); + //Panic(Lit("Failed to commit new memory block: System may be out of memory")); (*(volatile int *)0) = 0; } arena->committed += commit_bytes; diff --git a/src/base/base_entry.h b/src/base/base_entry.h new file mode 100644 index 00000000..bc580cc6 --- /dev/null +++ b/src/base/base_entry.h @@ -0,0 +1,17 @@ +//////////////////////////////// +//~ Exit callback types + +#define ExitFuncDef(name) void name(void) +typedef ExitFuncDef(ExitFunc); + +//////////////////////////////// +//~ @hookdecl Exit operations + +void OnExit(ExitFunc *func); +void Exit(void); +void Panic(String msg); + +//////////////////////////////// +//~ @hookdecl Application defined entry point + +void EntryPoint(void); diff --git a/src/base/base_incbin.c b/src/base/base_incbin.c index 74ca5dc1..6964f85a 100644 --- a/src/base/base_incbin.c +++ b/src/base/base_incbin.c @@ -55,7 +55,7 @@ String StringFromIncbinRcResource(IncbinRcResource *inc) if (!params.found) { /* FIXME: enable this */ - //P_Panic(StringFormat(scratch.arena, + //Panic(StringFormat(scratch.arena, // Lit("INCBIN include not found in RC file: \"%F\""), // FmtString(inc->rc_name))); (*(volatile int *)0) = 0; diff --git a/src/base/base_job.h b/src/base/base_job.h index b9209720..7711a09d 100644 --- a/src/base/base_job.h +++ b/src/base/base_job.h @@ -93,7 +93,6 @@ void RunJobEx(GenericJobDesc *desc); //~ @hookdecl Helpers i64 TimeNs(void); - -u32 GetLogicalProcessorCount(void); u32 ThreadId(void); +u32 GetLogicalProcessorCount(void); i64 GetCurrentSchedulerPeriodNs(void); diff --git a/src/base/win32/base_win32.c b/src/base/win32/base_win32.c index 20a3a3b3..6fcb625e 100644 --- a/src/base/win32/base_win32.c +++ b/src/base/win32/base_win32.c @@ -1,3 +1,4 @@ #include "base_win32.h" #include "base_win32_job.c" +#include "base_win32_entry.c" diff --git a/src/base/win32/base_win32.h b/src/base/win32/base_win32.h index abc11eb3..73a46c67 100644 --- a/src/base/win32/base_win32.h +++ b/src/base/win32/base_win32.h @@ -4,5 +4,6 @@ #include "../base.h" #include "base_win32_job.h" +#include "base_win32_entry.h" #endif diff --git a/src/base/win32/base_win32_entry.c b/src/base/win32/base_win32_entry.c new file mode 100644 index 00000000..798c6d1f --- /dev/null +++ b/src/base/win32/base_win32_entry.c @@ -0,0 +1,292 @@ +W32_SharedEntryCtx W32_shared_entry_ctx = ZI; + +//////////////////////////////// +//~ Startup / shutdown jobs + +JobDef(W32_AppStartupJob, UNUSED sig, UNUSED id) +{ + W32_SharedEntryCtx *g = &W32_shared_entry_ctx; + TempArena scratch = BeginScratchNoConflict(); + { + EntryPoint(); + SetEvent(g->startup_end_event); + } + EndScratch(scratch); +} + +JobDef(W32_AppShutdownJob, UNUSED sig, UNUSED id) +{ + __prof; + W32_SharedEntryCtx *g = &W32_shared_entry_ctx; + i32 num_funcs = Atomic32Fetch(&g->num_exit_funcs); + for (i32 i = num_funcs - 1; i >= 0; --i) + { + ExitFunc *func = g->exit_funcs[i]; + func(); + } + SetEvent(g->exit_end_event); +} + + +//////////////////////////////// +//~ @hookdef Exit hooks + +void OnExit(ExitFunc *func) +{ + W32_SharedEntryCtx *g = &W32_shared_entry_ctx; + i32 index = Atomic32FetchAdd(&g->num_exit_funcs, 1); + if (index >= W32_MaxOnExitFuncs) + { + Panic(Lit("Maximum on exit functions registered")); + } + g->exit_funcs[index] = func; +} + +void Exit(void) +{ + W32_SharedEntryCtx *g = &W32_shared_entry_ctx; + SetEvent(g->exit_begin_event); +} + +void Panic(String msg) +{ + W32_SharedEntryCtx *g = &W32_shared_entry_ctx; + if (Atomic32FetchTestSet(&g->panicking, 0, 1) == 0) + { + //LogPanic(msg); + + wchar_t *wstr = g->panic_wstr; + u64 WstrLen = 0; + + wchar_t prefix[] = L"A fatal error has occured and the application needs to exit:\n\n"; + CopyBytes(wstr, prefix, MinU64(countof(g->panic_wstr), (countof(prefix) << 1))); + WstrLen += countof(prefix) - 1; + + /* Perform manual string encode to avoid any implicit memory + * allocation (in case allocation is unreliable) */ + String str8 = msg; + u64 pos8 = 0; + while (pos8 < str8.len) + { + String str8_remaining = { .len = (str8.len - pos8), .text = str8.text + pos8 }; + Utf8DecodeResult decoded = DecodeUtf8(str8_remaining); + Utf16EncodeResult encoded = EncodeUtf16(decoded.codepoint); + u64 wstr_new_len = WstrLen + encoded.count16; + if (wstr_new_len < (countof(g->panic_wstr) - 1)) + { + u16 *dest = wstr + WstrLen; + CopyBytes(dest, encoded.chars16, (encoded.count16 << 1)); + WstrLen = wstr_new_len; + pos8 += decoded.advance8; + } + else + { + break; + } + } + + wstr[WstrLen] = 0; + +#if RtcIsEnabled + MessageBoxExW(0, wstr, L"Fatal error", MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST, 0); + Assert(0); +#endif + + SetEvent(g->panic_event); + + /* Wait for process termination */ + if (GetCurrentThreadId() != g->main_thread_id) + { + Sleep(INFINITE); + } + } +} + + +//////////////////////////////// +//~ Winmain + +int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, _In_ LPWSTR cmdline_wstr, _In_ int show_code) +{ + LAX instance; + LAX prev_instance; + LAX cmdline_wstr; + LAX show_code; + + __profthread("Main thread", PROF_THREAD_GROUP_MAIN); + W32_SharedEntryCtx *g = &W32_shared_entry_ctx; + + +#if ProfilingIsEnabled + /* Start profiler */ + { + __profn("Launch profiler"); + STARTUPINFO si = ZI; + si.cb = sizeof(si); + PROCESS_INFORMATION pi = ZI; + wchar_t cmd[sizeof(ProfilingCmdWstr)] = ZI; + CopyBytes(cmd, ProfilingCmdWstr, sizeof(ProfilingCmdWstr)); + DeleteFileW(ProfilingOutFileWstr); + b32 success = CreateProcessW(0, cmd, 0, 0, 0, DETACHED_PROCESS, 0, 0, &si, &pi); + if (!success) + { + MessageBoxExW(0, L"Failed to launch profiler using command '" ProfilingCmdWstr L"'.", L"Error", MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST, 0); + } + } + /* Set internal profiler thread affinities */ + { + __profn("Set profiler thread affinities"); + wchar_t *prefix_name_wstr = ProfilerThreadPrefixWstr; + u64 prefix_name_wstr_len = ((i32)sizeof(ProfilerThreadPrefixWstr) >> 1) - 1; + if (prefix_name_wstr_len > 0 && ProfilerThreadAffinityMask != 0) + { + DWORD proc_id = GetCurrentProcessId(); + HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + if (snapshot != INVALID_HANDLE_VALUE) + { + THREADENTRY32 te = ZI; + te.dwSize = sizeof(THREADENTRY32); + if (Thread32First(snapshot, &te)) + { + do + { + if (te.th32OwnerProcessID == proc_id) + { + i32 thread_id = te.th32ThreadID; + HANDLE thread = OpenThread(THREAD_ALL_ACCESS, FALSE, thread_id); + if (thread) + { + wchar_t *thread_name_wstr = 0; + HRESULT hr = GetThreadDescription(thread, &thread_name_wstr); + if (SUCCEEDED(hr)) + { + u64 thread_name_len = WstrLenNoLimit(thread_name_wstr); + if (thread_name_len >= prefix_name_wstr_len && EqBytes(thread_name_wstr, prefix_name_wstr, prefix_name_wstr_len)) + { + __profn("Set profiler thread affinity"); + b32 success = SetThreadAffinityMask(thread, ProfilerThreadAffinityMask) != 0; + { + /* Retry until external tools can set correct process affinity */ + i32 delay_ms = 16; + while (!success && delay_ms <= 1024) + { + __profn("Profiler thread affinity retry"); + Sleep(delay_ms); + success = SetThreadAffinityMask(thread, ProfilerThreadAffinityMask) != 0; + delay_ms *= 2; + } + } + Assert(success); + LAX success; + } + } + CloseHandle(thread); + } + } + } while (Thread32Next(snapshot, &te)); + } + } + CloseHandle(snapshot); + } + } +#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); + + u64 cmdline_len = WstrLen(cmdline_wstr, countof(g->cmdline_args_wstr) - 1); + CopyBytes(g->cmdline_args_wstr, cmdline_wstr, cmdline_len * sizeof(*cmdline_wstr)); + g->cmdline_args_wstr[cmdline_len] = 0; + + g->main_thread_id = GetCurrentThreadId(); + SetThreadDescription(GetCurrentThread(), L"Main thread"); + + /* Query system info */ + GetSystemInfo(&g->info); + + /* Initialize base layer */ + BaseMain(); + + //- App startup + + /* Run app start job */ + if (!Atomic32Fetch(&g->panicking)) + { + RunJob(1, W32_AppStartupJob, 0, JobPool_Floating, JobPriority_High, 0); + } + + /* Wait for startup end or panic */ + if (!Atomic32Fetch(&g->panicking)) + { + HANDLE handles[] = { + g->startup_end_event, + g->panic_event + }; + WaitForMultipleObjects(countof(handles), handles, 0, INFINITE); + } + + /* Wait for exit start or panic */ + if (!Atomic32Fetch(&g->panicking)) + { + HANDLE handles[] = { + g->exit_begin_event, + g->panic_event + }; + WaitForMultipleObjects(countof(handles), handles, 0, INFINITE); + } + + //- App shutdown + + /* Run exit callbacks job */ + if (!Atomic32Fetch(&g->panicking)) + { + RunJob(1, W32_AppShutdownJob, 0, JobPool_Floating, JobPriority_High, 0); + } + + /* Wait for exit end or panic */ + if (!Atomic32Fetch(&g->panicking)) + { + HANDLE handles[] = { + g->exit_end_event, + g->panic_event + }; + WaitForMultipleObjects(countof(handles), handles, 0, INFINITE); + } + + /* Exit */ + i32 exit_code = 0; + if (Atomic32Fetch(&g->panicking)) + { + WaitForSingleObject(g->panic_event, INFINITE); + MessageBoxExW(0, g->panic_wstr, L"Fatal error", MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST, 0); + exit_code = 1; + } + return exit_code; +} + +//////////////////////////////// +//~ Crt stub + +#if !CrtlibIsEnabled + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmissing-variable-declarations" +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +/* Enable floating point */ +__attribute((used)) +int _fltused; + +__attribute((used)) +void __stdcall wWinMainCRTStartup(void) +{ + int result = wWinMain(GetModuleHandle(0), 0, GetCommandLineW(), 0); + ExitProcess(result); +} + +#pragma clang diagnostic pop + +#endif /* !CrtlibIsEnabled */ diff --git a/src/base/win32/base_win32_entry.h b/src/base/win32/base_win32_entry.h new file mode 100644 index 00000000..e1d6b9bd --- /dev/null +++ b/src/base/win32/base_win32_entry.h @@ -0,0 +1,33 @@ +//////////////////////////////// +//~ Shared state + +#define W32_MaxOnExitFuncs 1024 + +Struct(W32_SharedEntryCtx) +{ + SYSTEM_INFO info; + u32 main_thread_id; + Atomic32 shutdown; + + wchar_t cmdline_args_wstr[8192]; + + //- Application control flow + Atomic32 panicking; + wchar_t panic_wstr[4096]; + HANDLE panic_event; + HANDLE startup_end_event; + HANDLE exit_begin_event; + HANDLE exit_end_event; + + //- Exit funcs + Atomic32 num_exit_funcs; + ExitFunc *exit_funcs[W32_MaxOnExitFuncs]; +}; + +extern W32_SharedEntryCtx W32_shared_entry_ctx; + +//////////////////////////////// +//~ Startup / shutdown jobs + +JobDecl(W32_AppStartupJob, EmptySig); +JobDecl(W32_AppShutdownJob, EmptySig); diff --git a/src/base/win32/base_win32_job.c b/src/base/win32/base_win32_job.c index 7d349641..b280c369 100644 --- a/src/base/win32/base_win32_job.c +++ b/src/base/win32/base_win32_job.c @@ -1,4 +1,4 @@ -W32_SharedCtx W32_shared_ctx = ZI; +W32_SharedJobCtx W32_shared_job_ctx = ZI; /* FIXME: Enable logs, panic, shutdown */ @@ -21,7 +21,7 @@ W32_SharedCtx W32_shared_ctx = ZI; void StartupBaseJobs(void) { - W32_SharedCtx *g = &W32_shared_ctx; + W32_SharedJobCtx *g = &W32_shared_job_ctx; /* Init timer */ { @@ -133,7 +133,7 @@ void StartupBaseJobs(void) } } - //P_OnExit(ShutdownJobs); + //OnExit(ShutdownJobs); } //////////////////////////////// @@ -195,7 +195,7 @@ void ShutdownJobs(void) ++num_dangling_threads; } threads_msg = StringFormat(scratch.arena, Lit("%F dangling thread(s):\n%F"), FmtUint(num_dangling_threads), FmtString(threads_msg)); - //P_Panic(threads_msg); + //Panic(threads_msg); EndScratch(scratch); } UnlockTicketMutex(&g->threads_tm); @@ -237,7 +237,7 @@ W32_Thread *W32_AllocThread(W32_ThreadFunc *entry_point, void *thread_data, Stri { __prof; TempArena scratch = BeginScratchNoConflict(); - W32_SharedCtx *g = &W32_shared_ctx; + W32_SharedJobCtx *g = &W32_shared_job_ctx; Assert(entry_point != 0); //P_LogInfoF("Creating thread \"%F\"", FmtString(thread_name)); @@ -296,7 +296,7 @@ W32_Thread *W32_AllocThread(W32_ThreadFunc *entry_point, void *thread_data, Stri if (!t->handle) { - //P_Panic(Lit("Failed to create thread")); + //Panic(Lit("Failed to create thread")); } EndScratch(scratch); @@ -307,7 +307,7 @@ W32_Thread *W32_AllocThread(W32_ThreadFunc *entry_point, void *thread_data, Stri b32 W32_TryReleaseThread(W32_Thread *thread, f32 timeout_seconds) { __prof; - W32_SharedCtx *g = &W32_shared_ctx; + W32_SharedJobCtx *g = &W32_shared_job_ctx; b32 success = 0; W32_Thread *t = (W32_Thread *)thread; HANDLE handle = t->handle; @@ -366,7 +366,7 @@ void W32_WaitReleaseThread(W32_Thread *thread) /* REQUIRED: Caller must have acquired `wake_lock` for each fiber in array */ void W32_WakeLockedFibers(i32 num_fibers, W32_Fiber **fibers) { - W32_SharedCtx *g = &W32_shared_ctx; + W32_SharedJobCtx *g = &W32_shared_job_ctx; /* Update wait lists */ for (i32 i = 0; i < num_fibers; ++i) @@ -593,7 +593,7 @@ void W32_WakeLockedFibers(i32 num_fibers, W32_Fiber **fibers) void W32_WakeByAddress(void *addr, i32 count) { TempArena scratch = BeginScratchNoConflict(); - W32_SharedCtx *g = &W32_shared_ctx; + W32_SharedJobCtx *g = &W32_shared_job_ctx; u64 wait_addr_bin_index = (u64)addr % W32_NumWaitAddrBins; W32_WaitBin *wait_addr_bin = &g->wait_addr_bins[wait_addr_bin_index]; @@ -655,7 +655,7 @@ void W32_WakeByAddress(void *addr, i32 count) void W32_WakeByTime(u64 time) { TempArena scratch = BeginScratchNoConflict(); - W32_SharedCtx *g = &W32_shared_ctx; + W32_SharedJobCtx *g = &W32_shared_job_ctx; u64 wait_time_bin_index = (u64)time % W32_NumWaitTimeBins; W32_WaitBin *wait_time_bin = &g->wait_time_bins[wait_time_bin_index]; @@ -706,7 +706,7 @@ void W32_WakeByTime(u64 time) /* If `pool` is 0, then the currently running thread will be converted into a fiber */ W32_Fiber *W32_AllocFiber(W32_JobPool *pool) { - W32_SharedCtx *g = &W32_shared_ctx; + W32_SharedJobCtx *g = &W32_shared_job_ctx; i16 fiber_id = 0; W32_Fiber *fiber = 0; char *new_name_cstr = 0; @@ -730,7 +730,7 @@ W32_Fiber *W32_AllocFiber(W32_JobPool *pool) fiber_id = g->num_fibers++; if (fiber_id >= MaxFibers) { - //P_Panic(Lit("Max fibers reached")); + //Panic(Lit("Max fibers reached")); } fiber = &g->fibers[fiber_id]; new_name_cstr = PushStructs(g->fiber_names_arena, char, W32_FiberNameMaxSize); @@ -825,7 +825,7 @@ void W32_ReleaseFiber(W32_JobPool *pool, W32_Fiber *fiber) //- Fiber id ForceInline W32_Fiber *W32_FiberFromId(i16 id) { - W32_SharedCtx *g = &W32_shared_ctx; + W32_SharedJobCtx *g = &W32_shared_job_ctx; if (id <= 0) { return 0; @@ -898,7 +898,7 @@ void W32_FiberEntryPoint(void *id_ptr) W32_ThreadDef(W32_JobWorkerEntryFunc, worker_ctx_arg) { - W32_SharedCtx *g = &W32_shared_ctx; + W32_SharedJobCtx *g = &W32_shared_job_ctx; W32_WorkerCtx *ctx = worker_ctx_arg; JobPool pool_kind = ctx->pool_kind; W32_JobPool *pool = &g->job_pools[pool_kind]; @@ -1066,7 +1066,7 @@ W32_ThreadDef(W32_JobWorkerEntryFunc, worker_ctx_arg) { /* Invalid yield kind */ TempArena scratch = BeginScratchNoConflict(); - //P_Panic(StringFormat(scratch.arena, Lit("Invalid fiber yield kind \"%F\""), FmtSint(yield.kind))); + //Panic(StringFormat(scratch.arena, Lit("Invalid fiber yield kind \"%F\""), FmtSint(yield.kind))); EndScratch(scratch); } break; @@ -1280,7 +1280,7 @@ W32_ThreadDef(W32_JobWorkerEntryFunc, worker_ctx_arg) W32_ThreadDef(W32_JobSchedulerEntryFunc, UNUSED arg) { - struct W32_SharedCtx *g = &W32_shared_ctx; + struct W32_SharedJobCtx *g = &W32_shared_job_ctx; { i32 priority = THREAD_PRIORITY_TIME_CRITICAL; @@ -1293,7 +1293,7 @@ W32_ThreadDef(W32_JobSchedulerEntryFunc, UNUSED arg) HANDLE timer = CreateWaitableTimerExW(0, 0, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS); if (!timer) { - //P_Panic(Lit("Failed to create high resolution timer")); + //Panic(Lit("Failed to create high resolution timer")); } /* Create rolling buffer of scheduler cycles initialized to default value */ @@ -1419,7 +1419,7 @@ GenericJobDesc *PushJobDesc_(u64 sig_size, u64 sig_align, GenericJobFunc *func, void RunJobEx(GenericJobDesc *desc) { __prof; - struct W32_SharedCtx *g = &W32_shared_ctx; + struct W32_SharedJobCtx *g = &W32_shared_job_ctx; i32 count = desc->count; Counter *counter = desc->counter; JobPool pool_kind = desc->pool; @@ -1496,25 +1496,25 @@ void RunJobEx(GenericJobDesc *desc) i64 TimeNs(void) { - struct W32_SharedCtx *g = &W32_shared_ctx; + struct W32_SharedJobCtx *g = &W32_shared_job_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(); } +u32 GetLogicalProcessorCount(void) +{ + return GetActiveProcessorCount(ALL_PROCESSOR_GROUPS); +} + i64 GetCurrentSchedulerPeriodNs(void) { - W32_SharedCtx *g = &W32_shared_ctx; + W32_SharedJobCtx *g = &W32_shared_job_ctx; return Atomic64Fetch(&g->current_scheduler_cycle_period_ns.v); } diff --git a/src/base/win32/base_win32_job.h b/src/base/win32/base_win32_job.h index ae56ffbe..ac7245b4 100644 --- a/src/base/win32/base_win32_job.h +++ b/src/base/win32/base_win32_job.h @@ -213,7 +213,7 @@ AlignedStruct(W32_JobPool, 64) /* Arbitrary threshold for determining when to fall back from a looped WakeByAddressSingle to WakeByAddressAll */ #define W32_WakeAllThreshold 16 -Struct(W32_SharedCtx) +Struct(W32_SharedJobCtx) { i64 timer_start_qpc; i64 ns_per_qpc; @@ -249,7 +249,7 @@ Struct(W32_SharedCtx) W32_JobPool job_pools[JobPool_Count]; }; -extern W32_SharedCtx W32_shared_ctx; +extern W32_SharedJobCtx W32_shared_job_ctx; //////////////////////////////// //~ Startup diff --git a/src/font/font_core.c b/src/font/font_core.c index 0884acb0..a791457a 100644 --- a/src/font/font_core.c +++ b/src/font/font_core.c @@ -40,7 +40,7 @@ JobDef(F_LoadJob, sig, _) if (!RES_ResourceExists(&res)) { /* FIME: Load baked font instead of panicking */ - P_Panic(StringFormat(scratch.arena, + Panic(StringFormat(scratch.arena, Lit("Font \"%F\" not found"), FmtString(path))); } @@ -70,7 +70,7 @@ JobDef(F_LoadJob, sig, _) /* FIXME: Load baked font instead of panicking */ if (font->glyphs_count <= 0) { - P_Panic(StringFormat(scratch.arena, + Panic(StringFormat(scratch.arena, Lit("Parsed 0 glyphs from font \"%F\"!"), FmtString(path))); } diff --git a/src/gpu/gpu_dx12.c b/src/gpu/gpu_dx12.c index 05f24e24..893d4eea 100644 --- a/src/gpu/gpu_dx12.c +++ b/src/gpu/gpu_dx12.c @@ -24,7 +24,7 @@ void GPU_StartupCore(void) GPU_D12_SharedState *g = &GPU_D12_shared_state; if (Atomic32FetchTestSet(&g->initialized, 0, 1) != 0) { - P_Panic(Lit("GP layer already initialized")); + Panic(Lit("GP layer already initialized")); } /* Initialize command descriptor heaps pool */ @@ -53,7 +53,7 @@ void GPU_StartupCore(void) String embedded_data = INC_GetDxcTar(); if (embedded_data.len <= 0) { - P_Panic(Lit("No embedded shaders found")); + Panic(Lit("No embedded shaders found")); } g->dxc_archive = TAR_ArchiveFromString(g->pipelines_arena, embedded_data, Lit("")); @@ -68,13 +68,13 @@ void GPU_StartupCore(void) #if RESOURCE_RELOADING W_RegisterCallback(GPU_D12_WatchPipelineCallback); #endif - P_OnExit(GPU_D12_Shutdown); + OnExit(GPU_D12_Shutdown); /* Start evictor job */ RunJob(1, GPU_D12_EvictorJob, JobPool_Background, JobPriority_Low, &g->evictor_job_counter, 0); } -P_ExitFuncDef(GPU_D12_Shutdown) +ExitFuncDef(GPU_D12_Shutdown) { __prof; GPU_D12_SharedState *g = &GPU_D12_shared_state; @@ -108,7 +108,7 @@ void GPU_D12_PushInitError(String error) { TempArena scratch = BeginScratchNoConflict(); String msg = StringFormat(scratch.arena, Lit("Failed to initialize DirectX 12.\n\n%F"), FmtString(error)); - P_Panic(msg); + Panic(msg); EndScratch(scratch); } @@ -464,7 +464,7 @@ void GPU_D12_InitNoise(void) String data = RES_GetResourceData(&noise_res); if (data.len != expected_size) { - P_Panic(StringFormat(scratch.arena, + Panic(StringFormat(scratch.arena, Lit("Noise texture has unexpected size for a %Fx%Fx%F texture (expected %F, got %F)"), FmtUint(K_BLUE_NOISE_TEX_WIDTH), FmtUint(K_BLUE_NOISE_TEX_HEIGHT), FmtUint(K_BLUE_NOISE_TEX_DEPTH), FmtUint(expected_size), FmtUint(data.len))); @@ -503,7 +503,7 @@ void GPU_D12_InitNoise(void) } else { - P_Panic(StringFormat(scratch.arena, Lit("Noise resource \"%F\" not found"), FmtString(noise_res_name))); + Panic(StringFormat(scratch.arena, Lit("Noise resource \"%F\" not found"), FmtString(noise_res_name))); } RES_CloseResource(&noise_res); } @@ -1237,7 +1237,7 @@ GPU_D12_Descriptor *GPU_D12_AllocDescriptor(GPU_D12_CpuDescriptorHeap *dh) { if (dh->num_descriptors_reserved >= dh->num_descriptors_capacity) { - P_Panic(Lit("Max descriptors reached in heap")); + Panic(Lit("Max descriptors reached in heap")); } d = PushStructNoZero(dh->arena, GPU_D12_Descriptor); index = dh->num_descriptors_reserved++; @@ -1287,7 +1287,7 @@ GPU_D12_CpuDescriptorHeap *GPU_D12_AllocCpuDescriptorHeap(enum D3D12_DESCRIPTOR_ } if (num_descriptors == 0 || descriptor_size == 0) { - P_Panic(Lit("Unsupported CPU descriptor type")); + Panic(Lit("Unsupported CPU descriptor type")); } dh->num_descriptors_capacity = num_descriptors; dh->descriptor_size = descriptor_size; @@ -1298,7 +1298,7 @@ GPU_D12_CpuDescriptorHeap *GPU_D12_AllocCpuDescriptorHeap(enum D3D12_DESCRIPTOR_ HRESULT hr = ID3D12Device_CreateDescriptorHeap(g->device, &desc, &IID_ID3D12DescriptorHeap, (void **)&dh->heap); if (FAILED(hr)) { - P_Panic(Lit("Failed to create CPU descriptor heap")); + Panic(Lit("Failed to create CPU descriptor heap")); } ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(dh->heap, &dh->handle); @@ -1388,7 +1388,7 @@ GPU_D12_Resource *GPU_D12_AllocResource(D3D12_HEAP_PROPERTIES heap_props, D3D12_ if (FAILED(hr)) { /* TODO: Don't panic */ - P_Panic(Lit("Failed to create resource")); + Panic(Lit("Failed to create resource")); } r->state = initial_state; @@ -1524,13 +1524,13 @@ JobDef(GPU_D12_AllocCommandQueueJob, sig, id) HRESULT hr = ID3D12Device_CreateCommandQueue(g->device, &dx12_desc, &IID_ID3D12CommandQueue, (void **)&cq->cq); if (FAILED(hr)) { - P_Panic(Lit("Failed to create command queue")); + Panic(Lit("Failed to create command queue")); } hr = ID3D12Device_CreateFence(g->device, 0, 0, &IID_ID3D12Fence, (void **)&cq->submit_fence); if (FAILED(hr)) { - P_Panic(Lit("Failed to create command queue fence")); + Panic(Lit("Failed to create command queue fence")); } cq->cl_pool = GPU_D12_AllocCommandListPool(cq); @@ -1630,19 +1630,19 @@ GPU_D12_CommandList *GPU_D12_BeginCommandList(GPU_D12_CommandListPool *pool) hr = ID3D12Device_CreateCommandAllocator(g->device, cq->desc.type, &IID_ID3D12CommandAllocator, (void **)&cl->ca); if (FAILED(hr)) { - P_Panic(Lit("Failed to create command allocator")); + Panic(Lit("Failed to create command allocator")); } hr = ID3D12Device_CreateCommandList(g->device, 0, cq->desc.type, cl->ca, 0, &IID_ID3D12GraphicsCommandList, (void **)&cl->cl); if (FAILED(hr)) { - P_Panic(Lit("Failed to create command list")); + Panic(Lit("Failed to create command list")); } hr = ID3D12GraphicsCommandList_Close(cl->cl); if (FAILED(hr)) { - P_Panic(Lit("Failed to close command list during initialization")); + Panic(Lit("Failed to close command list during initialization")); } } @@ -1650,13 +1650,13 @@ GPU_D12_CommandList *GPU_D12_BeginCommandList(GPU_D12_CommandListPool *pool) hr = ID3D12CommandAllocator_Reset(cl->ca); if (FAILED(hr)) { - P_Panic(Lit("Failed to reset command allocator")); + Panic(Lit("Failed to reset command allocator")); } hr = ID3D12GraphicsCommandList_Reset(cl->cl, cl->ca, 0); if (FAILED(hr)) { - P_Panic(Lit("Failed to reset command list")); + Panic(Lit("Failed to reset command list")); } return cl; @@ -1677,7 +1677,7 @@ u64 GPU_D12_EndCommandList(GPU_D12_CommandList *cl) if (FAILED(hr)) { /* TODO: Don't panic */ - P_Panic(Lit("Failed to close command list before execution")); + Panic(Lit("Failed to close command list before execution")); } } @@ -1834,7 +1834,7 @@ GPU_D12_CommandDescriptorHeap *GPU_D12_PushDescriptorHeap(GPU_D12_CommandList *c HRESULT hr = ID3D12Device_CreateDescriptorHeap(g->device, &desc, &IID_ID3D12DescriptorHeap, (void **)&cdh->heap); if (FAILED(hr)) { - P_Panic(Lit("Failed to create GPU descriptor heap")); + Panic(Lit("Failed to create GPU descriptor heap")); } ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(cdh->heap, &cdh->start_cpu_handle); ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(cdh->heap, &cdh->start_gpu_handle); @@ -1987,7 +1987,7 @@ GPU_D12_CommandBuffer *GPU_D12__PushCommandBuffer(GPU_D12_CommandList *cl, u64 d if (FAILED(hr) || !dst) { /* TODO: Don't panic */ - P_Panic(Lit("Failed to map command buffer resource")); + Panic(Lit("Failed to map command buffer resource")); } CopyBytes(dst, data, data_len); ID3D12Resource_Unmap(cb->resource->resource, 0, 0); @@ -2029,7 +2029,7 @@ GPU_Resource *GPU_AllocTexture(GPU_TextureFormat format, u32 flags, Vec2I32 size GPU_D12_SharedState *g = &GPU_D12_shared_state; if (size.x <= 0 || size.y <= 0) { - P_Panic(Lit("Tried to create texture with dimension <= 0")); + Panic(Lit("Tried to create texture with dimension <= 0")); } LocalPersist const DXGI_FORMAT formats[] = { [GP_TEXTURE_FORMAT_R8_UNORM] = DXGI_FORMAT_R8_UNORM, @@ -2045,7 +2045,7 @@ GPU_Resource *GPU_AllocTexture(GPU_TextureFormat format, u32 flags, Vec2I32 size } if (format == 0) { - P_Panic(Lit("Tried to create texture with unknown format")); + Panic(Lit("Tried to create texture with unknown format")); } D3D12_HEAP_PROPERTIES heap_props = { .Type = D3D12_HEAP_TYPE_DEFAULT }; @@ -2158,7 +2158,7 @@ JobDef(GPU_D12_UploadJob, sig, UNUSED id) if (FAILED(hr) || !mapped) { /* TODO: Don't panic */ - P_Panic(Lit("Failed to map texture upload resource")); + Panic(Lit("Failed to map texture upload resource")); } u8 *dst = (u8 *)mapped + placed_footprint.Offset; u8 *src = data; @@ -2998,7 +2998,7 @@ void GPU_D12_InitSwapchainResources(GPU_D12_Swapchain *swapchain) if (FAILED(hr)) { /* TODO: Don't panic */ - P_Panic(Lit("Failed to get swapchain buffer")); + Panic(Lit("Failed to get swapchain buffer")); } GPU_D12_SwapchainBuffer *sb = &swapchain->buffers[i]; ZeroStruct(sb); @@ -3050,7 +3050,7 @@ GPU_Swapchain *GPU_AllocSwapchain(P_Window *window, Vec2I32 resolution) hr = IDXGIFactory2_CreateSwapChainForHwnd(g->factory, (IUnknown *)cq->cq, hwnd, &desc, 0, 0, &swapchain1); if (FAILED(hr)) { - P_Panic(Lit("Failed to create IDXGISwapChain1")); + Panic(Lit("Failed to create IDXGISwapChain1")); } } @@ -3058,7 +3058,7 @@ GPU_Swapchain *GPU_AllocSwapchain(P_Window *window, Vec2I32 resolution) hr = IDXGISwapChain1_QueryInterface(swapchain1, &IID_IDXGISwapChain3, (void **)&swapchain->swapchain); if (FAILED(hr)) { - P_Panic(Lit("Failed to create IDXGISwapChain3")); + Panic(Lit("Failed to create IDXGISwapChain3")); } /* Create waitable object */ @@ -3137,7 +3137,7 @@ GPU_D12_SwapchainBuffer *GPU_D12_UpdateSwapchain(GPU_D12_Swapchain *swapchain, V if (FAILED(hr)) { /* TODO: Don't panic */ - P_Panic(Lit("Failed to resize swapchain")); + Panic(Lit("Failed to resize swapchain")); } } Unlock(&lock); diff --git a/src/gpu/gpu_dx12.h b/src/gpu/gpu_dx12.h index 100478ea..ddef9ec8 100644 --- a/src/gpu/gpu_dx12.h +++ b/src/gpu/gpu_dx12.h @@ -425,7 +425,7 @@ extern GPU_D12_SharedState GPU_D12_shared_state; * Startup * ========================== */ -P_ExitFuncDef(GPU_D12_Shutdown); +ExitFuncDef(GPU_D12_Shutdown); /* ========================== * * Dx12 device initialization diff --git a/src/platform/platform.c b/src/platform/platform.c index 00f493c8..185975ec 100644 --- a/src/platform/platform.c +++ b/src/platform/platform.c @@ -11,6 +11,7 @@ void P_Main(void) { RunOnce(); P_StartupDeps(); + P_StartupCore(); /* FIXME: Logfile path */ P_StartupLog(Lit("log.log")); } diff --git a/src/platform/platform_core.h b/src/platform/platform_core.h index 1b7c8a01..a5e68829 100644 --- a/src/platform/platform_core.h +++ b/src/platform/platform_core.h @@ -302,10 +302,9 @@ typedef i32 P_MessageBoxKind; enum }; //////////////////////////////// -//~ Exit callback types +//~ @hookdecl Startup -#define P_ExitFuncDef(name) void name(void) -typedef P_ExitFuncDef(P_ExitFunc); +void P_StartupCore(void); //////////////////////////////// //~ @hookdecl Time helper operations @@ -412,9 +411,9 @@ void P_SleepFrame(i64 last_frame_time_ns, i64 target_dt_ns); //////////////////////////////// //~ @hookdecl Program exit -void P_OnExit(P_ExitFunc *func); -void P_Exit(void); -void P_Panic(String msg); +void OnExit(ExitFunc *func); +void Exit(void); +void Panic(String msg); //////////////////////////////// //~ @hookdecl Entry point (implemented per application) diff --git a/src/platform/platform_log.c b/src/platform/platform_log.c index ad671798..f5379f42 100644 --- a/src/platform/platform_log.c +++ b/src/platform/platform_log.c @@ -145,7 +145,7 @@ void P_Log_(i32 level, String msg) P_LogLevelSettings settings = P_log_settings[level]; if (level < 0 || level >= P_LogLevel_Count) { - P_Panic(Lit("Invalid log level")); + Panic(Lit("Invalid log level")); } diff --git a/src/platform/platform_log.h b/src/platform/platform_log.h index 3cb6f5c5..454771a1 100644 --- a/src/platform/platform_log.h +++ b/src/platform/platform_log.h @@ -122,8 +122,6 @@ void P_StartupLog(String logfile_path); //////////////////////////////// //~ Logging macros -#define log_panic(msg) P_LogPanic_(msg) - #if P_LogLevel(P_LogLevel_Critical) # if P_IncludeLogSourceLocation # define P_LogCritical(msg) P_Log_(P_LogLevel_Critical, Lit(__FILE__), __LINE__, msg) diff --git a/src/platform/platform_win32.c b/src/platform/platform_win32.c index 29bcbe49..00bcc4ad 100644 --- a/src/platform/platform_win32.c +++ b/src/platform/platform_win32.c @@ -14,6 +14,107 @@ P_W32_SharedCtx P_W32_shared_ctx = ZI; #pragma comment(lib, "avrt") #pragma comment(lib, "ws2_32.lib") +//////////////////////////////// +//~ @hookdef Startup + +void P_StartupCore(void) +{ + P_W32_SharedCtx *g = &P_W32_shared_ctx; + + //- 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 success = RegisterRawInputDevices(&rid, 1, sizeof(rid)); + Assert(success); + LAX success; + } + + //- Init watches pool + g->watches_arena = AllocArena(Gibi(64)); + + //- Init windows pool + g->windows_arena = AllocArena(Gibi(64)); + + //- Init winsock + WSAStartup(MAKEWORD(2, 2), &g->wsa_data); + g->socks_arena = AllocArena(Gibi(64)); +} + //////////////////////////////// //~ Win32 time @@ -864,7 +965,7 @@ void P_MkDir(String path) Lit("Failed to create directory \"%F\": %F"), FmtString(path), FmtString(err)); - P_Panic(msg); + Panic(msg); } EndScratch(scratch); } @@ -1018,7 +1119,7 @@ void P_WriteFile(P_File file, String data) if (data.len >= 0x7FFF) { TempArena scratch = BeginScratchNoConflict(); - P_Panic(StringFormat(scratch.arena, + Panic(StringFormat(scratch.arena, Lit("Tried to write too many bytes to disk (%F)"), FmtUint(data.len))); EndScratch(scratch); @@ -1922,386 +2023,3 @@ void P_SleepFrame(i64 last_frame_time_ns, i64 target_dt_ns) } } } - -//////////////////////////////// -//~ @hookdef Exit hooks - -void P_OnExit(P_ExitFunc *func) -{ - P_W32_SharedCtx *g = &P_W32_shared_ctx; - i32 index = Atomic32FetchAdd(&g->num_exit_funcs, 1); - if (index >= P_W32_MaxOnExitFuncs) - { - P_Panic(Lit("Maximum on exit functions registered")); - } - g->exit_funcs[index] = func; -} - -void P_Exit(void) -{ - P_W32_SharedCtx *g = &P_W32_shared_ctx; - SetEvent(g->exit_begin_event); -} - -void P_Panic(String msg) -{ - P_W32_SharedCtx *g = &P_W32_shared_ctx; - if (Atomic32FetchTestSet(&g->panicking, 0, 1) == 0) - { - log_panic(msg); - - wchar_t *wstr = g->panic_wstr; - u64 WstrLen = 0; - - wchar_t prefix[] = L"A fatal error has occured and the application needs to exit:\n\n"; - CopyBytes(wstr, prefix, MinU64(countof(g->panic_wstr), (countof(prefix) << 1))); - WstrLen += countof(prefix) - 1; - - /* Perform manual string encode to avoid any implicit memory - * allocation (in case allocation is unreliable) */ - String str8 = msg; - u64 pos8 = 0; - while (pos8 < str8.len) - { - String str8_remaining = { .len = (str8.len - pos8), .text = str8.text + pos8 }; - Utf8DecodeResult decoded = DecodeUtf8(str8_remaining); - Utf16EncodeResult encoded = EncodeUtf16(decoded.codepoint); - u64 wstr_new_len = WstrLen + encoded.count16; - if (wstr_new_len < (countof(g->panic_wstr) - 1)) - { - u16 *dest = wstr + WstrLen; - CopyBytes(dest, encoded.chars16, (encoded.count16 << 1)); - WstrLen = wstr_new_len; - pos8 += decoded.advance8; - } - else - { - break; - } - } - - wstr[WstrLen] = 0; - -#if RtcIsEnabled - MessageBoxExW(0, wstr, L"Fatal error", MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST, 0); - Assert(0); -#endif - - SetEvent(g->panic_event); - - /* Wait for process termination */ - if (GetCurrentThreadId() != g->main_thread_id) - { - Sleep(INFINITE); - } - } -} - -//////////////////////////////// -//~ Win32 entry point - -void P_W32_InitBtnTable(void) -{ - P_W32_SharedCtx *g = &P_W32_shared_ctx; - 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; -} - -JobDef(P_W32_AppStartupJob, UNUSED sig, UNUSED id) -{ - P_W32_SharedCtx *g = &P_W32_shared_ctx; - TempArena scratch = BeginScratchNoConflict(); - { - String cmdline_args = StringFromWstr(scratch.arena, g->cmdline_args_wstr, countof(g->cmdline_args_wstr)); - P_AppStartup(cmdline_args); - SetEvent(g->startup_end_event); - } - EndScratch(scratch); -} - -JobDef(P_W32_AppShutdownJob, UNUSED sig, UNUSED id) -{ - __prof; - P_W32_SharedCtx *g = &P_W32_shared_ctx; - i32 num_funcs = Atomic32Fetch(&g->num_exit_funcs); - for (i32 i = num_funcs - 1; i >= 0; --i) - { - P_ExitFunc *func = g->exit_funcs[i]; - func(); - } - SetEvent(g->exit_end_event); -} - -int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, _In_ LPWSTR cmdline_wstr, _In_ int show_code) -{ - P_Main(); - - LAX instance; - LAX prev_instance; - LAX cmdline_wstr; - LAX show_code; - - __profthread("Main thread", PROF_THREAD_GROUP_MAIN); - P_W32_SharedCtx *g = &P_W32_shared_ctx; - -#if ProfilingIsEnabled - /* Start profiler */ - { - __profn("Launch profiler"); - STARTUPINFO si = ZI; - si.cb = sizeof(si); - PROCESS_INFORMATION pi = ZI; - wchar_t cmd[sizeof(ProfilingCmdWstr)] = ZI; - CopyBytes(cmd, ProfilingCmdWstr, sizeof(ProfilingCmdWstr)); - DeleteFileW(ProfilingOutFileWstr); - b32 success = CreateProcessW(0, cmd, 0, 0, 0, DETACHED_PROCESS, 0, 0, &si, &pi); - if (!success) - { - MessageBoxExW(0, L"Failed to launch profiler using command '" ProfilingCmdWstr L"'.", L"Error", MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST, 0); - } - } - /* Set internal profiler thread affinities */ - { - __profn("Set profiler thread affinities"); - wchar_t *prefix_name_wstr = ProfilerThreadPrefixWstr; - u64 prefix_name_wstr_len = ((i32)sizeof(ProfilerThreadPrefixWstr) >> 1) - 1; - if (prefix_name_wstr_len > 0 && ProfilerThreadAffinityMask != 0) - { - DWORD proc_id = GetCurrentProcessId(); - HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); - if (snapshot != INVALID_HANDLE_VALUE) - { - THREADENTRY32 te = ZI; - te.dwSize = sizeof(THREADENTRY32); - if (Thread32First(snapshot, &te)) - { - do - { - if (te.th32OwnerProcessID == proc_id) - { - i32 thread_id = te.th32ThreadID; - HANDLE thread = OpenThread(THREAD_ALL_ACCESS, FALSE, thread_id); - if (thread) - { - wchar_t *thread_name_wstr = 0; - HRESULT hr = GetThreadDescription(thread, &thread_name_wstr); - if (SUCCEEDED(hr)) - { - u64 thread_name_len = WstrLenNoLimit(thread_name_wstr); - if (thread_name_len >= prefix_name_wstr_len && EqBytes(thread_name_wstr, prefix_name_wstr, prefix_name_wstr_len)) - { - __profn("Set profiler thread affinity"); - b32 success = SetThreadAffinityMask(thread, ProfilerThreadAffinityMask) != 0; - { - /* Retry until external tools can set correct process affinity */ - i32 delay_ms = 16; - while (!success && delay_ms <= 1024) - { - __profn("Profiler thread affinity retry"); - Sleep(delay_ms); - success = SetThreadAffinityMask(thread, ProfilerThreadAffinityMask) != 0; - delay_ms *= 2; - } - } - Assert(success); - LAX success; - } - } - CloseHandle(thread); - } - } - } while (Thread32Next(snapshot, &te)); - } - } - CloseHandle(snapshot); - } - } -#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); - - u64 cmdline_len = WstrLen(cmdline_wstr, countof(g->cmdline_args_wstr) - 1); - CopyBytes(g->cmdline_args_wstr, cmdline_wstr, cmdline_len * sizeof(*cmdline_wstr)); - g->cmdline_args_wstr[cmdline_len] = 0; - - g->main_thread_id = GetCurrentThreadId(); - SetThreadDescription(GetCurrentThread(), L"Main thread"); - - /* Query system info */ - GetSystemInfo(&g->info); - - /* Initialize vk table */ - P_W32_InitBtnTable(); - - /* Create window class */ - { - /* 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)) - { - P_Panic(Lit("Failed to register window class")); - } - } - - /* Register raw input */ - if (!Atomic32Fetch(&g->panicking)) - { - 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 success = RegisterRawInputDevices(&rid, 1, sizeof(rid)); - Assert(success); - LAX success; - } - - /* Init watches pool */ - g->watches_arena = AllocArena(Gibi(64)); - - /* Init windows pool */ - g->windows_arena = AllocArena(Gibi(64)); - - /* Init winsock */ - WSAStartup(MAKEWORD(2, 2), &g->wsa_data); - g->socks_arena = AllocArena(Gibi(64)); - - //- App startup - - /* Run app start job */ - if (!Atomic32Fetch(&g->panicking)) - { - RunJob(1, P_W32_AppStartupJob, 0, JobPool_Floating, JobPriority_High, 0); - } - - /* Wait for startup end or panic */ - if (!Atomic32Fetch(&g->panicking)) - { - HANDLE handles[] = { - g->startup_end_event, - g->panic_event - }; - WaitForMultipleObjects(countof(handles), handles, 0, INFINITE); - } - - /* Wait for exit start or panic */ - if (!Atomic32Fetch(&g->panicking)) - { - HANDLE handles[] = { - g->exit_begin_event, - g->panic_event - }; - WaitForMultipleObjects(countof(handles), handles, 0, INFINITE); - } - - //- App shutdown - - /* Run exit callbacks job */ - if (!Atomic32Fetch(&g->panicking)) - { - RunJob(1, P_W32_AppShutdownJob, 0, JobPool_Floating, JobPriority_High, 0); - } - - /* Wait for exit end or panic */ - if (!Atomic32Fetch(&g->panicking)) - { - HANDLE handles[] = { - g->exit_end_event, - g->panic_event - }; - WaitForMultipleObjects(countof(handles), handles, 0, INFINITE); - } - - /* Exit */ - i32 exit_code = 0; - if (Atomic32Fetch(&g->panicking)) - { - WaitForSingleObject(g->panic_event, INFINITE); - MessageBoxExW(0, g->panic_wstr, L"Fatal error", MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST, 0); - exit_code = 1; - } - return exit_code; -} - -//////////////////////////////// -//~ Crt stub - -#if !CrtlibIsEnabled - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wmissing-variable-declarations" -#pragma clang diagnostic ignored "-Wmissing-prototypes" - - /* Enable floating point */ -__attribute((used)) -int _fltused; - -__attribute((used)) -void __stdcall wWinMainCRTStartup(void) -{ - int result = wWinMain(GetModuleHandle(0), 0, GetCommandLineW(), 0); - ExitProcess(result); -} - -#pragma clang diagnostic pop - -#endif /* !CrtlibIsEnabled */ diff --git a/src/platform/platform_win32.h b/src/platform/platform_win32.h index 3068110b..60a4e317 100644 --- a/src/platform/platform_win32.h +++ b/src/platform/platform_win32.h @@ -108,24 +108,8 @@ Struct(P_W32_Sock) #define P_W32_WindowClassName L"power_play_window_class" -#define P_W32_MaxOnExitFuncs 1024 - Struct(P_W32_SharedCtx) { - SYSTEM_INFO info; - u32 main_thread_id; - Atomic32 shutdown; - - wchar_t cmdline_args_wstr[8192]; - - //- Application control flow - Atomic32 panicking; - wchar_t panic_wstr[4096]; - HANDLE panic_event; - HANDLE startup_end_event; - HANDLE exit_begin_event; - HANDLE exit_end_event; - //- Key lookup table P_Btn vk_btn_table[256]; @@ -145,10 +129,6 @@ Struct(P_W32_SharedCtx) Arena *socks_arena; Mutex socks_mutex; P_W32_Sock *first_free_sock; - - //- Exit funcs - Atomic32 num_exit_funcs; - P_ExitFunc *exit_funcs[P_W32_MaxOnExitFuncs]; }; extern P_W32_SharedCtx P_W32_shared_ctx; @@ -186,10 +166,3 @@ LRESULT CALLBACK P_W32_Win32WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARA P_W32_Address P_W32_Win32AddressFromPlatformAddress(P_Address addr); P_W32_Address P_W32_ConvertAnyaddrToLocalhost(P_W32_Address addr); P_Address P_W32_PlatformAddressFromWin32Address(P_W32_Address ws_addr); - -//////////////////////////////// -//~ Entry point - -void P_W32_InitBtnTable(void); -JobDecl(P_W32_AppStartupJob, EmptySig); -JobDecl(P_W32_AppShutdownJob, EmptySig); diff --git a/src/playback/playback_win32.c b/src/playback/playback_win32.c index 82a69063..6cb97f5b 100644 --- a/src/playback/playback_win32.c +++ b/src/playback/playback_win32.c @@ -16,10 +16,10 @@ void PB_StartupCore(void) PB_WSP_InitializeWasapi(); /* Start playback job */ RunJob(1, PB_WSP_PlaybackJob, 0, JobPool_Audio, JobPriority_High, &g->PB_WSP_PlaybackJob_counter); - P_OnExit(&PB_WSP_Shutdown); + OnExit(&PB_WSP_Shutdown); } -P_ExitFuncDef(PB_WSP_Shutdown) +ExitFuncDef(PB_WSP_Shutdown) { __prof; PB_WSP_SharedState *g = &PB_WSP_shared_state; diff --git a/src/playback/playback_win32.h b/src/playback/playback_win32.h index cd5cad81..169617b2 100644 --- a/src/playback/playback_win32.h +++ b/src/playback/playback_win32.h @@ -48,7 +48,7 @@ extern PB_WSP_SharedState PB_WSP_shared_state; //~ Wasapi startup void PB_WSP_InitializeWasapi(void); -P_ExitFuncDef(PB_WSP_Shutdown); +ExitFuncDef(PB_WSP_Shutdown); //////////////////////////////// //~ Playback update diff --git a/src/pp/pp_core.c b/src/pp/pp_core.c index e6b175d5..1b7f92fd 100644 --- a/src/pp/pp_core.c +++ b/src/pp/pp_core.c @@ -46,13 +46,13 @@ void StartupUser(void) /* Start jobs */ RunJob(1, UpdateUserJob, 0, JobPool_User, JobPriority_High, &g->shutdown_job_counters); RunJob(1, SimJob, 0, JobPool_Sim, JobPriority_High, &g->shutdown_job_counters); - P_OnExit(&ShutdownUser); + OnExit(&ShutdownUser); } //////////////////////////////// //~ Shutdown -P_ExitFuncDef(ShutdownUser) +ExitFuncDef(ShutdownUser) { __prof; SharedUserState *g = &shared_user_state; @@ -553,7 +553,7 @@ void UpdateUser(P_Window *window) P_WindowEvent *event = &events.events[ent_index]; if (event->kind == P_WindowEventKind_Quit) { - P_Exit(); + Exit(); } if (event->kind == P_WindowEventKind_ButtonUp) @@ -561,7 +561,7 @@ void UpdateUser(P_Window *window) /* Escape quit */ if (event->button == P_Btn_ESC) { - P_Exit(); + Exit(); } } diff --git a/src/pp/pp_core.h b/src/pp/pp_core.h index ea87c796..b67f921b 100644 --- a/src/pp/pp_core.h +++ b/src/pp/pp_core.h @@ -257,7 +257,7 @@ void StartupUser(void); //////////////////////////////// //~ Shutdown -P_ExitFuncDef(ShutdownUser); +ExitFuncDef(ShutdownUser); //////////////////////////////// //~ Debug draw operations diff --git a/src/resource/resource_core.c b/src/resource/resource_core.c index 859754f4..817e51b6 100644 --- a/src/resource/resource_core.c +++ b/src/resource/resource_core.c @@ -13,14 +13,14 @@ void RES_StartupCore(void) String embedded_data = INC_GetResTar(); if (embedded_data.len <= 0) { - P_Panic(Lit("No embedded resources found")); + Panic(Lit("No embedded resources found")); } g->archive = TAR_ArchiveFromString(g->arena, embedded_data, Lit("")); #else /* Ensure we have the right working directory */ if (!P_IsDir(Lit("res"))) { - P_Panic(Lit("Resource directory \"res\" not found. Make sure the executable is being launched from the correct working directory.")); + Panic(Lit("Resource directory \"res\" not found. Make sure the executable is being launched from the correct working directory.")); } #endif } diff --git a/src/sprite/sprite_core.c b/src/sprite/sprite_core.c index bad2a1c9..93c4edf5 100644 --- a/src/sprite/sprite_core.c +++ b/src/sprite/sprite_core.c @@ -44,7 +44,7 @@ void S_StartupCore(void) RunJob(1, S_EvictorJob, JobPool_Background, JobPriority_Low, &g->shutdown_counter, 0); - P_OnExit(&S_Shutdown); + OnExit(&S_Shutdown); #if RESOURCE_RELOADING W_RegisterCallback(&S_WatchSpriteCallback); #endif @@ -53,7 +53,7 @@ void S_StartupCore(void) //////////////////////////////// //~ Shutdown -P_ExitFuncDef(S_Shutdown) +ExitFuncDef(S_Shutdown) { __prof; S_SharedState *g = &S_shared_state; @@ -433,7 +433,7 @@ JobDef(S_LoadSpriteJob, sig, UNUSED id) { S_LoadCacheEntrySheet(ref, tag); } break; - default: { P_Panic(Lit("Unknown sprite cache node kind")); } break; + default: { Panic(Lit("Unknown sprite cache node kind")); } break; } S_EndScope(scope); } @@ -665,7 +665,7 @@ S_ScopeCacheEntryRef *S_EnsureRefUnsafely(S_Scope *scope, S_CacheEntry *e) { if (scope->num_references >= S_MaxScopeReferences) { - P_Panic(Lit("Max sprite scope references reached")); + Panic(Lit("Max sprite scope references reached")); } /* Increment refcount */ @@ -908,7 +908,7 @@ void *S_DataFromTag(S_Scope *scope, S_Tag tag, S_CacheEntryKind kind, b32 await) { case S_CacheEntryKind_Texture: { result = g->loading_texture; } break; case S_CacheEntryKind_Sheet: { result = g->loading_sheet; } break; - default: { P_Panic(Lit("Unknown sprite cache entry kind")); } break; + default: { Panic(Lit("Unknown sprite cache entry kind")); } break; } S_ScopeCacheEntryRef *scope_ref = S_EntryFromTag(scope, tag, kind, 0); @@ -921,7 +921,7 @@ void *S_DataFromTag(S_Scope *scope, S_Tag tag, S_CacheEntryKind kind, b32 await) { case S_CacheEntryKind_Texture: { result = ref.e->texture; } break; case S_CacheEntryKind_Sheet: { result = ref.e->sheet; } break; - default: { P_Panic(Lit("Unknown sprite cache entry kind")); } break; + default: { Panic(Lit("Unknown sprite cache entry kind")); } break; } } else if (state == S_CacheEntryState_None) @@ -944,7 +944,7 @@ void *S_DataFromTag(S_Scope *scope, S_Tag tag, S_CacheEntryKind kind, b32 await) S_LoadCacheEntrySheet(ref, tag); result = ref.e->sheet; } break; - default: { P_Panic(Lit("Unknown sprite cache entry kind")); } break; + default: { Panic(Lit("Unknown sprite cache entry kind")); } break; } } else diff --git a/src/sprite/sprite_core.h b/src/sprite/sprite_core.h index c996e082..3b58ece1 100644 --- a/src/sprite/sprite_core.h +++ b/src/sprite/sprite_core.h @@ -260,7 +260,7 @@ void S_StartupCore(void); //////////////////////////////// //~ Shutdown -P_ExitFuncDef(S_Shutdown); +ExitFuncDef(S_Shutdown); //////////////////////////////// //~ Purple-black image diff --git a/src/ttf/ttf_dwrite.cpp b/src/ttf/ttf_dwrite.cpp index 07af9e36..fe750e07 100644 --- a/src/ttf/ttf_dwrite.cpp +++ b/src/ttf/ttf_dwrite.cpp @@ -45,7 +45,7 @@ void TTF_StartupCore(void) if (error != S_OK) { /* FIXME: Enable this */ - //P_Panic(Lit("Error creating DWrite factory")); + //Panic(Lit("Error creating DWrite factory")); (*(volatile int *)0) = 0; } } diff --git a/src/watch/watch_core.c b/src/watch/watch_core.c index 583357f6..7e5d34b6 100644 --- a/src/watch/watch_core.c +++ b/src/watch/watch_core.c @@ -12,10 +12,10 @@ void W_StartupCore(void) RunJob(1, W_MonitorJob, JobPool_Floating, JobPriority_Low, &g->watch_jobs_counter, 0); RunJob(1, W_DispatcherJob, JobPool_Floating, JobPriority_Low, &g->watch_jobs_counter, 0); - P_OnExit(&W_Shutdown); + OnExit(&W_Shutdown); } -P_ExitFuncDef(W_Shutdown) +ExitFuncDef(W_Shutdown) { __prof; W_SharedState *g = &W_shared_state; @@ -43,7 +43,7 @@ void W_RegisterCallback(W_CallbackFunc *callback) } else { - P_Panic(Lit("Max resource watch callbacks reached")); + Panic(Lit("Max resource watch callbacks reached")); } } Unlock(&lock); diff --git a/src/watch/watch_core.h b/src/watch/watch_core.h index c77c3d75..174fbd1c 100644 --- a/src/watch/watch_core.h +++ b/src/watch/watch_core.h @@ -42,7 +42,7 @@ extern W_SharedState W_shared_state; //~ Startup void W_StartupCore(void); -P_ExitFuncDef(W_Shutdown); +ExitFuncDef(W_Shutdown); //////////////////////////////// //~ Watch operations