// attempt to fix vsync with opengl on windows // https://bugs.chromium.org/p/chromium/issues/detail?id=467617 // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/d3dkmthk/nf-d3dkmthk-d3dkmtwaitforverticalblankevent // NOTE: requires installing windows driver kit addon for msvc // TODO: not working with hdc provided by SDL, try enumerating display devices as described here: // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/d3dkmthk/nf-d3dkmthk-d3dkmtopenadapterfromhdc // NOTE: the above seems to make some difference in lowering cpu usage, but cpu stays at max frequency even when relatively idle. // TODO: if d3dkmt... doensn't work, try DWMFlush() https://docs.microsoft.com/en-us/windows/desktop/api/dwmapi/nf-dwmapi-dwmflush // glfw uses this https://github.com/glfw/glfw/blob/master/src/wgl_context.c // // if that doesn't work... https://docs.microsoft.com/en-us/windows/desktop/api/timeapi/nf-timeapi-timebeginperiod // to increase schedular granularity. can then use sleep(1) for 1ms resolution #pragma once #include #include "SDL_syswm.h" #if defined(_WIN32) #include "windows.h" #include "d3dkmthk.h" typedef uint32_t D3DKMT_HANDLE; typedef struct { D3DKMT_HANDLE hAdapter = NULL; UINT vidID = 0; } platform_win_device_handles; platform_win_device_handles g_platform_win_device_handles; #endif // _WIN32 inline bool platform_init(SDL_Window* window) { #if defined(_WIN32) D3DKMT_HANDLE hAdapter = NULL; UINT vidID = 0; D3DKMT_OPENADAPTERFROMHDC OpenAdapterData; DISPLAY_DEVICE dd; HDC hdc; memset(&dd, 0, sizeof(dd)); dd.cb = sizeof dd; for (int i = 0; EnumDisplayDevicesA(NULL, i, &dd, 0); ++i) { if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) break; } hdc = CreateDC(NULL, dd.DeviceName, NULL, NULL); if (hdc == NULL) return false; OpenAdapterData.hDc = hdc; if ((D3DKMTOpenAdapterFromHdc(&OpenAdapterData)) >= 0) { DeleteDC(hdc); g_platform_win_device_handles.hAdapter = OpenAdapterData.hAdapter; g_platform_win_device_handles.vidID = OpenAdapterData.VidPnSourceId; return true; } DeleteDC(hdc); return false; #endif // _WIN32 return true; } inline void platform_wait_for_vblank(bool wait=true) { if (!wait) return; #if defined(_WIN32) _D3DKMT_WAITFORVERTICALBLANKEVENT waitForVBlankData; memset(&waitForVBlankData, 0, sizeof(waitForVBlankData)); waitForVBlankData.hAdapter = g_platform_win_device_handles.hAdapter; waitForVBlankData.VidPnSourceId = g_platform_win_device_handles.vidID; NTSTATUS ret = D3DKMTWaitForVerticalBlankEvent(&waitForVBlankData); switch (ret) { case 0x00000000: // STATUS_SUCCESS //OutputDebugString("Success\r\n"); break; //case STATUS_DEVICE_REMOVED: // OutputDebugString("STATUS_DEVICE_REMOVED\r\n"); // break; case STATUS_INVALID_PARAMETER: OutputDebugString("STATUS_INVALID_PARAMETER\r\n"); break; default: OutputDebugString("????"); } #endif // _WIN32 // TODO: implement/test for linux }