From 5175b0d1b599ea4c7b929f6b4282dd379fa116b8 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sun, 17 Apr 2022 11:26:06 -0300 Subject: [PATCH] Windows: fix some cases of stuttering in windowed mode. Use DwmFlush instead of OpenGL vsync, when specific conditions are met. Fixes #1628. --- CMakeLists.txt | 1 + src/modules/window/sdl/Window.cpp | 52 +++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index a4ccb5409..3d6dbeab4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1755,6 +1755,7 @@ if(MSVC) set(LOVE_LINK_LIBRARIES ${LOVE_LINK_LIBRARIES} ws2_32.lib winmm.lib + dwmapi.lib ) set(LOVE_RC diff --git a/src/modules/window/sdl/Window.cpp b/src/modules/window/sdl/Window.cpp index 798b606ed..bc2d0c2e2 100644 --- a/src/modules/window/sdl/Window.cpp +++ b/src/modules/window/sdl/Window.cpp @@ -44,6 +44,8 @@ #if defined(LOVE_WINDOWS) #include +#include +#include #elif defined(LOVE_MACOSX) #include "common/macosx.h" #endif @@ -1015,7 +1017,57 @@ bool Window::isMinimized() const void Window::swapBuffers() { +#ifdef LOVE_WINDOWS + bool useDwmFlush = false; + int swapInterval = getVSync(); + + // https://github.com/love2d/love/issues/1628 + // VSync can interact badly with Windows desktop composition (DWM) in windowed mode. DwmFlush can be used instead + // of vsync, but it's much less flexible so we're very conservative here with where it's used: + // - It won't work with exclusive or desktop fullscreen. + // - DWM refreshes don't always match the refresh rate of the monitor the window is in (or the requested swap + // interval), so we only use it when they do match. + // - The user may force GL vsync, and DwmFlush shouldn't be used together with GL vsync. + if (context != nullptr && !settings.fullscreen && swapInterval == 1) + { + // Desktop composition is always enabled in Windows 8+. But DwmIsCompositionEnabled won't always return true... + // (see DwmIsCompositionEnabled docs). + BOOL compositionEnabled = IsWindows8OrGreater(); + if (compositionEnabled || (SUCCEEDED(DwmIsCompositionEnabled(&compositionEnabled)) && compositionEnabled)) + { + DWM_TIMING_INFO info = {}; + info.cbSize = sizeof(DWM_TIMING_INFO); + double dwmRefreshRate = 0; + if (SUCCEEDED(DwmGetCompositionTimingInfo(nullptr, &info))) + dwmRefreshRate = (double)info.rateRefresh.uiNumerator / (double)info.rateRefresh.uiDenominator; + + SDL_DisplayMode dmode = {}; + int displayindex = SDL_GetWindowDisplayIndex(window); + + if (displayindex >= 0) + SDL_GetCurrentDisplayMode(displayindex, &dmode); + + if (dmode.refresh_rate > 0 && dwmRefreshRate > 0 && (fabs(dmode.refresh_rate - dwmRefreshRate) < 2)) + { + SDL_GL_SetSwapInterval(0); + if (SDL_GL_GetSwapInterval() == 0) + useDwmFlush = true; + else + SDL_GL_SetSwapInterval(swapInterval); + } + } + } +#endif + SDL_GL_SwapWindow(window); + +#ifdef LOVE_WINDOWS + if (useDwmFlush) + { + DwmFlush(); + SDL_GL_SetSwapInterval(swapInterval); + } +#endif } bool Window::hasFocus() const