1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-13 16:08:50 +01:00

[d3d9] Don't swap buffers for SWAPEFFECT_COPY & DISCARD with 1 backbuffer

This commit is contained in:
Robin Kertels 2023-05-03 19:32:32 +02:00 committed by Joshie
parent 83a294285e
commit 5443a2f9f5
3 changed files with 54 additions and 23 deletions

View File

@ -44,6 +44,10 @@
#define D3DPRESENT_FORCEIMMEDIATE 0x00000100L #define D3DPRESENT_FORCEIMMEDIATE 0x00000100L
#endif #endif
#ifndef D3DSWAPEFFECT_COPY_VSYNC
#define D3DSWAPEFFECT_COPY_VSYNC 4
#endif
// MinGW headers are broken. Who'dve guessed? // MinGW headers are broken. Who'dve guessed?
#ifndef _MSC_VER #ifndef _MSC_VER
typedef struct _D3DDEVINFO_RESOURCEMANAGER typedef struct _D3DDEVINFO_RESOURCEMANAGER

View File

@ -153,9 +153,9 @@ namespace dxvk {
m_lastDialog = m_dialog; m_lastDialog = m_dialog;
#ifdef _WIN32 #ifdef _WIN32
const bool useGDIFallback = m_partialCopy && m_presentParams.SwapEffect == D3DSWAPEFFECT_COPY; const bool useGDIFallback = m_partialCopy && !HasFrontBuffer();
if (useGDIFallback) if (useGDIFallback)
return BlitGDI(window); return PresentImageGDI(window);
#endif #endif
try { try {
@ -176,7 +176,7 @@ namespace dxvk {
} catch (const DxvkError& e) { } catch (const DxvkError& e) {
Logger::err(e.message()); Logger::err(e.message());
#ifdef _WIN32 #ifdef _WIN32
return BlitGDI(window); return PresentImageGDI(window);
#else #else
return D3DERR_DEVICEREMOVED; return D3DERR_DEVICEREMOVED;
#endif #endif
@ -186,8 +186,11 @@ namespace dxvk {
#ifdef _WIN32 #ifdef _WIN32
#define DCX_USESTYLE 0x00010000 #define DCX_USESTYLE 0x00010000
HRESULT D3D9SwapChainEx::BlitGDI(HWND Window) { HRESULT D3D9SwapChainEx::PresentImageGDI(HWND Window) {
if (!std::exchange(m_warnedAboutFallback, true)) m_parent->EndFrame();
m_parent->Flush();
if (!std::exchange(m_warnedGDIAboutFallback, true))
Logger::warn("Using GDI for swapchain presentation. This will impact performance."); Logger::warn("Using GDI for swapchain presentation. This will impact performance.");
HDC hDC; HDC hDC;
@ -233,13 +236,18 @@ namespace dxvk {
// of src onto a temp image of dst's extents, // of src onto a temp image of dst's extents,
// then copy buffer back to dst (given dst is subresource) // then copy buffer back to dst (given dst is subresource)
// For SWAPEFFECT_COPY and windowed SWAPEFFECT_DISCARD with 1 backbuffer, we just copy the backbuffer data instead.
// We just copy from the backbuffer instead of the front buffer to avoid having to do another blit.
// This mostly impacts windowed mode and our implementation was not accurate in that case anyway as Windows D3D9
// takes a screenshot of the entire screen.
D3D9Surface* dst = static_cast<D3D9Surface*>(pDestSurface); D3D9Surface* dst = static_cast<D3D9Surface*>(pDestSurface);
if (unlikely(dst == nullptr)) if (unlikely(dst == nullptr))
return D3DERR_INVALIDCALL; return D3DERR_INVALIDCALL;
D3D9CommonTexture* dstTexInfo = dst->GetCommonTexture(); D3D9CommonTexture* dstTexInfo = dst->GetCommonTexture();
D3D9CommonTexture* srcTexInfo = m_backBuffers.back()->GetCommonTexture(); D3D9CommonTexture* srcTexInfo = GetFrontBuffer()->GetCommonTexture();
if (unlikely(dstTexInfo->Desc()->Pool != D3DPOOL_SYSTEMMEM && dstTexInfo->Desc()->Pool != D3DPOOL_SCRATCH)) if (unlikely(dstTexInfo->Desc()->Pool != D3DPOOL_SYSTEMMEM && dstTexInfo->Desc()->Pool != D3DPOOL_SCRATCH))
return D3DERR_INVALIDCALL; return D3DERR_INVALIDCALL;
@ -730,8 +738,8 @@ namespace dxvk {
m_parent->Flush(); m_parent->Flush();
// Retrieve the image and image view to present // Retrieve the image and image view to present
auto swapImage = m_backBuffers[0]->GetCommonTexture()->GetImage(); Rc<DxvkImage> swapImage = m_backBuffers[0]->GetCommonTexture()->GetImage();
auto swapImageView = m_backBuffers[0]->GetImageView(false); Rc<DxvkImageView> swapImageView = m_backBuffers[0]->GetImageView(false);
// Bump our frame id. // Bump our frame id.
++m_frameId; ++m_frameId;
@ -821,7 +829,6 @@ namespace dxvk {
RecreateSwapChain(m_vsync); RecreateSwapChain(m_vsync);
} }
void D3D9SwapChainEx::RecreateSwapChain(BOOL Vsync) { void D3D9SwapChainEx::RecreateSwapChain(BOOL Vsync) {
// Ensure that we can safely destroy the swap chain // Ensure that we can safely destroy the swap chain
m_device->waitForSubmission(&m_presentStatus); m_device->waitForSubmission(&m_presentStatus);
@ -954,7 +961,7 @@ namespace dxvk {
// creating a new one to free up resources // creating a new one to free up resources
DestroyBackBuffers(); DestroyBackBuffers();
int NumFrontBuffer = m_parent->GetOptions()->noExplicitFrontBuffer ? 0 : 1; int NumFrontBuffer = HasFrontBuffer() ? 1 : 0;
const uint32_t NumBuffers = NumBackBuffers + NumFrontBuffer; const uint32_t NumBuffers = NumBackBuffers + NumFrontBuffer;
m_backBuffers.reserve(NumBuffers); m_backBuffers.reserve(NumBuffers);
@ -1235,7 +1242,11 @@ namespace dxvk {
} }
bool D3D9SwapChainEx::UpdatePresentRegion(const RECT* pSourceRect, const RECT* pDestRect) { bool D3D9SwapChainEx::UpdatePresentRegion(const RECT* pSourceRect, const RECT* pDestRect) {
if (pSourceRect == nullptr) { const bool isWindowed = m_presentParams.Windowed;
// Tests show that present regions are ignored in fullscreen
if (pSourceRect == nullptr || !isWindowed) {
m_srcRect.top = 0; m_srcRect.top = 0;
m_srcRect.left = 0; m_srcRect.left = 0;
m_srcRect.right = m_presentParams.BackBufferWidth; m_srcRect.right = m_presentParams.BackBufferWidth;
@ -1249,7 +1260,7 @@ namespace dxvk {
wsi::getWindowSize(m_window, &width, &height); wsi::getWindowSize(m_window, &width, &height);
RECT dstRect; RECT dstRect;
if (pDestRect == nullptr) { if (pDestRect == nullptr || !isWindowed) {
// TODO: Should we hook WM_SIZE message for this? // TODO: Should we hook WM_SIZE message for this?
dstRect.top = 0; dstRect.top = 0;
dstRect.left = 0; dstRect.left = 0;
@ -1267,20 +1278,17 @@ namespace dxvk {
|| dstRect.bottom - dstRect.top != LONG(height); || dstRect.bottom - dstRect.top != LONG(height);
bool recreate = bool recreate =
m_dstRect.left != dstRect.left m_swapchainExtent.width != width
|| m_dstRect.top != dstRect.top || m_swapchainExtent.height != height;
|| m_dstRect.right != dstRect.right
|| m_dstRect.bottom != dstRect.bottom;
m_swapchainExtent = { width, height };
m_dstRect = dstRect; m_dstRect = dstRect;
return recreate; return recreate;
} }
VkExtent2D D3D9SwapChainEx::GetPresentExtent() { VkExtent2D D3D9SwapChainEx::GetPresentExtent() {
return VkExtent2D { return m_swapchainExtent;
std::max<uint32_t>(m_dstRect.right - m_dstRect.left, 1u),
std::max<uint32_t>(m_dstRect.bottom - m_dstRect.top, 1u) };
} }

View File

@ -41,7 +41,7 @@ namespace dxvk {
DWORD dwFlags); DWORD dwFlags);
#ifdef _WIN32 #ifdef _WIN32
HRESULT BlitGDI(HWND Window); HRESULT PresentImageGDI(HWND Window);
#endif #endif
HRESULT STDMETHODCALLTYPE GetFrontBufferData(IDirect3DSurface9* pDestSurface); HRESULT STDMETHODCALLTYPE GetFrontBufferData(IDirect3DSurface9* pDestSurface);
@ -107,6 +107,7 @@ namespace dxvk {
RECT m_srcRect; RECT m_srcRect;
RECT m_dstRect; RECT m_dstRect;
VkExtent2D m_swapchainExtent = { 0u, 0u };
bool m_partialCopy = false; bool m_partialCopy = false;
DxvkSubmitStatus m_presentStatus; DxvkSubmitStatus m_presentStatus;
@ -131,7 +132,7 @@ namespace dxvk {
double m_displayRefreshRate = 0.0; double m_displayRefreshRate = 0.0;
bool m_warnedAboutFallback = false; bool m_warnedGDIAboutFallback = false;
void PresentImage(UINT PresentInterval); void PresentImage(UINT PresentInterval);
@ -197,6 +198,24 @@ namespace dxvk {
std::string GetApiName(); std::string GetApiName();
const Com<D3D9Surface, false>& GetFrontBuffer() const {
return m_backBuffers.back();
}
bool HasFrontBuffer() const {
if (m_presentParams.SwapEffect == D3DSWAPEFFECT_COPY)
return false;
if (m_presentParams.SwapEffect == D3DSWAPEFFECT_COPY_VSYNC)
return false;
// Tests show that SWAPEEFFECT_DISCARD + 1 backbuffer in windowed mode behaves identically to SWAPEFFECT_COPY
// For SWAPEFFECT_COPY we don't swap buffers but do another blit to the front buffer instead.
if (m_presentParams.SwapEffect == D3DSWAPEFFECT_DISCARD && m_presentParams.BackBufferCount == 1 && m_presentParams.Windowed)
return false;
return true;
}
}; };
} }