From 91b389f351e608d01ac9f4679b04cd46201976a5 Mon Sep 17 00:00:00 2001 From: Caleb Cornett Date: Sat, 10 Feb 2024 17:07:56 -0600 Subject: [PATCH] SetSwapchainPresentMode + other swapchain-y features from FNA3D D3D11 --- src/Refresh_Driver_D3D11.c | 103 +++++++++++++++++++++++----- src/Refresh_Driver_D3D11_cdefines.h | 2 + 2 files changed, 87 insertions(+), 18 deletions(-) diff --git a/src/Refresh_Driver_D3D11.c b/src/Refresh_Driver_D3D11.c index 218d00b..b413f41 100644 --- a/src/Refresh_Driver_D3D11.c +++ b/src/Refresh_Driver_D3D11.c @@ -389,12 +389,13 @@ typedef struct D3D11SwapchainData { IDXGISwapChain *swapchain; D3D11Texture texture; + Refresh_PresentMode presentMode; } D3D11SwapchainData; +/* FIXME: Why do we have WindowData separate from SwapchainData? */ typedef struct D3D11WindowData { void* windowHandle; - uint8_t allowTearing; D3D11SwapchainData *swapchainData; } D3D11WindowData; @@ -517,7 +518,8 @@ typedef struct D3D11Renderer void *d3dcompiler_dll; uint8_t debugMode; - D3D_FEATURE_LEVEL featureLevel; /* FIXME: Do we need this? */ + BOOL supportsTearing; + PFN_D3DCOMPILE D3DCompileFunc; D3D11WindowData **claimedWindows; @@ -3296,12 +3298,14 @@ static uint8_t D3D11_INTERNAL_InitializeSwapchainTexture( static uint8_t D3D11_INTERNAL_CreateSwapchain( D3D11Renderer *renderer, - D3D11WindowData *windowData + D3D11WindowData *windowData, + Refresh_PresentMode presentMode ) { SDL_SysWMinfo info; HWND dxgiHandle; int width, height; DXGI_SWAP_CHAIN_DESC swapchainDesc; + IDXGIFactory4 *factory4; IDXGIFactory1 *pParent; IDXGISwapChain *swapchain; D3D11SwapchainData *swapchainData; @@ -3328,11 +3332,35 @@ static uint8_t D3D11_INTERNAL_CreateSwapchain( swapchainDesc.SampleDesc.Count = 1; swapchainDesc.SampleDesc.Quality = 0; swapchainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swapchainDesc.BufferCount = 3; + swapchainDesc.BufferCount = 2; swapchainDesc.OutputWindow = dxgiHandle; swapchainDesc.Windowed = 1; - swapchainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; - swapchainDesc.Flags = 0; + + if (renderer->supportsTearing) + { + swapchainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; + swapchainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + } + else + { + swapchainDesc.Flags = 0; + + /* For Windows 10+, use a better form of discard swap behavior */ + res = IDXGIFactory1_QueryInterface( + renderer->factory, + &D3D_IID_IDXGIFactory4, + &factory4 + ); + if (SUCCEEDED(res)) + { + swapchainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + IDXGIFactory4_Release(factory4); + } + else + { + swapchainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + } + } /* Create the swapchain! */ res = IDXGIFactory1_CreateSwapChain( @@ -3341,7 +3369,7 @@ static uint8_t D3D11_INTERNAL_CreateSwapchain( &swapchainDesc, &swapchain ); - ERROR_CHECK("Could not create swapchain"); + ERROR_CHECK("Could not create swapchain", 0); /* * The swapchain's parent is a separate factory from the factory that @@ -3385,6 +3413,7 @@ static uint8_t D3D11_INTERNAL_CreateSwapchain( /* Create the swapchain data */ swapchainData = (D3D11SwapchainData*) SDL_malloc(sizeof(D3D11SwapchainData)); swapchainData->swapchain = swapchain; + swapchainData->presentMode = presentMode; if (!D3D11_INTERNAL_InitializeSwapchainTexture( renderer, @@ -3415,11 +3444,11 @@ static uint8_t D3D11_INTERNAL_ResizeSwapchain( /* Resize the swapchain */ res = IDXGISwapChain_ResizeBuffers( swapchainData->swapchain, - 0, /* Keep buffer count the same */ + 0, /* Keep buffer count the same */ width, height, - DXGI_FORMAT_UNKNOWN, /* Keep the old format */ - 0 + DXGI_FORMAT_UNKNOWN, /* Keep the old format */ + renderer->supportsTearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0 ); ERROR_CHECK_RETURN("Could not resize swapchain buffers", 0); @@ -3470,9 +3499,8 @@ static uint8_t D3D11_ClaimWindow( { windowData = (D3D11WindowData*) SDL_malloc(sizeof(D3D11WindowData)); windowData->windowHandle = windowHandle; - windowData->allowTearing = presentMode == REFRESH_PRESENTMODE_IMMEDIATE; - if (D3D11_INTERNAL_CreateSwapchain(renderer, windowData)) + if (D3D11_INTERNAL_CreateSwapchain(renderer, windowData, presentMode)) { SDL_SetWindowData((SDL_Window*) windowHandle, WINDOW_DATA, windowData); @@ -3604,7 +3632,9 @@ static void D3D11_SetSwapchainPresentMode( void *windowHandle, Refresh_PresentMode presentMode ) { - NOT_IMPLEMENTED + D3D11WindowData *windowData = D3D11_INTERNAL_FetchWindowData(windowHandle); + D3D11SwapchainData *swapchainData = windowData->swapchainData; + swapchainData->presentMode = presentMode; } /* Submission and Fences */ @@ -3737,7 +3767,7 @@ static void D3D11_Submit( ID3D11CommandList_Release(commandList); /* Mark the command buffer as submitted */ - if (renderer->submittedCommandBufferCount + 1 >= renderer->submittedCommandBufferCapacity) + if (renderer->submittedCommandBufferCount >= renderer->submittedCommandBufferCapacity) { renderer->submittedCommandBufferCapacity = renderer->submittedCommandBufferCount + 1; @@ -3753,10 +3783,24 @@ static void D3D11_Submit( /* Present, if applicable */ if (d3d11CommandBuffer->swapchainData) { + uint32_t syncInterval = 1; + if (d3d11CommandBuffer->swapchainData->presentMode == REFRESH_PRESENTMODE_IMMEDIATE) + { + syncInterval = 0; + } + + uint32_t presentFlags = 0; + if ( renderer->supportsTearing && + (d3d11CommandBuffer->swapchainData->presentMode == REFRESH_PRESENTMODE_IMMEDIATE || + d3d11CommandBuffer->swapchainData->presentMode == REFRESH_PRESENTMODE_FIFO_RELAXED) + ) { + presentFlags = DXGI_PRESENT_ALLOW_TEARING; + } + IDXGISwapChain_Present( d3d11CommandBuffer->swapchainData->swapchain, - 1, /* FIXME: Assumes vsync! */ - 0 + syncInterval, + presentFlags ); } @@ -4040,6 +4084,7 @@ static Refresh_Device* D3D11_CreateDevice( PFN_CREATE_DXGI_FACTORY1 CreateDXGIFactoryFunc; PFN_D3D11_CREATE_DEVICE D3D11CreateDeviceFunc; D3D_FEATURE_LEVEL levels[] = { D3D_FEATURE_LEVEL_11_1 }; + IDXGIFactory5 *factory5; IDXGIFactory6 *factory6; uint32_t flags; DXGI_ADAPTER_DESC1 adapterDesc; @@ -4094,7 +4139,28 @@ static Refresh_Device* D3D11_CreateDevice( ); ERROR_CHECK_RETURN("Could not create DXGIFactory", NULL); - /* Get the default adapter */ + /* Check for explicit tearing support */ + res = IDXGIFactory1_QueryInterface( + renderer->factory, + &D3D_IID_IDXGIFactory5, + (void**) &factory5 + ); + if (SUCCEEDED(res)) + { + res = IDXGIFactory5_CheckFeatureSupport( + factory5, + DXGI_FEATURE_PRESENT_ALLOW_TEARING, + &renderer->supportsTearing, + sizeof(renderer->supportsTearing) + ); + if (FAILED(res)) + { + renderer->supportsTearing = FALSE; + } + IDXGIFactory5_Release(factory5); + } + + /* Select the appropriate device for rendering */ res = IDXGIAdapter1_QueryInterface( renderer->factory, &D3D_IID_IDXGIFactory6, @@ -4109,6 +4175,7 @@ static Refresh_Device* D3D11_CreateDevice( &D3D_IID_IDXGIAdapter1, &renderer->adapter ); + IDXGIFactory6_Release(factory6); } else { @@ -4166,7 +4233,7 @@ tryCreateDevice: SDL_arraysize(levels), D3D11_SDK_VERSION, &d3d11Device, - &renderer->featureLevel, + NULL, &renderer->immediateContext ); if (FAILED(res) && debugMode) diff --git a/src/Refresh_Driver_D3D11_cdefines.h b/src/Refresh_Driver_D3D11_cdefines.h index da87aef..3caa2e6 100644 --- a/src/Refresh_Driver_D3D11_cdefines.h +++ b/src/Refresh_Driver_D3D11_cdefines.h @@ -30,6 +30,8 @@ typedef HRESULT(WINAPI* PFN_DXGI_GET_DEBUG_INTERFACE)(const GUID* riid, void** p /* IIDs (from https://magnumdb.com) */ static const IID D3D_IID_IDXGIFactory1 = { 0x770aae78,0xf26f,0x4dba,{0xa8,0x29,0x25,0x3c,0x83,0xd1,0xb3,0x87} }; +static const IID D3D_IID_IDXGIFactory4 = { 0x1bc6ea02,0xef36,0x464f,{0xbf,0x0c,0x21,0xca,0x39,0xe5,0x16,0x8a} }; +static const IID D3D_IID_IDXGIFactory5 = { 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_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} };