diff --git a/src/d3d9/d3d9_options.cpp b/src/d3d9/d3d9_options.cpp index 0eabb339164..40468feadf9 100644 --- a/src/d3d9/d3d9_options.cpp +++ b/src/d3d9/d3d9_options.cpp @@ -48,7 +48,6 @@ namespace dxvk { this->strictPow = config.getOption ("d3d9.strictPow", true); this->lenientClear = config.getOption ("d3d9.lenientClear", false); this->numBackBuffers = config.getOption ("d3d9.numBackBuffers", 0); - this->noExplicitFrontBuffer = config.getOption ("d3d9.noExplicitFrontBuffer", false); this->deferSurfaceCreation = config.getOption ("d3d9.deferSurfaceCreation", false); this->samplerAnisotropy = config.getOption ("d3d9.samplerAnisotropy", -1); this->maxAvailableMemory = config.getOption ("d3d9.maxAvailableMemory", 4096); diff --git a/src/d3d9/d3d9_options.h b/src/d3d9/d3d9_options.h index cb0b5d4d3dc..40d0604c47c 100644 --- a/src/d3d9/d3d9_options.h +++ b/src/d3d9/d3d9_options.h @@ -54,16 +54,6 @@ namespace dxvk { /// Overrides buffer count in present parameters. int32_t numBackBuffers; - /// Don't create an explicit front buffer in our own swapchain. The Vulkan swapchain is unaffected. - /// Some games don't handle front/backbuffer flipping very well because they don't always redraw - /// each frame completely, and rely on old pixel data from the previous frame to still be there. - /// When this option is set and a game only requests one backbuffer, there will be no flipping in - /// our own swapchain, so the game will always draw to the same buffer and can rely on old pixel - /// data to still be there after a Present call. - /// This means that D3D9SwapChainEx::GetFrontBufferData returns data from the backbuffer of the - /// previous frame, which is the same as the current backbuffer if only 1 backbuffer was requested. - bool noExplicitFrontBuffer; - /// Defer surface creation bool deferSurfaceCreation; diff --git a/src/d3d9/d3d9_swapchain.cpp b/src/d3d9/d3d9_swapchain.cpp index 8e078cf40a0..f57b8aa77e7 100644 --- a/src/d3d9/d3d9_swapchain.cpp +++ b/src/d3d9/d3d9_swapchain.cpp @@ -172,7 +172,7 @@ namespace dxvk { return D3DERR_INVALIDCALL; D3D9CommonTexture* dstTexInfo = dst->GetCommonTexture(); - D3D9CommonTexture* srcTexInfo = m_backBuffers.back()->GetCommonTexture(); + D3D9CommonTexture* srcTexInfo = m_frontBuffer->GetCommonTexture(); if (unlikely(dstTexInfo->Desc()->Pool != D3DPOOL_SYSTEMMEM && dstTexInfo->Desc()->Pool != D3DPOOL_SCRATCH)) return D3DERR_INVALIDCALL; @@ -673,6 +673,23 @@ namespace dxvk { m_context->beginRecording( m_device->createCommandList()); + if (m_presentParams.SwapEffect != D3DSWAPEFFECT_DISCARD) { + VkOffset3D srcOffset = { int32_t(m_srcRect.left), int32_t(m_srcRect.top), 0 }; + VkOffset3D dstOffset = { int32_t(m_dstRect.left), int32_t(m_dstRect.top), 0 }; + VkImageSubresourceLayers singleLayerSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }; + VkExtent3D copyExtent = + { uint32_t(m_dstRect.right - m_dstRect.left), uint32_t(m_dstRect.bottom - m_dstRect.top), 0 }; + + m_context->copyImage( + m_frontBuffer->GetCommonTexture()->GetImage(), + singleLayerSubresource, + srcOffset, + swapImage, + singleLayerSubresource, + dstOffset, + copyExtent); + } + VkRect2D srcRect = { { int32_t(m_srcRect.left), int32_t(m_srcRect.top) }, { uint32_t(m_srcRect.right - m_srcRect.left), uint32_t(m_srcRect.bottom - m_srcRect.top) } }; @@ -701,6 +718,11 @@ namespace dxvk { for (uint32_t i = 1; i < m_backBuffers.size(); i++) m_backBuffers[i]->Swap(m_backBuffers[i - 1].ptr()); + // For swap discard do not copy the content to the front buffer + // but replace the front buffer reference with the last back buffer. + if (m_presentParams.SwapEffect == D3DSWAPEFFECT_DISCARD) + m_backBuffers.back()->Swap(m_frontBuffer.ptr()); + m_parent->m_flags.set(D3D9DeviceFlag::DirtyFramebuffer); } @@ -840,6 +862,9 @@ namespace dxvk { backBuffer->ClearContainer(); m_backBuffers.clear(); + + if (m_frontBuffer != nullptr) + m_frontBuffer->ClearContainer(); } @@ -848,8 +873,7 @@ namespace dxvk { // creating a new one to free up resources DestroyBackBuffers(); - int NumFrontBuffer = m_parent->GetOptions()->noExplicitFrontBuffer ? 0 : 1; - m_backBuffers.resize(NumBackBuffers + NumFrontBuffer); + m_backBuffers.resize(NumBackBuffers); // Create new back buffer D3D9_COMMON_TEXTURE_DESC desc; @@ -867,8 +891,17 @@ namespace dxvk { desc.IsBackBuffer = TRUE; desc.IsAttachmentOnly = FALSE; - for (uint32_t i = 0; i < m_backBuffers.size(); i++) - m_backBuffers[i] = new D3D9Surface(m_parent, &desc, this, nullptr); + try { + for (uint32_t i = 0; i < m_backBuffers.size(); i++) + m_backBuffers[i] = new D3D9Surface(m_parent, &desc, this, nullptr); + + // Create an additional hidden front buffer. + m_frontBuffer = new D3D9Surface(m_parent, &desc, this, nullptr); + } + catch (const DxvkError& e) { + Logger::err(e.message()); + return D3DERR_OUTOFVIDEOMEMORY; + } auto swapImage = m_backBuffers[0]->GetCommonTexture()->GetImage(); @@ -890,6 +923,10 @@ namespace dxvk { subresources, VK_IMAGE_LAYOUT_UNDEFINED); } + m_context->initImage( + m_frontBuffer->GetCommonTexture()->GetImage(), + subresources, VK_IMAGE_LAYOUT_UNDEFINED); + m_device->submitCommandList( m_context->endRecording()); } diff --git a/src/d3d9/d3d9_swapchain.h b/src/d3d9/d3d9_swapchain.h index 9eae6a9630f..a8782839a2e 100644 --- a/src/d3d9/d3d9_swapchain.h +++ b/src/d3d9/d3d9_swapchain.h @@ -100,7 +100,8 @@ namespace dxvk { Rc m_hud; std::vector> m_backBuffers; - + Com m_frontBuffer; + RECT m_srcRect; RECT m_dstRect; diff --git a/src/util/config/config.cpp b/src/util/config/config.cpp index ffe2d89d18c..54dd6ca362e 100644 --- a/src/util/config/config.cpp +++ b/src/util/config/config.cpp @@ -404,10 +404,6 @@ namespace dxvk { { R"(\\ToEE\.exe$)", {{ { "d3d9.allowDiscard", "False" }, }} }, - /* ZUSI 3 - Aerosoft Edition */ - { R"(\\ZusiSim\.exe$)", {{ - { "d3d9.noExplicitFrontBuffer", "True" }, - }} }, /* GTA IV (NVAPI) */ /* Also thinks we're always on Intel * * and will report/use bad amounts of VRAM. @@ -482,10 +478,6 @@ namespace dxvk { { R"(\\SineMoraEX\.exe$)", {{ { "d3d9.maxFrameRate", "60" }, }} }, - /* Fantasy Grounds */ - { R"(\\FantasyGrounds\.exe$)", {{ - { "d3d9.noExplicitFrontBuffer", "True" }, - }} }, /* Red Orchestra 2 */ { R"(\\ROGame\.exe$)", {{ { "d3d9.floatEmulation", "Strict" },