From b4a685eba0f91a5a68365c311232b08aeda40605 Mon Sep 17 00:00:00 2001 From: Kleadron Date: Tue, 1 Aug 2023 02:36:29 -0700 Subject: [PATCH] Add DWM VSync Code --- platforms/windows/main.cpp | 68 +++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/platforms/windows/main.cpp b/platforms/windows/main.cpp index 2101f38..cbd96e1 100644 --- a/platforms/windows/main.cpp +++ b/platforms/windows/main.cpp @@ -7,7 +7,10 @@ ********************************************************************/ #include +#include #include +//#include +#include #include "compat/GL.hpp" #include "compat/AKeyCodes.hpp" @@ -19,6 +22,41 @@ LPCTSTR g_GameTitle = TEXT("MINECRAFT"); LPCTSTR g_WindowClassName = TEXT("MinecraftClass"); +BOOL wantVSync = TRUE; + +// windows dwm sync functions +// On windows versions with the DWM compositor enabled, regular opengl vsync isn't accurate to the compositor's display time. +// Waiting until DWM has flushed to display a frame results in a smoother experience. +// If you don't want this, or it causes problems, you can comment out this line. +// The project does not need to be linked against dwmapi.lib and will find the functions if the DLL exists. +#define USE_DWM_SYNC + +#ifdef USE_DWM_SYNC +BOOL hasDWM; +typedef HRESULT(WINAPI *DWMFUNC1)(BOOL *pfEnabled); +typedef HRESULT(WINAPI *DWMFUNC2)(); +DWMFUNC1 p_DwmIsCompositionEnabled; +DWMFUNC2 p_DwmFlush; + +void linkDWM() +{ + HMODULE dwmapiLib = LoadLibrary("dwmapi.dll"); + + if (dwmapiLib != NULL) + { + printf("Found dwmapi.dll, vsync will sync to compositor."); + p_DwmIsCompositionEnabled = (DWMFUNC1)GetProcAddress(dwmapiLib, "DwmIsCompositionEnabled"); + p_DwmFlush = (DWMFUNC2)GetProcAddress(dwmapiLib, "DwmFlush"); + hasDWM = true; + } + else + { + printf("No dwmapi.dll, vsync will sync to monitor."); + hasDWM = false; + } +} +#endif + void LogMsg(const char* fmt, ...) { va_list lst; @@ -191,6 +229,10 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLin g_AppPlatform.initConsts(); +#ifdef USE_DWM_SYNC + linkDWM(); +#endif + // register the window class: WNDCLASS wc; wc.style = CS_OWNDC; @@ -230,7 +272,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLin if (!xglInitted()) goto _cleanup; - xglSwapIntervalEXT(1); g_pApp = new NinecraftApp; g_pApp->m_pPlatform = &g_AppPlatform; @@ -259,6 +300,31 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLin // update our stuff here: g_pApp->update(); + if (wantVSync) + { + // todo: check if DWM sync is appropriate for versions over 7/vista +#ifdef USE_DWM_SYNC + if (hasDWM && IsWindowsVistaOrGreater()) + { + BOOL enabled = FALSE; + + if (SUCCEEDED(p_DwmIsCompositionEnabled(&enabled)) && enabled) + { + xglSwapIntervalEXT(0); + p_DwmFlush(); + } + } + else +#endif + { + xglSwapIntervalEXT(1); + } + } + else + { + xglSwapIntervalEXT(0); + } + // note: NinecraftApp would have done this with eglSwapBuffers, but I'd rather do it here: SwapBuffers(hDC); }