diff --git a/src/FNA3D_Driver_D3D11.c b/src/FNA3D_Driver_D3D11.c index a890b1f7..52f49625 100644 --- a/src/FNA3D_Driver_D3D11.c +++ b/src/FNA3D_Driver_D3D11.c @@ -56,6 +56,10 @@ #include #endif +#ifndef DXGI_PRESENT_ALLOW_TEARING +#define DXGI_PRESENT_ALLOW_TEARING 0x00000200UL +#endif /* DXGI_PRESENT_ALLOW_TEARING */ + #define ERROR_CHECK(msg) \ if (FAILED(res)) \ { \ @@ -212,6 +216,7 @@ typedef struct D3D11Renderer /* Cast FNA3D_Renderer* to this! */ void* factory; /* IDXGIFactory1 or IDXGIFactory2 */ IDXGIAdapter1 *adapter; ID3DUserDefinedAnnotation *annotation; + BOOL supportsTearing; SDL_mutex *ctxLock; SDL_iconv_t iconv; @@ -1489,6 +1494,7 @@ static void D3D11_SwapBuffers( int32_t drawableWidth, drawableHeight; FNA3D_Rect srcRect, dstRect; D3D11SwapchainData *swapchainData; + uint32_t presentFlags; /* Only the faux-backbuffer supports presenting * specific regions given to Present(). @@ -1601,7 +1607,19 @@ static void D3D11_SwapBuffers( } /* Present! */ - IDXGISwapChain_Present(swapchainData->swapchain, renderer->syncInterval, 0); + if (renderer->syncInterval == 0 && renderer->supportsTearing) + { + presentFlags = DXGI_PRESENT_ALLOW_TEARING; + } + else + { + presentFlags = 0; + } + IDXGISwapChain_Present( + swapchainData->swapchain, + renderer->syncInterval, + presentFlags + ); /* Bind the faux-backbuffer now, in case DXGI unsets target state */ D3D11_SetRenderTargets( @@ -5111,6 +5129,7 @@ static FNA3D_Device* D3D11_CreateDevice( D3D_FEATURE_LEVEL_10_0 }; uint32_t flags, supportsDxt3, supportsDxt5, supportsSrgb; + void* factory5; int32_t i; HRESULT res; @@ -5128,6 +5147,25 @@ static FNA3D_Device* D3D11_CreateDevice( &renderer->factory ); ERROR_CHECK_RETURN("Could not create DXGIFactory", NULL) + + /* Check for explicit tearing support */ + if (SUCCEEDED(IDXGIFactory1_QueryInterface( + (IDXGIFactory1*) renderer->factory, + &D3D_IID_IDXGIFactory5, + (void**) &factory5 + ))) { + if (FAILED(IDXGIFactory5_CheckFeatureSupport( + (IDXGIFactory5*) factory5, + DXGI_FEATURE_PRESENT_ALLOW_TEARING, + &renderer->supportsTearing, + sizeof(renderer->supportsTearing) + ))) { + renderer->supportsTearing = FALSE; + } + IDXGIFactory5_Release((IDXGIFactory5*) factory5); + } + + /* Select the appropriate device for rendering */ D3D11_PLATFORM_GetDefaultAdapter( renderer->factory, &renderer->adapter @@ -5591,7 +5629,15 @@ static void D3D11_PLATFORM_CreateSwapChain( swapchainDesc.BufferCount = 3; swapchainDesc.OutputWindow = dxgiHandle; swapchainDesc.Windowed = 1; - swapchainDesc.Flags = 0; + if (renderer->supportsTearing) + { + /* This enum may not be complete, so use the magic number */ + swapchainDesc.Flags = 2048; /* DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; */ + } + else + { + swapchainDesc.Flags = 0; + } /* For Windows 10+, use a better form of discard swap behavior */ if (SUCCEEDED(IDXGIFactory1_QueryInterface( diff --git a/src/FNA3D_Driver_D3D11.h b/src/FNA3D_Driver_D3D11.h index 35347ca4..cff1c85c 100644 --- a/src/FNA3D_Driver_D3D11.h +++ b/src/FNA3D_Driver_D3D11.h @@ -38,6 +38,7 @@ static const IID D3D_IID_IDXGIFactory1 = {0x770aae78,0xf26f,0x4dba,{0xa8,0x29,0x static const IID D3D_IID_IDXGIFactory2 = {0x50c83a1c,0xe072,0x4c48,{0x87,0xb0,0x36,0x30,0xfa,0x36,0xa6,0xd0}}; static const IID D3D_IID_IDXGIFactory4 = {0x7632e1f5,0xee65,0x4dca,{0x87,0xfd,0x84,0xcd,0x75,0xf8,0x83,0x8d}}; static const IID D3D_IID_IDXGIFactory6 = {0xc1b6694f,0xff09,0x44a9,{0xb0,0x3c,0x77,0x90,0x0a,0x0a,0x1d,0x17}}; +static const IID D3D_IID_IDXGIFactory5 = {0x7632e1f5,0xee65,0x4dca,{0x87,0xfd,0x84,0xcd,0x75,0xf8,0x83,0x8d}}; static const IID D3D_IID_IDXGIAdapter1 = {0x29038f61,0x3839,0x4626,{0x91,0xfd,0x08,0x68,0x79,0x01,0x1a,0x05}}; static const IID D3D_IID_ID3D11Texture2D = {0x6f15aaf2,0xd208,0x4e89,{0x9a,0xb4,0x48,0x95,0x35,0xd3,0x4f,0x9c}}; static const IID D3D_IID_ID3DUserDefinedAnnotation = {0xb2daad8b,0x03d4,0x4dbf,{0x95,0xeb,0x32,0xab,0x4b,0x63,0xd0,0xab}}; @@ -283,14 +284,180 @@ struct IDXGIFactory4 #define IDXGIFactory4_Release(This) \ ( (This)->lpVtbl -> Release(This) ) -/* IDXGIFactory6 */ -/* From dxgi1_6.h, cleaned up a bit... */ +/* IDXGIFactory5 */ +/* From dxgi1_5.h, cleaned up a bit... */ typedef enum { DXGI_FEATURE_PRESENT_ALLOW_TEARING = 0 } DXGI_FEATURE; +typedef struct IDXGIFactory5 IDXGIFactory5; +typedef struct IDXGIFactory5Vtbl +{ + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDXGIFactory5 * This, + REFIID riid, + void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDXGIFactory5 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDXGIFactory5 * This); + + HRESULT ( STDMETHODCALLTYPE *SetPrivateData )( + IDXGIFactory5 * This, + REFGUID Name, + UINT DataSize, + const void *pData); + + HRESULT ( STDMETHODCALLTYPE *SetPrivateDataInterface )( + IDXGIFactory5 * This, + REFGUID Name, + const IUnknown *pUnknown); + + HRESULT ( STDMETHODCALLTYPE *GetPrivateData )( + IDXGIFactory5 * This, + REFGUID Name, + UINT *pDataSize, + void *pData); + + HRESULT ( STDMETHODCALLTYPE *GetParent )( + IDXGIFactory5 * This, + REFIID riid, + void **ppParent); + + HRESULT ( STDMETHODCALLTYPE *EnumAdapters )( + IDXGIFactory5 * This, + UINT Adapter, + IDXGIAdapter **ppAdapter); + + HRESULT ( STDMETHODCALLTYPE *MakeWindowAssociation )( + IDXGIFactory5 * This, + HWND WindowHandle, + UINT Flags); + + HRESULT ( STDMETHODCALLTYPE *GetWindowAssociation )( + IDXGIFactory5 * This, + HWND *pWindowHandle); + + HRESULT ( STDMETHODCALLTYPE *CreateSwapChain )( + IDXGIFactory5 * This, + IUnknown *pDevice, + DXGI_SWAP_CHAIN_DESC *pDesc, + IDXGISwapChain **ppSwapChain); + + HRESULT ( STDMETHODCALLTYPE *CreateSoftwareAdapter )( + IDXGIFactory5 * This, + HMODULE Module, + IDXGIAdapter **ppAdapter); + + HRESULT ( STDMETHODCALLTYPE *EnumAdapters1 )( + IDXGIFactory5 * This, + UINT Adapter, + IDXGIAdapter1 **ppAdapter); + + BOOL ( STDMETHODCALLTYPE *IsCurrent )( + IDXGIFactory5 * This); + + BOOL ( STDMETHODCALLTYPE *IsWindowedStereoEnabled )( + IDXGIFactory5 * This); + + HRESULT ( STDMETHODCALLTYPE *CreateSwapChainForHwnd )( + IDXGIFactory5 * This, + IUnknown *pDevice, + HWND hWnd, + void *pDesc, + void *pFullscreenDesc, + void *pRestrictToOutput, + void **ppSwapChain); + + HRESULT ( STDMETHODCALLTYPE *CreateSwapChainForCoreWindow )( + IDXGIFactory5 * This, + IUnknown *pDevice, + IUnknown *pWindow, + void *pDesc, + void *pRestrictToOutput, + void **ppSwapChain); + + HRESULT ( STDMETHODCALLTYPE *GetSharedResourceAdapterLuid )( + IDXGIFactory5 * This, + HANDLE hResource, + LUID *pLuid); + + HRESULT ( STDMETHODCALLTYPE *RegisterStereoStatusWindow )( + IDXGIFactory5 * This, + HWND WindowHandle, + UINT wMsg, + DWORD *pdwCookie); + + HRESULT ( STDMETHODCALLTYPE *RegisterStereoStatusEvent )( + IDXGIFactory5 * This, + HANDLE hEvent, + DWORD *pdwCookie); + + void ( STDMETHODCALLTYPE *UnregisterStereoStatus )( + IDXGIFactory5 * This, + DWORD dwCookie); + + HRESULT ( STDMETHODCALLTYPE *RegisterOcclusionStatusWindow )( + IDXGIFactory5 * This, + HWND WindowHandle, + UINT wMsg, + DWORD *pdwCookie); + + HRESULT ( STDMETHODCALLTYPE *RegisterOcclusionStatusEvent )( + IDXGIFactory5 * This, + HANDLE hEvent, + DWORD *pdwCookie); + + void ( STDMETHODCALLTYPE *UnregisterOcclusionStatus )( + IDXGIFactory5 * This, + DWORD dwCookie); + + HRESULT ( STDMETHODCALLTYPE *CreateSwapChainForComposition )( + IDXGIFactory5 * This, + IUnknown *pDevice, + void *pDesc, + void *pRestrictToOutput, + void **ppSwapChain); + + UINT ( STDMETHODCALLTYPE *GetCreationFlags )( + IDXGIFactory5 * This); + + HRESULT ( STDMETHODCALLTYPE *EnumAdapterByLuid )( + IDXGIFactory5 * This, + LUID AdapterLuid, + REFIID riid, + void **ppvAdapter); + + HRESULT ( STDMETHODCALLTYPE *EnumWarpAdapter )( + IDXGIFactory5 * This, + REFIID riid, + void **ppvAdapter); + + HRESULT ( STDMETHODCALLTYPE *CheckFeatureSupport )( + IDXGIFactory5 * This, + DXGI_FEATURE Feature, + void *pFeatureSupportData, + UINT FeatureSupportDataSize); +} IDXGIFactory5Vtbl; + +struct IDXGIFactory5 +{ + struct IDXGIFactory5Vtbl *lpVtbl; +}; + +#define IDXGIFactory5_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + +#define IDXGIFactory5_CheckFeatureSupport(This,Feature,pFeatureSupportData,FeatureSupportDataSize) \ + ( (This)->lpVtbl -> CheckFeatureSupport(This,Feature,pFeatureSupportData,FeatureSupportDataSize) ) + +/* IDXGIFactory6 */ +/* From dxgi1_6.h, cleaned up a bit... */ + typedef enum { DXGI_GPU_PREFERENCE_UNSPECIFIED = 0,