Get latest upstream changes from internal project

This commit is contained in:
2026-10-19 12:21:40 +11:00
parent eb4e1c4d20
commit 7147ad52a2
10 changed files with 5428 additions and 3826 deletions
+183 -91
View File
@@ -5,7 +5,8 @@
#include <windows.h>
#endif
// NOTE: DN_Mem
////////////////////////////////////////////////////////////////////////////////////////////////////
// NOTE: DN OS layer implementation
static DN_U32 DN_OS_MemConvertPageToOSFlags_(DN_U32 protect)
{
DN_Assert((protect & ~DN_MemPage_All) == 0);
@@ -231,6 +232,21 @@ DN_API DN_OSDiskSpace DN_OS_DiskSpace(DN_Str8 path)
return result;
}
DN_API DN_OSMemoryInfo DN_OS_MemoryInfo()
{
DN_OSMemoryInfo result = {};
MEMORYSTATUSEX status = {};
status.dwLength = sizeof(status);
if (GlobalMemoryStatusEx(&status)) {
result.success = true;
result.total_phys = status.ullTotalPhys;
result.avail_phys = status.ullAvailPhys;
result.total_virtual = status.ullTotalVirtual;
result.avail_virtual = status.ullAvailVirtual;
}
return result;
}
DN_API bool DN_OS_SetEnvVar(DN_Str8 name, DN_Str8 value)
{
DN_TcScratch scratch = DN_TcScratchBeginArena(nullptr, 0);
@@ -247,7 +263,7 @@ DN_API DN_Str8 DN_OS_ExePath(DN_Arena *arena)
if (!arena)
return result;
DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1);
DN_Str16 exe_dir16 = DN_OS_W32EXEPathW(&scratch.arena);
DN_Str16 exe_dir16 = DN_OS_W32ExePathW(&scratch.arena);
result = DN_OS_W32Str16ToStr8(arena, exe_dir16);
DN_TcScratchEnd(&scratch);
return result;
@@ -536,6 +552,25 @@ DN_API bool DN_OS_PathDelete(DN_Str8 path)
return result;
}
DN_API DN_OSPathResult DN_OS_PathCanonicalise(DN_Arena *arena, DN_Str8 path, DN_ErrSink *error)
{
DN_OSPathResult result = {};
DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1);
DN_Str16 path16 = DN_OS_W32Str8ToStr16(&scratch.arena, path);
wchar_t out_path[1024];
HRESULT convert_result = PathCchCanonicalizeEx(out_path, DN_ArrayCountU(out_path), path16.data, PATHCCH_ALLOW_LONG_PATHS);
if (convert_result == S_OK) {
result.success = true;
result.path = DN_OS_W32Str16ToStr8(arena, DN_Str16FromPtr(out_path, DN_CStr16Count(out_path)));
} else {
DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena);
DN_ErrSinkAppendF(error, win_error.code, "Failed to canonicalise path. %.*s", DN_Str8PrintFmt(win_error.msg));
}
DN_TcScratchEnd(&scratch);
return result;
}
DN_API bool DN_OS_PathIsFile(DN_Str8 path)
{
bool result = false;
@@ -648,9 +683,9 @@ DN_API bool DN_OS_PathIterateDir(DN_Str8 path, DN_OSDirIterator *it)
// add those characters in this branch, so overwrite the null
// character, add the glob and re-null terminate the buffer.
if (needs_asterisks)
adjusted_path = DN_Str8FmtOsPathArena(&scratch.arena, "%.*s*", DN_Str8PrintFmt(path));
adjusted_path = DN_Str8PathFmtOsArena(&scratch.arena, "%.*s*", DN_Str8PrintFmt(path)).value;
else
adjusted_path = DN_Str8FmtOsPathArena(&scratch.arena, "%.*s/*", DN_Str8PrintFmt(path));
adjusted_path = DN_Str8PathFmtOsArena(&scratch.arena, "%.*s/*", DN_Str8PrintFmt(path)).value;
}
path16 = DN_OS_W32Str8ToStr16(&scratch.arena, adjusted_path);
@@ -1057,44 +1092,6 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs
return result;
}
DN_API void DN_OS_W32Init(DN_OSW32Core *w32)
{
InitializeCriticalSection(&w32->sync_primitive_free_list_mutex);
QueryPerformanceFrequency(&w32->qpc_frequency);
// NOTE: DPI
HMODULE user32 = LoadLibraryA("user32.dll");
if (user32) {
w32->get_dpi_for_window = (DN_OSW32GetDpiForWindowFunc* )GetProcAddress(user32, "GetDpiForWindow");
w32->get_dpi_for_monitor = (DN_OSW32GetDpiForMonitorFunc * )GetProcAddress(user32, "GetDpiForMonitor");
w32->get_system_metrics_for_dpi = (DN_OSW32GetSystemMetricsForDpiFunc *)GetProcAddress(user32, "GetSystemMetricsForDpi");
FreeLibrary(user32);
}
// NOTE: SetThreadDesc
HMODULE kernel32 = LoadLibraryA("kernel32.dll");
if (kernel32) {
w32->set_thread_description = DN_Cast(DN_OSW32SetThreadDescriptionFunc *) GetProcAddress(kernel32, "SetThreadDescription");
FreeLibrary(kernel32);
}
// NOTE: win32 bcrypt
wchar_t const BCRYPT_ALGORITHM[] = L"RNG";
long /*NTSTATUS*/ init_status = BCryptOpenAlgorithmProvider(&w32->bcrypt_rng_handle, BCRYPT_ALGORITHM, nullptr /*implementation*/, 0 /*flags*/);
if (w32->bcrypt_rng_handle && init_status == 0)
w32->bcrypt_init_success = true;
else
DN_LogErrorF("Failed to initialise Windows secure random number generator, error: %d", init_status);
}
DN_API DN_OSW32Core *DN_OS_W32GetCore()
{
DN_Core *dn = DN_Get();
DN_Assert(dn && dn->os_init);
DN_OSW32Core *result = DN_Cast(DN_OSW32Core *)dn->os.platform_context;
return result;
}
static DN_OSW32SyncPrimitive *DN_OS_U64ToW32SyncPrimitive_(DN_U64 u64)
{
DN_OSW32SyncPrimitive *result = nullptr;
@@ -1140,7 +1137,6 @@ static void DN_OS_W32DeallocSyncPrimitive_(DN_OSW32SyncPrimitive *primitive)
}
}
// NOTE: DN_OSSemaphore
DN_API DN_OSSemaphore DN_OS_SemaphoreInit(DN_U32 initial_count)
{
DN_OSSemaphore result = {};
@@ -1189,7 +1185,6 @@ DN_API DN_OSSemaphoreWaitResult DN_OS_SemaphoreWait(DN_OSSemaphore *semaphore, D
return result;
}
// NOTE: DN_OSBarrier
DN_API DN_OSBarrier DN_OS_BarrierInit(DN_U32 thread_count)
{
DN_OSBarrier result = {};
@@ -1260,7 +1255,6 @@ DN_API void DN_OS_MutexUnlock(DN_OSMutex *mutex)
}
}
// NOTE: DN_OSConditionVariable ////////////////////////////////////////////////////////////////////
DN_API DN_OSConditionVariable DN_OS_ConditionVariableInit()
{
DN_OSW32SyncPrimitive *primitive = DN_OS_W32AllocSyncPrimitive_();
@@ -1444,6 +1438,69 @@ DN_API DN_U32 DN_OS_ThreadID()
return result;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// NOTE: DN Win32 book-keeping
DN_API void DN_OS_W32Init(DN_OSW32Core *w32)
{
InitializeCriticalSection(&w32->sync_primitive_free_list_mutex);
QueryPerformanceFrequency(&w32->qpc_frequency);
// NOTE: DPI
HMODULE user32 = LoadLibraryA("user32.dll");
if (user32) {
w32->get_dpi_for_window = (DN_OSW32GetDpiForWindowFunc* )GetProcAddress(user32, "GetDpiForWindow");
w32->get_dpi_for_monitor = (DN_OSW32GetDpiForMonitorFunc * )GetProcAddress(user32, "GetDpiForMonitor");
w32->get_system_metrics_for_dpi = (DN_OSW32GetSystemMetricsForDpiFunc *)GetProcAddress(user32, "GetSystemMetricsForDpi");
FreeLibrary(user32);
}
// NOTE: SetThreadDesc
HMODULE kernel32 = LoadLibraryA("kernel32.dll");
if (kernel32) {
w32->set_thread_description = DN_Cast(DN_OSW32SetThreadDescriptionFunc *) GetProcAddress(kernel32, "SetThreadDescription");
FreeLibrary(kernel32);
}
// NOTE: win32 bcrypt
wchar_t const BCRYPT_ALGORITHM[] = L"RNG";
long /*NTSTATUS*/ init_status = BCryptOpenAlgorithmProvider(&w32->bcrypt_rng_handle, BCRYPT_ALGORITHM, nullptr /*implementation*/, 0 /*flags*/);
if (w32->bcrypt_rng_handle && init_status == 0)
w32->bcrypt_init_success = true;
else
DN_LogErrorF("Failed to initialise Windows secure random number generator, error: %d", init_status);
}
DN_API DN_OSW32Core *DN_OS_W32GetCore()
{
DN_Core *dn = DN_Get();
DN_Assert(dn && dn->os_init);
DN_OSW32Core *result = DN_Cast(DN_OSW32Core *)dn->os.platform_context;
return result;
}
DN_API DN_OSW32Window* DN_OS_W32WindowFromHwndMaybeAlloc(DN_OSW32Core *w32, HWND hwnd, DN_Arena *arena)
{
DN_OSW32Window *result = nullptr;
for (DN_OSW32Window *check = w32->windows; !result && check; check = check->next) {
if (check->hwnd == hwnd)
result = check;
}
if (!result && arena) {
result = DN_ArenaNewZ(arena, DN_OSW32Window);
if (result) {
result->hwnd = hwnd;
if (w32->windows)
w32->windows->next = result;
result->next = w32->windows;
w32->windows = result;
}
}
return result;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// NOTE: Process management
DN_API void DN_OS_W32ThreadSetName(DN_Str8 name)
{
// NOTE: SetThreadDescription is only available in
@@ -1475,7 +1532,7 @@ DN_API void DN_OS_W32ThreadSetName(DN_Str8 name)
// TODO: Review warning 6320
DN_MSVC_WARNING_PUSH
DN_MSVC_WARNING_DISABLE(6320) // Exception-filter expression is the constant EXCEPTION_EXECUTE_HANDLER. This might mask exceptions that were not intended to be handled
DN_MSVC_WARNING_DISABLE(6320) // Exception-filter expression is the constant EXCEPTION_ExeCUTE_HANDLER. This might mask exceptions that were not intended to be handled
DN_MSVC_WARNING_DISABLE(6322) // Empty _except block
__try {
RaiseException(0x406D1388, 0, sizeof(info) / sizeof(void *), (const ULONG_PTR *)&info);
@@ -1486,27 +1543,6 @@ DN_API void DN_OS_W32ThreadSetName(DN_Str8 name)
DN_TcScratchEnd(&scratch);
}
DN_API DN_OSW32Window* DN_OS_W32WindowFromHwndMaybeAlloc(DN_OSW32Core *w32, HWND hwnd, DN_Arena *arena)
{
DN_OSW32Window *result = nullptr;
for (DN_OSW32Window *check = w32->windows; !result && check; check = check->next) {
if (check->hwnd == hwnd)
result = check;
}
if (!result && arena) {
result = DN_ArenaNewZ(arena, DN_OSW32Window);
if (result) {
result->hwnd = hwnd;
if (w32->windows)
w32->windows->next = result;
result->next = w32->windows;
w32->windows = result;
}
}
return result;
}
DN_API LRESULT __stdcall DN_OS_W32WindowProcCustomTitlebar(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param)
{
DN_OSW32Core *w32 = DN_OS_W32GetCore();
@@ -1640,6 +1676,81 @@ DN_API LRESULT __stdcall DN_OS_W32WindowProcCustomTitlebar(HWND hwnd, UINT msg,
return result;
}
DN_API void DN_OS_W32MakeProcessDPIAware()
{
typedef bool SetProcessDpiAwareProc(void);
typedef bool SetProcessDpiAwarenessProc(DPI_AWARENESS);
typedef bool SetProcessDpiAwarenessContextProc(void * /*DPI_AWARENESS_CONTEXT*/);
// NOTE(doyle): Taken from cmuratori/refterm snippet on DPI awareness. It
// appears we can make this robust by just loading user32.dll and using
// GetProcAddress on the DPI function. If it's not there, we're on an old
// version of windows, so we can call an older version of the API.
void *lib_handle = LoadLibraryA("user32.dll");
if (!lib_handle)
return;
if (auto *set_process_dpi_awareness_context = DN_Cast(SetProcessDpiAwarenessContextProc *) GetProcAddress(DN_Cast(HMODULE) lib_handle, "SetProcessDpiAwarenessContext"))
set_process_dpi_awareness_context(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
else if (auto *set_process_dpi_awareness = DN_Cast(SetProcessDpiAwarenessProc *) GetProcAddress(DN_Cast(HMODULE) lib_handle, "SetProcessDpiAwareness"))
set_process_dpi_awareness(DPI_AWARENESS_PER_MONITOR_AWARE);
else if (auto *set_process_dpi_aware = DN_Cast(SetProcessDpiAwareProc *) GetProcAddress(DN_Cast(HMODULE) lib_handle, "SetProcessDpiAware"))
set_process_dpi_aware();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// NOTE: DLL
DN_API void DN_OS_W32DllUnload(DN_OSW32DllCore *dll)
{
if (dll) {
if (dll->handle) {
FreeLibrary(DN_Cast(HMODULE) dll->handle);
dll->handle = nullptr;
}
for (DN_ForItSize(it, DN_OSW32DllFunction, dll->functions, dll->functions_count))
it.data->func_ptr = nullptr;
}
}
DN_API DN_OSW32DllLoadFunctionsResult DN_OS_W32DllLoadFunctions(DN_OSW32DllCore *dll, DN_Str8 dll_path)
{
DN_OSW32DllLoadFunctionsResult result = DN_OSW32DllLoadFunctionsResult_LoadLibraryFailed;
HMODULE handle = LoadLibraryA(dll_path.data);
if (handle) {
bool all_good = true;
// NOTE: Validate that all the functions can be loaded from the DLL
for (DN_ForItSize(it, DN_OSW32DllFunction, dll->functions, dll->functions_count)) {
DN_Str8 func_name = it.data->name;
DN_AssertF(func_name.count && func_name.data[func_name.count] == 0, "Function name must be set and null-terminated");
void *func_ptr = GetProcAddress(handle, func_name.data);
all_good &= (func_ptr != nullptr);
}
// NOTE: If all functions can be loaded, then mutate the user's `dll` struct
if (all_good) {
result = DN_OSW32DllLoadFunctionsResult_Ok;
for (DN_ForItSize(it, DN_OSW32DllFunction, dll->functions, dll->functions_count)) {
DN_Str8 func_name = it.data->name;
it.data->func_ptr = GetProcAddress(handle, func_name.data);
}
// NOTE: Cleanup the old handle
if (dll->handle)
FreeLibrary(DN_Cast(HMODULE) dll->handle);
dll->handle = handle;
DN_StackTraceReloadSymbols();
} else {
FreeLibrary(handle);
result = DN_OSW32DllLoadFunctionsResult_FunctionMissing;
}
}
return result;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// NOTE: Errors
DN_API DN_Str16 DN_OS_W32ErrorCodeToMsg16Alloc(DN_U32 error_code)
{
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
@@ -1702,28 +1813,8 @@ DN_API DN_OSW32Error DN_OS_W32LastErrorAlloc()
return result;
}
DN_API void DN_OS_W32MakeProcessDPIAware()
{
typedef bool SetProcessDpiAwareProc(void);
typedef bool SetProcessDpiAwarenessProc(DPI_AWARENESS);
typedef bool SetProcessDpiAwarenessContextProc(void * /*DPI_AWARENESS_CONTEXT*/);
// NOTE(doyle): Taken from cmuratori/refterm snippet on DPI awareness. It
// appears we can make this robust by just loading user32.dll and using
// GetProcAddress on the DPI function. If it's not there, we're on an old
// version of windows, so we can call an older version of the API.
void *lib_handle = LoadLibraryA("user32.dll");
if (!lib_handle)
return;
if (auto *set_process_dpi_awareness_context = DN_Cast(SetProcessDpiAwarenessContextProc *) GetProcAddress(DN_Cast(HMODULE) lib_handle, "SetProcessDpiAwarenessContext"))
set_process_dpi_awareness_context(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
else if (auto *set_process_dpi_awareness = DN_Cast(SetProcessDpiAwarenessProc *) GetProcAddress(DN_Cast(HMODULE) lib_handle, "SetProcessDpiAwareness"))
set_process_dpi_awareness(DPI_AWARENESS_PER_MONITOR_AWARE);
else if (auto *set_process_dpi_aware = DN_Cast(SetProcessDpiAwareProc *) GetProcAddress(DN_Cast(HMODULE) lib_handle, "SetProcessDpiAware"))
set_process_dpi_aware();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// NOTE: Windows Str8 <-> Str16
DN_API DN_Str16 DN_OS_W32Str8ToStr16(DN_Arena *arena, DN_Str8 src)
{
DN_Str16 result = {};
@@ -1845,8 +1936,9 @@ DN_API DN_Str8 DN_OS_W32Str16ToStr8FromHeap(DN_Str16 src)
return result;
}
// NOTE: Windows Executable Directory //////////////////////////////////////////
DN_API DN_Str16 DN_OS_W32EXEPathW(DN_Arena *arena)
////////////////////////////////////////////////////////////////////////////////////////////////////
// NOTE: Path navigation
DN_API DN_Str16 DN_OS_W32ExePathW(DN_Arena *arena)
{
DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1);
DN_Str16 result = {};