Qt 6.9 Gui module on Windows with D3D 11 and 12 uses dedicated vblank watcher thread to update window (https://doc.qt.io/qt-6/whatsnew69.html). This thread calls IDXGIOutput::WaitForVBlank that must halt the thread until the next vblank occurs.
This implementation is based on incorrect calculation of vblank occurrence. But it helps to update window.
From: Mike Kozelkov augenzi@etersoft.ru
--- dlls/dxgi/output.c | 9 ++++++- dlls/wined3d/directx.c | 54 +++++++++++++++++++++++++++++++++++++++ dlls/wined3d/wined3d.spec | 1 + include/wine/wined3d.h | 1 + 4 files changed, 64 insertions(+), 1 deletion(-)
diff --git a/dlls/dxgi/output.c b/dlls/dxgi/output.c index e828ed0d9d8..dedb3280fa6 100644 --- a/dlls/dxgi/output.c +++ b/dlls/dxgi/output.c @@ -365,12 +365,19 @@ static HRESULT STDMETHODCALLTYPE dxgi_output_WaitForVBlank(IDXGIOutput6 *iface) { static BOOL once = FALSE;
+ struct dxgi_output *output = impl_from_IDXGIOutput6(iface); + HRESULT hr; + if (!once++) FIXME("iface %p stub!\n", iface); else TRACE("iface %p stub!\n", iface);
- return E_NOTIMPL; + wined3d_mutex_lock(); + hr = wined3d_output_wait_for_vblank(output->wined3d_output); + wined3d_mutex_unlock(); + + return hr == WINED3D_OK ? S_OK : DXGI_ERROR_UNSUPPORTED; }
static HRESULT STDMETHODCALLTYPE dxgi_output_TakeOwnership(IDXGIOutput6 *iface, IUnknown *device, BOOL exclusive) diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c index 939915889ad..627493e9247 100644 --- a/dlls/wined3d/directx.c +++ b/dlls/wined3d/directx.c @@ -1858,6 +1858,60 @@ HRESULT CDECL wined3d_output_get_raster_status(const struct wined3d_output *outp return WINED3D_OK; }
+static DWORD WINAPI wined3d_output_wait_for_vblank_worker(void* arg) +{ + static BOOL once = FALSE; + struct wined3d_output *output = arg; + struct wined3d_display_mode mode; + LARGE_INTEGER counter_start, counter_end, freq_per_sec; + LONGLONG ticks_per_frame; + + if (!once++) + FIXME("output %p semi-stub!\n", output); + else + TRACE("output %p semi-stub!\n", output); + + if (!QueryPerformanceCounter(&counter_start) || !QueryPerformanceFrequency(&freq_per_sec)) + return WINED3DERR_INVALIDCALL; + if (FAILED(wined3d_output_get_display_mode(output, &mode, NULL))) + return WINED3DERR_INVALIDCALL; + if (mode.refresh_rate == DEFAULT_REFRESH_RATE) + mode.refresh_rate = 60; + + ticks_per_frame = freq_per_sec.QuadPart / (mode.refresh_rate * 100); + + do + { + QueryPerformanceCounter(&counter_end); + } while (counter_end.QuadPart - counter_start.QuadPart < ticks_per_frame); + + + return WINED3D_OK; +} + +HRESULT CDECL wined3d_output_wait_for_vblank(struct wined3d_output *output) +{ + static BOOL once = FALSE; + HANDLE thread; + DWORD tid; + DWORD exit_code; + + if (!once++) + FIXME("output %p semi-stub!\n", output); + else + TRACE("output %p semi-stub!\n", output); + + thread = CreateThread(NULL, 0, wined3d_output_wait_for_vblank_worker, output, 0, &tid); + + WaitForSingleObject(thread, INFINITE); + + GetExitCodeThread(thread, &exit_code); + + CloseHandle(thread); + + return exit_code; +} + HRESULT CDECL wined3d_check_depth_stencil_match(const struct wined3d_adapter *adapter, enum wined3d_device_type device_type, enum wined3d_format_id adapter_format_id, enum wined3d_format_id render_target_format_id, enum wined3d_format_id depth_stencil_format_id) diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec index 94e418ca885..de3cdb4da61 100644 --- a/dlls/wined3d/wined3d.spec +++ b/dlls/wined3d/wined3d.spec @@ -175,6 +175,7 @@ @ cdecl wined3d_output_set_display_mode(ptr ptr) @ cdecl wined3d_output_set_gamma_ramp(ptr ptr) @ cdecl wined3d_output_take_ownership(ptr long) +@ cdecl wined3d_output_wait_for_vblank(ptr)
@ cdecl wined3d_palette_apply_to_dc(ptr ptr) @ cdecl wined3d_palette_create(ptr long long ptr ptr) diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h index 3b5edd9639a..c5e811a4ea2 100644 --- a/include/wine/wined3d.h +++ b/include/wine/wined3d.h @@ -2624,6 +2624,7 @@ HRESULT __cdecl wined3d_output_set_display_mode(struct wined3d_output *output, const struct wined3d_display_mode *mode); HRESULT __cdecl wined3d_output_set_gamma_ramp(struct wined3d_output *output, const struct wined3d_gamma_ramp *ramp); HRESULT __cdecl wined3d_output_take_ownership(const struct wined3d_output *output, BOOL exclusive); +HRESULT __cdecl wined3d_output_wait_for_vblank(struct wined3d_output *output);
HRESULT __cdecl wined3d_palette_create(struct wined3d_device *device, uint32_t flags, unsigned int entry_count, const PALETTEENTRY *entries, struct wined3d_palette **palette);
This merge request was closed by Mike Kozelkov.