From 270737584e95915a3af2dd1456fe57833d60fe1b Mon Sep 17 00:00:00 2001 From: ceski <56656010+ceski-1@users.noreply.github.com> Date: Mon, 18 Aug 2025 20:05:08 -0700 Subject: [PATCH] Fix vsync-off support for direct3d11 --- CMakeLists.txt | 1 + include/build_config/SDL_build_config.h.cmake | 1 + .../build_config/SDL_build_config_windows.h | 1 + .../build_config/SDL_build_config_wingdk.h | 1 + src/render/direct3d11/SDL_render_d3d11.c | 57 +++++++++++++++++-- 5 files changed, 57 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 27864de8a6..c67d875ab2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2172,6 +2172,7 @@ elseif(WINDOWS) #include int main(int argc, char **argv) { return 0; }" HAVE_GAMEINPUT_H ) + check_include_file(dxgi1_5.h HAVE_DXGI1_5_H) check_include_file(dxgi1_6.h HAVE_DXGI1_6_H) check_include_file(tpcshrd.h HAVE_TPCSHRD_H) check_include_file(roapi.h HAVE_ROAPI_H) diff --git a/include/build_config/SDL_build_config.h.cmake b/include/build_config/SDL_build_config.h.cmake index 8965e6db48..cc491526e5 100644 --- a/include/build_config/SDL_build_config.h.cmake +++ b/include/build_config/SDL_build_config.h.cmake @@ -223,6 +223,7 @@ #cmakedefine HAVE_WINDOWS_GAMING_INPUT_H 1 #cmakedefine HAVE_GAMEINPUT_H 1 #cmakedefine HAVE_DXGI_H 1 +#cmakedefine HAVE_DXGI1_5_H 1 #cmakedefine HAVE_DXGI1_6_H 1 #cmakedefine HAVE_MMDEVICEAPI_H 1 diff --git a/include/build_config/SDL_build_config_windows.h b/include/build_config/SDL_build_config_windows.h index 98079cb178..7872d2a928 100644 --- a/include/build_config/SDL_build_config_windows.h +++ b/include/build_config/SDL_build_config_windows.h @@ -85,6 +85,7 @@ typedef unsigned int uintptr_t; #define HAVE_DXGI_H 1 #define HAVE_XINPUT_H 1 #if defined(_WIN32_MAXVER) && _WIN32_MAXVER >= 0x0A00 /* Windows 10 SDK */ +#define HAVE_DXGI1_5_H 1 #define HAVE_DXGI1_6_H 1 #define HAVE_WINDOWS_GAMING_INPUT_H 1 #endif diff --git a/include/build_config/SDL_build_config_wingdk.h b/include/build_config/SDL_build_config_wingdk.h index a5fb7e497a..734fb6c6c6 100644 --- a/include/build_config/SDL_build_config_wingdk.h +++ b/include/build_config/SDL_build_config_wingdk.h @@ -37,6 +37,7 @@ #define HAVE_DSOUND_H 1 /* No SDK version checks needed for these because the SDK has to be new. */ #define HAVE_DXGI_H 1 +#define HAVE_DXGI1_5_H 1 #define HAVE_DXGI1_6_H 1 #define HAVE_XINPUT_H 1 #define HAVE_WINDOWS_GAMING_INPUT_H 1 diff --git a/src/render/direct3d11/SDL_render_d3d11.c b/src/render/direct3d11/SDL_render_d3d11.c index 12fd5abc45..39fc94dbe8 100644 --- a/src/render/direct3d11/SDL_render_d3d11.c +++ b/src/render/direct3d11/SDL_render_d3d11.c @@ -30,7 +30,11 @@ #include "../../video/SDL_pixels_c.h" #include +#ifdef HAVE_DXGI1_5_H +#include +#else #include +#endif #include #include "SDL_shaders_d3d11.h" @@ -157,6 +161,7 @@ typedef struct ID3D11DeviceContext1 *d3dContext; IDXGISwapChain1 *swapChain; DXGI_SWAP_EFFECT swapEffect; + UINT swapChainFlags; UINT syncInterval; UINT presentFlags; ID3D11RenderTargetView *mainRenderTargetView; @@ -206,6 +211,9 @@ typedef struct #pragma GCC diagnostic ignored "-Wunused-const-variable" #endif +#ifdef HAVE_DXGI1_5_H +static const GUID SDL_IID_IDXGIFactory5 = { 0x7632e1f5, 0xee65, 0x4dca, { 0x87, 0xfd, 0x84, 0xcd, 0x75, 0xf8, 0x83, 0x8d } }; +#endif static const GUID SDL_IID_IDXGIFactory2 = { 0x50c83a1c, 0xe072, 0x4c48, { 0x87, 0xb0, 0x36, 0x30, 0xfa, 0x36, 0xa6, 0xd0 } }; static const GUID SDL_IID_IDXGIDevice1 = { 0x77db970f, 0x6276, 0x48ba, { 0xba, 0x28, 0x07, 0x01, 0x43, 0xb4, 0x39, 0x2c } }; static const GUID SDL_IID_ID3D11Texture2D = { 0x6f15aaf2, 0xd208, 0x4e89, { 0x9a, 0xb4, 0x48, 0x95, 0x35, 0xd3, 0x4f, 0x9c } }; @@ -511,6 +519,9 @@ static HRESULT D3D11_CreateDeviceResources(SDL_Renderer *renderer) HRESULT result = S_OK; UINT creationFlags = 0; bool createDebug; +#ifdef HAVE_DXGI1_5_H + IDXGIFactory5 *dxgiFactory5 = NULL; +#endif /* This array defines the set of DirectX hardware feature levels this app will support. * Note the ordering should be preserved. @@ -601,6 +612,20 @@ static HRESULT D3D11_CreateDeviceResources(SDL_Renderer *renderer) goto done; } +#ifdef HAVE_DXGI1_5_H + // Check for tearing support, which requires the IDXGIFactory5 interface. + data->swapChainFlags = 0; + result = IDXGIFactory2_QueryInterface(data->dxgiFactory, &SDL_IID_IDXGIFactory5, (void **)&dxgiFactory5); + if (SUCCEEDED(result)) { + BOOL allowTearing = FALSE; + result = IDXGIFactory5_CheckFeatureSupport(dxgiFactory5, DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing, sizeof(allowTearing)); + if (SUCCEEDED(result) && allowTearing) { + data->swapChainFlags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; + } + IDXGIFactory5_Release(dxgiFactory5); + } +#endif // HAVE_DXGI1_5_H + // FIXME: Should we use the default adapter? result = IDXGIFactory2_EnumAdapters(data->dxgiFactory, 0, &data->dxgiAdapter); if (FAILED(result)) { @@ -870,7 +895,7 @@ static HRESULT D3D11_CreateSwapChain(SDL_Renderer *renderer, int w, int h) } else { swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // All Windows Store apps must use this SwapEffect. } - swapChainDesc.Flags = 0; + swapChainDesc.Flags = data->swapChainFlags; if (coreWindow) { result = IDXGIFactory2_CreateSwapChainForCoreWindow(data->dxgiFactory, @@ -956,6 +981,28 @@ static void D3D11_ReleaseMainRenderTargetView(SDL_Renderer *renderer) SAFE_RELEASE(data->mainRenderTargetView); } +static void D3D11_UpdatePresentFlags(SDL_Renderer *renderer) +{ + D3D11_RenderData *data = (D3D11_RenderData *)renderer->internal; + + if (data->syncInterval > 0) { + data->presentFlags = 0; + } else { + data->presentFlags = DXGI_PRESENT_DO_NOT_WAIT; +#ifdef HAVE_DXGI1_5_H + // Present tearing requires sync interval 0, a swap chain flag, and not in exclusive fullscreen mode. + if ((data->swapChainFlags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING)) { + HRESULT result = S_OK; + BOOL fullscreenState = FALSE; + result = IDXGISwapChain_GetFullscreenState(data->swapChain, &fullscreenState, NULL); + if (SUCCEEDED(result) && !fullscreenState) { + data->presentFlags = DXGI_PRESENT_ALLOW_TEARING; + } + } +#endif // HAVE_DXGI1_5_H + } +} + // Initialize all resources that change when the window's size changes. static HRESULT D3D11_CreateWindowSizeDependentResources(SDL_Renderer *renderer) { @@ -985,7 +1032,7 @@ static HRESULT D3D11_CreateWindowSizeDependentResources(SDL_Renderer *renderer) 0, w, h, DXGI_FORMAT_UNKNOWN, - 0); + data->swapChainFlags); if (FAILED(result)) { WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain::ResizeBuffers"), result); goto done; @@ -997,6 +1044,8 @@ static HRESULT D3D11_CreateWindowSizeDependentResources(SDL_Renderer *renderer) } } + D3D11_UpdatePresentFlags(renderer); + // Set the proper rotation for the swap chain. if (WIN_IsWindows8OrGreater()) { if (data->swapEffect == DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL) { @@ -2663,11 +2712,10 @@ static bool D3D11_SetVSync(SDL_Renderer *renderer, const int vsync) if (vsync > 0) { data->syncInterval = vsync; - data->presentFlags = 0; } else { data->syncInterval = 0; - data->presentFlags = DXGI_PRESENT_DO_NOT_WAIT; } + D3D11_UpdatePresentFlags(renderer); return true; } @@ -2733,6 +2781,7 @@ static bool D3D11_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_NV21); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_P010); + data->swapChainFlags = 0; data->syncInterval = 0; data->presentFlags = DXGI_PRESENT_DO_NOT_WAIT;