Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[D3D9] Fix for back buffer data loss during D3D9 present #2967

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/d3d9/d3d9_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ namespace dxvk {
this->strictPow = config.getOption<bool> ("d3d9.strictPow", true);
this->lenientClear = config.getOption<bool> ("d3d9.lenientClear", false);
this->numBackBuffers = config.getOption<int32_t> ("d3d9.numBackBuffers", 0);
this->noExplicitFrontBuffer = config.getOption<bool> ("d3d9.noExplicitFrontBuffer", false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also noExplicitFrontBuffer variable declared in d3d9_options.h

this->deferSurfaceCreation = config.getOption<bool> ("d3d9.deferSurfaceCreation", false);
this->samplerAnisotropy = config.getOption<int32_t> ("d3d9.samplerAnisotropy", -1);
this->maxAvailableMemory = config.getOption<int32_t> ("d3d9.maxAvailableMemory", 4096);
Expand Down
10 changes: 0 additions & 10 deletions src/d3d9/d3d9_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
47 changes: 42 additions & 5 deletions src/d3d9/d3d9_swapchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) } };
Expand Down Expand Up @@ -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());
K0bin marked this conversation as resolved.
Show resolved Hide resolved

m_parent->m_flags.set(D3D9DeviceFlag::DirtyFramebuffer);
}

Expand Down Expand Up @@ -840,6 +862,9 @@ namespace dxvk {
backBuffer->ClearContainer();

m_backBuffers.clear();

if (m_frontBuffer != nullptr)
m_frontBuffer->ClearContainer();
}


Expand All @@ -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;
Expand All @@ -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();

Expand All @@ -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());
}
Expand Down
3 changes: 2 additions & 1 deletion src/d3d9/d3d9_swapchain.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ namespace dxvk {
Rc<hud::Hud> m_hud;

std::vector<Com<D3D9Surface, false>> m_backBuffers;

Com<D3D9Surface, false> m_frontBuffer;

RECT m_srcRect;
RECT m_dstRect;

Expand Down
8 changes: 0 additions & 8 deletions src/util/config/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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" },
Expand Down