Windows: fix some cases of stuttering in windowed mode.

Use DwmFlush instead of OpenGL vsync, when specific conditions are met. Fixes #1628.
This commit is contained in:
Alex Szpakowski
2022-04-17 11:26:06 -03:00
parent b3b1317f61
commit 5175b0d1b5
2 changed files with 53 additions and 0 deletions
+52
View File
@@ -44,6 +44,8 @@
#if defined(LOVE_WINDOWS)
#include <windows.h>
#include <dwmapi.h>
#include <VersionHelpers.h>
#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