Skip to content

Commit d1abdfc

Browse files
Fix VSync off on Windows 11 (close #648)
1 parent cb232b3 commit d1abdfc

File tree

5 files changed

+100
-21
lines changed

5 files changed

+100
-21
lines changed

Graphics/GraphicsEngineD3D11/src/SwapChainD3D11Impl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2022 Diligent Graphics LLC
2+
* Copyright 2019-2025 Diligent Graphics LLC
33
* Copyright 2015-2019 Egor Yusov
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -152,7 +152,7 @@ void SwapChainD3D11Impl::Present(Uint32 SyncInterval)
152152
// https://docs.microsoft.com/en-us/windows/uwp/gaming/reduce-latency-with-dxgi-1-3-swap-chains#step-4-wait-before-rendering-each-frame
153153
WaitForFrame();
154154

155-
m_pSwapChain->Present(SyncInterval, 0);
155+
PresentInternal(SyncInterval);
156156
}
157157

158158
void SwapChainD3D11Impl::UpdateSwapChain(bool CreateNew)

Graphics/GraphicsEngineD3D12/src/SwapChainD3D12Impl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2022 Diligent Graphics LLC
2+
* Copyright 2019-2025 Diligent Graphics LLC
33
* Copyright 2015-2019 Egor Yusov
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -154,7 +154,7 @@ void SwapChainD3D12Impl::Present(Uint32 SyncInterval)
154154
// https://docs.microsoft.com/en-us/windows/uwp/gaming/reduce-latency-with-dxgi-1-3-swap-chains#step-4-wait-before-rendering-each-frame
155155
WaitForFrame();
156156

157-
auto hr = m_pSwapChain->Present(SyncInterval, 0);
157+
auto hr = PresentInternal(SyncInterval);
158158
VERIFY(SUCCEEDED(hr), "Present failed");
159159

160160
if (m_SwapChainDesc.IsPrimary)

Graphics/GraphicsEngineD3DBase/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ set(SOURCE
3232
src/DXGITypeConversions.cpp
3333
src/ShaderD3DBase.cpp
3434
src/ShaderResources.cpp
35+
src/SwapChainD3DBase.cpp
3536
)
3637

3738
add_library(Diligent-GraphicsEngineD3DBase STATIC

Graphics/GraphicsEngineD3DBase/include/SwapChainD3DBase.hpp

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2023 Diligent Graphics LLC
2+
* Copyright 2019-2025 Diligent Graphics LLC
33
* Copyright 2015-2019 Egor Yusov
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -31,13 +31,16 @@
3131
#include "SwapChainBase.hpp"
3232
#include "DXGITypeConversions.hpp"
3333
#include "GraphicsAccessories.hpp"
34+
#include "D3DErrors.hpp"
3435

3536
/// \file
3637
/// Base implementation of a D3D swap chain
3738

3839
namespace Diligent
3940
{
4041

42+
bool CheckDXGITearingSupport(IDXGIFactory2* pDXGIFactory2);
43+
4144
/// Base implementation of a D3D swap chain
4245
template <class BaseInterface, typename DXGISwapChainType>
4346
class SwapChainD3DBase : public SwapChainBase<BaseInterface>
@@ -101,7 +104,7 @@ class SwapChainD3DBase : public SwapChainBase<BaseInterface>
101104
void CreateDXGISwapChain(IUnknown* pD3D11DeviceOrD3D12CmdQueue)
102105
{
103106
#if PLATFORM_WIN32
104-
auto hWnd = reinterpret_cast<HWND>(m_Window.hWnd);
107+
HWND hWnd = reinterpret_cast<HWND>(m_Window.hWnd);
105108
if (m_SwapChainDesc.Width == 0 || m_SwapChainDesc.Height == 0)
106109
{
107110
RECT rc;
@@ -124,7 +127,7 @@ class SwapChainD3DBase : public SwapChainBase<BaseInterface>
124127
m_DesiredPreTransform = SURFACE_TRANSFORM_OPTIMAL;
125128
m_SwapChainDesc.PreTransform = SURFACE_TRANSFORM_IDENTITY;
126129

127-
auto DXGIColorBuffFmt = TexFormatToDXGI_Format(m_SwapChainDesc.ColorBufferFormat);
130+
DXGI_FORMAT DXGIColorBuffFmt = TexFormatToDXGI_Format(m_SwapChainDesc.ColorBufferFormat);
128131

129132
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
130133

@@ -199,18 +202,27 @@ class SwapChainD3DBase : public SwapChainBase<BaseInterface>
199202
// DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT enables querying a waitable object that can be
200203
// used to synchronize presentation with CPU timeline.
201204
// The flag is not supported in D3D11 fullscreen mode.
202-
if (!(m_FSDesc.Fullscreen && m_pRenderDevice->GetDeviceInfo().Type == RENDER_DEVICE_TYPE_D3D11))
205+
if (!m_FSDesc.Fullscreen)
203206
{
204-
// We do not need pDXGIFactory3 itself, however DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT flag
205-
// is only supported starting with Windows 8.1, and so is IDXGIFactory3 interface. We query this
206-
// interface to check Windows 8.1.
207-
// Note that we can't use IsWindows8Point1OrGreater because unlike IsWindows8OrGreater, it returns
208-
// false if an application is not manifested for Windows 8.1 or Windows 10, even if the current
209-
// operating system version is Windows 8.1 or Windows 10.
210-
CComPtr<IDXGIFactory3> pDXGIFactory3;
211-
if (SUCCEEDED(pDXGIFactory.QueryInterface(&pDXGIFactory3)))
207+
if (m_pRenderDevice->GetDeviceInfo().Type == RENDER_DEVICE_TYPE_D3D11)
208+
{
209+
// We do not need pDXGIFactory3 itself, however DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT flag
210+
// is only supported starting with Windows 8.1, and so is IDXGIFactory3 interface. We query this
211+
// interface to check Windows 8.1.
212+
// Note that we can't use IsWindows8Point1OrGreater because unlike IsWindows8OrGreater, it returns
213+
// false if an application is not manifested for Windows 8.1 or Windows 10, even if the current
214+
// operating system version is Windows 8.1 or Windows 10.
215+
CComPtr<IDXGIFactory3> pDXGIFactory3;
216+
if (SUCCEEDED(pDXGIFactory.QueryInterface(&pDXGIFactory3)))
217+
{
218+
swapChainDesc.Flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
219+
}
220+
}
221+
222+
if (CheckDXGITearingSupport(pDXGIFactory))
212223
{
213-
swapChainDesc.Flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
224+
m_TearingSupported = true;
225+
swapChainDesc.Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
214226
}
215227
}
216228

@@ -284,9 +296,9 @@ class SwapChainD3DBase : public SwapChainBase<BaseInterface>
284296
// https://docs.microsoft.com/en-us/windows/uwp/gaming/reduce-latency-with-dxgi-1-3-swap-chains#step-4-wait-before-rendering-each-frame
285297
if (m_FrameLatencyWaitableObject != NULL)
286298
{
287-
auto Res = WaitForSingleObjectEx(m_FrameLatencyWaitableObject,
288-
500, // 0.5 second timeout (shouldn't ever occur)
289-
true);
299+
DWORD Res = WaitForSingleObjectEx(m_FrameLatencyWaitableObject,
300+
500, // 0.5 second timeout (shouldn't ever occur)
301+
true);
290302
if (Res != WAIT_OBJECT_0)
291303
{
292304
const char* ErrorMsg = Res == WAIT_TIMEOUT ?
@@ -360,8 +372,23 @@ class SwapChainD3DBase : public SwapChainBase<BaseInterface>
360372
}
361373
}
362374

375+
protected:
363376
virtual void SetDXGIDeviceMaximumFrameLatency() {}
364377

378+
HRESULT PresentInternal(Uint32 SyncInterval)
379+
{
380+
if (!m_pSwapChain)
381+
return E_FAIL;
382+
383+
UINT Flags = 0;
384+
// DXGI_PRESENT_ALLOW_TEARING can only be used with sync interval 0
385+
if (SyncInterval == 0 && m_TearingSupported)
386+
Flags |= DXGI_PRESENT_ALLOW_TEARING;
387+
388+
return m_pSwapChain->Present(SyncInterval, Flags);
389+
}
390+
391+
protected:
365392
using TBase::m_pRenderDevice;
366393
using TBase::m_SwapChainDesc;
367394
using TBase::m_DesiredPreTransform;
@@ -372,7 +399,8 @@ class SwapChainD3DBase : public SwapChainBase<BaseInterface>
372399

373400
HANDLE m_FrameLatencyWaitableObject = NULL;
374401

375-
Uint32 m_MaxFrameLatency = 0;
402+
Uint32 m_MaxFrameLatency = 0;
403+
bool m_TearingSupported = false;
376404
};
377405

378406
} // namespace Diligent
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright 2025 Diligent Graphics LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* In no event and under no legal theory, whether in tort (including negligence),
17+
* contract, or otherwise, unless required by applicable law (such as deliberate
18+
* and grossly negligent acts) or agreed to in writing, shall any Contributor be
19+
* liable for any damages, including any direct, indirect, special, incidental,
20+
* or consequential damages of any character arising as a result of this License or
21+
* out of the use or inability to use the software (including but not limited to damages
22+
* for loss of goodwill, work stoppage, computer failure or malfunction, or any and
23+
* all other commercial damages or losses), even if such Contributor has been advised
24+
* of the possibility of such damages.
25+
*/
26+
27+
#include "WinHPreface.h"
28+
#include <dxgi1_5.h>
29+
#include <atlcomcli.h>
30+
#include "WinHPostface.h"
31+
32+
#include "SwapChainD3DBase.hpp"
33+
34+
namespace Diligent
35+
{
36+
37+
bool CheckDXGITearingSupport(IDXGIFactory2* pDXGIFactory2)
38+
{
39+
CComPtr<IDXGIFactory5> pDXGIFactory5;
40+
if (FAILED(pDXGIFactory2->QueryInterface(__uuidof(pDXGIFactory5), reinterpret_cast<void**>(static_cast<IDXGIFactory5**>(&pDXGIFactory5)))))
41+
return false;
42+
43+
BOOL AllowTearing = FALSE;
44+
if (FAILED(pDXGIFactory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &AllowTearing, sizeof(AllowTearing))))
45+
return false;
46+
47+
return AllowTearing;
48+
}
49+
50+
} // namespace Diligent

0 commit comments

Comments
 (0)