mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-03-15 16:29:16 +01:00
[d3d9] Add option for extra frame buffer to fix GetFrameBufferData
This commit is contained in:
parent
3f7460931a
commit
65a91900f5
@ -765,6 +765,14 @@
|
|||||||
|
|
||||||
# d3d9.countLosableResources = True
|
# d3d9.countLosableResources = True
|
||||||
|
|
||||||
|
# Add an extra frame buffer when necessary
|
||||||
|
#
|
||||||
|
# Some games create a swapchain with only 1 buffer and still expect GetFrontBufferData() to correctly return back the data of the last present.
|
||||||
|
# To make that work correctly, we add a second buffer and copy to it every single frame.
|
||||||
|
# This is unnecessary for all but a single modded game (Silent Hill 2 Enhanced Edition), that's why it's a config option.
|
||||||
|
|
||||||
|
# d3d9.extraFrontbuffer = False
|
||||||
|
|
||||||
# Dref scaling for DXS0/FVF
|
# Dref scaling for DXS0/FVF
|
||||||
#
|
#
|
||||||
# Some early D3D8 games expect Dref (depth texcoord Z) to be on the range of
|
# Some early D3D8 games expect Dref (depth texcoord Z) to be on the range of
|
||||||
@ -843,4 +851,3 @@
|
|||||||
# - True/False
|
# - True/False
|
||||||
|
|
||||||
# d3d8.forceLegacyDiscard = False
|
# d3d8.forceLegacyDiscard = False
|
||||||
|
|
||||||
|
@ -75,6 +75,7 @@ namespace dxvk {
|
|||||||
this->clampNegativeLodBias = config.getOption<bool> ("d3d9.clampNegativeLodBias", false);
|
this->clampNegativeLodBias = config.getOption<bool> ("d3d9.clampNegativeLodBias", false);
|
||||||
this->countLosableResources = config.getOption<bool> ("d3d9.countLosableResources", true);
|
this->countLosableResources = config.getOption<bool> ("d3d9.countLosableResources", true);
|
||||||
this->reproducibleCommandStream = config.getOption<bool> ("d3d9.reproducibleCommandStream", false);
|
this->reproducibleCommandStream = config.getOption<bool> ("d3d9.reproducibleCommandStream", false);
|
||||||
|
this->extraFrontbuffer = config.getOption<bool> ("d3d9.extraFrontbuffer", false);
|
||||||
|
|
||||||
// D3D8 options
|
// D3D8 options
|
||||||
this->drefScaling = config.getOption<int32_t> ("d3d8.scaleDref", 0);
|
this->drefScaling = config.getOption<int32_t> ("d3d8.scaleDref", 0);
|
||||||
|
@ -151,6 +151,9 @@ namespace dxvk {
|
|||||||
|
|
||||||
/// Enable depth texcoord Z (Dref) scaling (D3D8 quirk)
|
/// Enable depth texcoord Z (Dref) scaling (D3D8 quirk)
|
||||||
int32_t drefScaling;
|
int32_t drefScaling;
|
||||||
|
|
||||||
|
/// Add an extra front buffer to make GetFrontBufferData() work correctly when the swapchain only has a single buffer
|
||||||
|
bool extraFrontbuffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -167,8 +167,27 @@ namespace dxvk {
|
|||||||
UpdatePresentRegion(pSourceRect, pDestRect);
|
UpdatePresentRegion(pSourceRect, pDestRect);
|
||||||
UpdatePresentParameters();
|
UpdatePresentParameters();
|
||||||
|
|
||||||
|
if (!SwapWithFrontBuffer() && m_parent->GetOptions()->extraFrontbuffer) {
|
||||||
|
// We never actually rotate in the front buffer.
|
||||||
|
// Just blit to it for GetFrontBufferData.
|
||||||
|
|
||||||
|
// When we have multiple buffers, the last buffer always acts as the front buffer.
|
||||||
|
// (See comment in PresentImage for an explaination why.)
|
||||||
|
// Games with a buffer count of 1 rely on the contents of the previous frame still
|
||||||
|
// being there, so we can't just add another buffer to the rotation.
|
||||||
|
// At the same time, they could call GetFrontBufferData after already rendering to the backbuffer.
|
||||||
|
// So we have to do a copy of the backbuffer that will be copied to the Vulkan backbuffer
|
||||||
|
// and keep that around for the next frame.
|
||||||
|
|
||||||
|
const auto& backbuffer = m_backBuffers[0];
|
||||||
|
const auto& frontbuffer = GetFrontBuffer();
|
||||||
|
if (FAILED(m_parent->StretchRect(backbuffer.ptr(), nullptr, frontbuffer.ptr(), nullptr, D3DTEXF_NONE))) {
|
||||||
|
Logger::err("Failed to blit to front buffer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
const bool useGDIFallback = m_partialCopy && !HasFrontBuffer();
|
const bool useGDIFallback = m_partialCopy && !SwapWithFrontBuffer();
|
||||||
if (useGDIFallback)
|
if (useGDIFallback)
|
||||||
return PresentImageGDI(m_window);
|
return PresentImageGDI(m_window);
|
||||||
#endif
|
#endif
|
||||||
@ -916,7 +935,17 @@ namespace dxvk {
|
|||||||
|
|
||||||
// Rotate swap chain buffers so that the back
|
// Rotate swap chain buffers so that the back
|
||||||
// buffer at index 0 becomes the front buffer.
|
// buffer at index 0 becomes the front buffer.
|
||||||
for (uint32_t i = 1; i < m_backBuffers.size(); i++)
|
uint32_t rotatingBufferCount = m_backBuffers.size();
|
||||||
|
if (!SwapWithFrontBuffer() && m_parent->GetOptions()->extraFrontbuffer) {
|
||||||
|
// The front buffer only exists for GetFrontBufferData
|
||||||
|
// and the application cannot obserse buffer swapping in GetBackBuffer()
|
||||||
|
rotatingBufferCount -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backbuffer 0 is the one that gets copied to the Vulkan swapchain backbuffer.
|
||||||
|
// => m_backBuffers[1] is the next one that gets presented
|
||||||
|
// and the currente m_backBuffers[0] ends up at the end of the vector.
|
||||||
|
for (uint32_t i = 1; i < rotatingBufferCount; i++)
|
||||||
m_backBuffers[i]->Swap(m_backBuffers[i - 1].ptr());
|
m_backBuffers[i]->Swap(m_backBuffers[i - 1].ptr());
|
||||||
|
|
||||||
m_parent->m_flags.set(D3D9DeviceFlag::DirtyFramebuffer);
|
m_parent->m_flags.set(D3D9DeviceFlag::DirtyFramebuffer);
|
||||||
@ -986,10 +1015,10 @@ namespace dxvk {
|
|||||||
// creating a new one to free up resources
|
// creating a new one to free up resources
|
||||||
DestroyBackBuffers();
|
DestroyBackBuffers();
|
||||||
|
|
||||||
int NumFrontBuffer = HasFrontBuffer() ? 1 : 0;
|
int frontBufferCount = (SwapWithFrontBuffer() || m_parent->GetOptions()->extraFrontbuffer) ? 1 : 0;
|
||||||
const uint32_t NumBuffers = NumBackBuffers + NumFrontBuffer;
|
const uint32_t bufferCount = NumBackBuffers + frontBufferCount;
|
||||||
|
|
||||||
m_backBuffers.reserve(NumBuffers);
|
m_backBuffers.reserve(bufferCount);
|
||||||
|
|
||||||
// Create new back buffer
|
// Create new back buffer
|
||||||
D3D9_COMMON_TEXTURE_DESC desc;
|
D3D9_COMMON_TEXTURE_DESC desc;
|
||||||
@ -1010,7 +1039,7 @@ namespace dxvk {
|
|||||||
// we might need to lock for the BlitGDI fallback path
|
// we might need to lock for the BlitGDI fallback path
|
||||||
desc.IsLockable = true;
|
desc.IsLockable = true;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < NumBuffers; i++) {
|
for (uint32_t i = 0; i < bufferCount; i++) {
|
||||||
D3D9Surface* surface;
|
D3D9Surface* surface;
|
||||||
try {
|
try {
|
||||||
surface = new D3D9Surface(m_parent, &desc, m_parent->IsExtended(), this, nullptr);
|
surface = new D3D9Surface(m_parent, &desc, m_parent->IsExtended(), this, nullptr);
|
||||||
|
@ -240,17 +240,19 @@ namespace dxvk {
|
|||||||
bool IsDeviceReset(D3D9WindowContext* wctx);
|
bool IsDeviceReset(D3D9WindowContext* wctx);
|
||||||
|
|
||||||
const Com<D3D9Surface, false>& GetFrontBuffer() const {
|
const Com<D3D9Surface, false>& GetFrontBuffer() const {
|
||||||
|
// Buffer 0 is the one that gets copied to the Vulkan backbuffer.
|
||||||
|
// We rotate buffers after presenting, so buffer 0 becomes the last buffer in the vector.
|
||||||
return m_backBuffers.back();
|
return m_backBuffers.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasFrontBuffer() const {
|
bool SwapWithFrontBuffer() const {
|
||||||
if (m_presentParams.SwapEffect == D3DSWAPEFFECT_COPY)
|
if (m_presentParams.SwapEffect == D3DSWAPEFFECT_COPY)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (m_presentParams.SwapEffect == D3DSWAPEFFECT_COPY_VSYNC)
|
if (m_presentParams.SwapEffect == D3DSWAPEFFECT_COPY_VSYNC)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Tests show that SWAPEEFFECT_DISCARD + 1 backbuffer in windowed mode behaves identically to SWAPEFFECT_COPY
|
// Tests show that SWAPEEFFECT_DISCARD with 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.
|
// 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)
|
if (m_presentParams.SwapEffect == D3DSWAPEFFECT_DISCARD && m_presentParams.BackBufferCount == 1 && m_presentParams.Windowed)
|
||||||
return false;
|
return false;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user