From: Grazvydas Ignotas notasas@gmail.com
The documentation states it's a blocking call. There are reports of it being used for WaitForVBlank-like purposes [1]. Without blocking Softube VST plugin logic breaks and they never update their UIs.
[1] https://news.ycombinator.com/item?id=34501612
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=56935 --- dlls/dwmapi/dwmapi_main.c | 23 +++++++++++++++++++-- dlls/dwmapi/tests/dwmapi.c | 41 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 2 deletions(-)
diff --git a/dlls/dwmapi/dwmapi_main.c b/dlls/dwmapi/dwmapi_main.c index 8d4ccbb1fc4..419216534aa 100644 --- a/dlls/dwmapi/dwmapi_main.c +++ b/dlls/dwmapi/dwmapi_main.c @@ -32,6 +32,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(dwmapi);
+static int get_display_frequency(void);
/********************************************************************** * DwmIsCompositionEnabled (DWMAPI.@) @@ -88,9 +89,26 @@ HRESULT WINAPI DwmGetColorizationColor(DWORD *colorization, BOOL *opaque_blend) */ HRESULT WINAPI DwmFlush(void) { + static volatile LONG last_time; static BOOL once; + DWORD now, interval, last = last_time, target; + int freq;
- if (!once++) FIXME("() stub\n"); + if (!once++) FIXME("() semi-stub\n"); + + // simulate the WaitForVBlank-like blocking behavior + freq = get_display_frequency(); + interval = 1000 / freq; + now = GetTickCount(); + if (now - last < interval) + target = last + interval; + else + { + // act as if we were called midway between 2 vsyncs + target = now + interval / 2; + } + Sleep(target - now); + InterlockedCompareExchange(&last_time, target, last);
return S_OK; } @@ -262,7 +280,8 @@ static int get_display_frequency(void) } else { - WARN("Failed to query display frequency, returning a fallback value.\n"); + static BOOL once; + if (!once++) WARN("Failed to query display frequency, returning a fallback value.\n"); return 60; } } diff --git a/dlls/dwmapi/tests/dwmapi.c b/dlls/dwmapi/tests/dwmapi.c index a89a1fd705b..20628578f41 100644 --- a/dlls/dwmapi/tests/dwmapi.c +++ b/dlls/dwmapi/tests/dwmapi.c @@ -140,9 +140,50 @@ cleanup: DestroyWindow(hwnd); }
+static void test_DwmFlush(void) +{ + LARGE_INTEGER frequency, ts[2]; + int i, result, ms; + DEVMODEA mode; + BOOL enabled; + HRESULT hr; + + enabled = FALSE; + hr = DwmIsCompositionEnabled(&enabled); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + if (!enabled) + { + skip("DWM is disabled.\n"); + return; + } + + memset(&mode, 0, sizeof(mode)); + mode.dmSize = sizeof(mode); + result = EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &mode); + ok(result, "Failed to get display mode %#lx.\n", GetLastError()); + ok(mode.dmDisplayFrequency != 0, "dmDisplayFrequency is 0.\n"); + + result = QueryPerformanceFrequency(&frequency); + ok(result, "Failed to get performance counter frequency.\n"); + + result = QueryPerformanceCounter(&ts[0]); + ok(result, "Failed to read performance counter.\n"); + for (i = 0; i < 2; i++) + { + hr = DwmFlush(); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + } + result = QueryPerformanceCounter(&ts[1]); + ok(result, "Failed to read performance counter.\n"); + ms = (ts[1].QuadPart - ts[0].QuadPart) * 1000 / frequency.QuadPart; + ok(ms >= 1000 / mode.dmDisplayFrequency, + "DwmFlush() took %dms with dmDisplayFrequency %ld.\n", ms, mode.dmDisplayFrequency); +} + START_TEST(dwmapi) { test_DwmIsCompositionEnabled(); test_DwmGetCompositionTimingInfo(); test_DWMWA_EXTENDED_FRAME_BOUNDS(); + test_DwmFlush(); }