From 0e623450c0fa5ee0466162eb313dedbf02353986 Mon Sep 17 00:00:00 2001 From: Nukem Date: Thu, 9 Jan 2025 21:10:47 -0500 Subject: [PATCH 1/2] d3d11: Use modern flip model and tearing flags for swap chain creation --- Common/GPU/D3D11/thin3d_d3d11.cpp | 24 +++++++++++---- Windows/GPU/D3D11Context.cpp | 50 +++++++++++++++++++------------ Windows/GPU/D3D11Context.h | 1 + 3 files changed, 51 insertions(+), 24 deletions(-) diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index 1822e906c5..cd42458df5 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -215,6 +216,7 @@ private: ID3D11DeviceContext *context_; ID3D11DeviceContext1 *context1_; IDXGISwapChain *swapChain_; + bool swapChainTearingSupported_ = false; ID3D11Texture2D *bbRenderTargetTex_ = nullptr; // NOT OWNED ID3D11RenderTargetView *bbRenderTargetView_ = nullptr; @@ -367,6 +369,15 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de caps_.supportsD3D9 = false; } + if (swapChain_) { + DXGI_SWAP_CHAIN_DESC swapChainDesc; + swapChain_->GetDesc(&swapChainDesc); + + if (swapChainDesc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING) { + swapChainTearingSupported_ = true; + } + } + // Temp texture for read-back of small images. Custom textures are created on demand for larger ones. // TODO: Should really benchmark if this extra complexity has any benefit. D3D11_TEXTURE2D_DESC packDesc{}; @@ -478,14 +489,17 @@ void D3D11DrawContext::EndFrame() { void D3D11DrawContext::Present(PresentMode presentMode, int vblanks) { frameTimeHistory_[frameCount_].queuePresent = time_now_d(); - int interval = vblanks; - if (presentMode != PresentMode::FIFO) { - interval = 0; - } // Safety for libretro if (swapChain_) { - swapChain_->Present(interval, 0); + uint32_t interval = vblanks; + uint32_t flags = 0; + if (presentMode != PresentMode::FIFO) { + interval = 0; + flags |= swapChainTearingSupported_ ? DXGI_PRESENT_ALLOW_TEARING : 0; // Assume "vsync off" also means "allow tearing" + } + swapChain_->Present(interval, flags); } + curRenderTargetView_ = nullptr; curDepthStencilView_ = nullptr; frameCount_++; diff --git a/Windows/GPU/D3D11Context.cpp b/Windows/GPU/D3D11Context.cpp index b6aba1b895..e412da23b8 100644 --- a/Windows/GPU/D3D11Context.cpp +++ b/Windows/GPU/D3D11Context.cpp @@ -1,6 +1,7 @@ #include "ppsspp_config.h" #include "Common/CommonWindows.h" +#include #include #include @@ -152,35 +153,46 @@ bool D3D11Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) { // Obtain DXGI factory from device (since we used nullptr for pAdapter above) IDXGIFactory1 *dxgiFactory = nullptr; IDXGIDevice *dxgiDevice = nullptr; - IDXGIAdapter *adapter = nullptr; hr = device_->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast(&dxgiDevice)); if (SUCCEEDED(hr)) { + IDXGIAdapter *adapter = nullptr; hr = dxgiDevice->GetAdapter(&adapter); if (SUCCEEDED(hr)) { hr = adapter->GetParent(__uuidof(IDXGIFactory1), reinterpret_cast(&dxgiFactory)); - DXGI_ADAPTER_DESC desc; - adapter->GetDesc(&desc); adapter->Release(); } dxgiDevice->Release(); } - // DirectX 11.0 systems - DXGI_SWAP_CHAIN_DESC sd; - ZeroMemory(&sd, sizeof(sd)); - sd.BufferCount = 1; - sd.BufferDesc.Width = width; - sd.BufferDesc.Height = height; - sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - sd.BufferDesc.RefreshRate.Numerator = 60; - sd.BufferDesc.RefreshRate.Denominator = 1; - sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - sd.OutputWindow = hWnd_; - sd.SampleDesc.Count = 1; - sd.SampleDesc.Quality = 0; - sd.Windowed = TRUE; + // Create the swap chain. Modern features (flip model, tearing) require Windows 10 (DXGI 1.5) or newer. + swapChainDesc_.BufferCount = 1; + swapChainDesc_.BufferDesc.Width = width; + swapChainDesc_.BufferDesc.Height = height; + swapChainDesc_.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + swapChainDesc_.BufferDesc.RefreshRate.Numerator = 60; + swapChainDesc_.BufferDesc.RefreshRate.Denominator = 1; + swapChainDesc_.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swapChainDesc_.OutputWindow = hWnd_; + swapChainDesc_.SampleDesc.Count = 1; + swapChainDesc_.SampleDesc.Quality = 0; + swapChainDesc_.Windowed = TRUE; + swapChainDesc_.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; - hr = dxgiFactory->CreateSwapChain(device_, &sd, &swapChain_); + IDXGIFactory5 *dxgiFactory5 = nullptr; + hr = dxgiFactory->QueryInterface(__uuidof(IDXGIFactory5), (void**)&dxgiFactory5); + if (SUCCEEDED(hr)) { + swapChainDesc_.BufferCount = 2; + swapChainDesc_.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + + BOOL allowTearing = FALSE; + hr = dxgiFactory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing, sizeof(allowTearing)); + if (SUCCEEDED(hr) && allowTearing) { + swapChainDesc_.Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; + } + dxgiFactory5->Release(); + } + + hr = dxgiFactory->CreateSwapChain(device_, &swapChainDesc_, &swapChain_); dxgiFactory->MakeWindowAssociation(hWnd_, DXGI_MWA_NO_ALT_ENTER); dxgiFactory->Release(); @@ -224,7 +236,7 @@ void D3D11Context::Resize() { int width; int height; W32Util::GetWindowRes(hWnd_, &width, &height); - swapChain_->ResizeBuffers(0, width, height, DXGI_FORMAT_UNKNOWN, 0); + swapChain_->ResizeBuffers(0, width, height, DXGI_FORMAT_UNKNOWN, swapChainDesc_.Flags); GotBackbuffer(); } diff --git a/Windows/GPU/D3D11Context.h b/Windows/GPU/D3D11Context.h index f3d8ff4d8a..52ea65b07a 100644 --- a/Windows/GPU/D3D11Context.h +++ b/Windows/GPU/D3D11Context.h @@ -43,6 +43,7 @@ private: Draw::DrawContext *draw_ = nullptr; IDXGISwapChain *swapChain_ = nullptr; + DXGI_SWAP_CHAIN_DESC swapChainDesc_ = {}; ID3D11Device *device_ = nullptr; ID3D11Device1 *device1_ = nullptr; ID3D11DeviceContext *context_ = nullptr; From d5cd8e699b47f0eded5c0a2de4b5a60ab8df63ad Mon Sep 17 00:00:00 2001 From: Nukem Date: Thu, 9 Jan 2025 21:11:13 -0500 Subject: [PATCH 2/2] d3d11: Fix DXGI device ref count leak --- Common/GPU/D3D11/thin3d_d3d11.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index cd42458df5..beaaa8e1c4 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -405,6 +405,7 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de if (SUCCEEDED(hr)) { caps_.setMaxFrameLatencySupported = true; dxgiDevice1->SetMaximumFrameLatency(maxInflightFrames); + dxgiDevice1->Release(); } }