Răsfoiți Sursa

Fix vsync-off support for direct3d11

ceski 4 săptămâni în urmă
părinte
comite
270737584e

+ 1 - 0
CMakeLists.txt

@@ -2172,6 +2172,7 @@ elseif(WINDOWS)
     #include <gameinput.h>
     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)

+ 1 - 0
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

+ 1 - 0
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

+ 1 - 0
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

+ 53 - 4
src/render/direct3d11/SDL_render_d3d11.c

@@ -30,7 +30,11 @@
 #include "../../video/SDL_pixels_c.h"
 
 #include <d3d11_1.h>
+#ifdef HAVE_DXGI1_5_H
+#include <dxgi1_5.h>
+#else
 #include <dxgi1_4.h>
+#endif
 #include <dxgidebug.h>
 
 #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;