mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-03-14 04:29:15 +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
|
||||
|
||||
# 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
|
||||
#
|
||||
# Some early D3D8 games expect Dref (depth texcoord Z) to be on the range of
|
||||
@ -843,4 +851,3 @@
|
||||
# - True/False
|
||||
|
||||
# d3d8.forceLegacyDiscard = False
|
||||
|
||||
|
@ -75,6 +75,7 @@ namespace dxvk {
|
||||
this->clampNegativeLodBias = config.getOption<bool> ("d3d9.clampNegativeLodBias", false);
|
||||
this->countLosableResources = config.getOption<bool> ("d3d9.countLosableResources", true);
|
||||
this->reproducibleCommandStream = config.getOption<bool> ("d3d9.reproducibleCommandStream", false);
|
||||
this->extraFrontbuffer = config.getOption<bool> ("d3d9.extraFrontbuffer", false);
|
||||
|
||||
// D3D8 options
|
||||
this->drefScaling = config.getOption<int32_t> ("d3d8.scaleDref", 0);
|
||||
|
@ -151,6 +151,9 @@ namespace dxvk {
|
||||
|
||||
/// Enable depth texcoord Z (Dref) scaling (D3D8 quirk)
|
||||
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);
|
||||
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
|
||||
const bool useGDIFallback = m_partialCopy && !HasFrontBuffer();
|
||||
const bool useGDIFallback = m_partialCopy && !SwapWithFrontBuffer();
|
||||
if (useGDIFallback)
|
||||
return PresentImageGDI(m_window);
|
||||
#endif
|
||||
@ -916,7 +935,17 @@ namespace dxvk {
|
||||
|
||||
// Rotate swap chain buffers so that the back
|
||||
// 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_parent->m_flags.set(D3D9DeviceFlag::DirtyFramebuffer);
|
||||
@ -986,10 +1015,10 @@ namespace dxvk {
|
||||
// creating a new one to free up resources
|
||||
DestroyBackBuffers();
|
||||
|
||||
int NumFrontBuffer = HasFrontBuffer() ? 1 : 0;
|
||||
const uint32_t NumBuffers = NumBackBuffers + NumFrontBuffer;
|
||||
int frontBufferCount = (SwapWithFrontBuffer() || m_parent->GetOptions()->extraFrontbuffer) ? 1 : 0;
|
||||
const uint32_t bufferCount = NumBackBuffers + frontBufferCount;
|
||||
|
||||
m_backBuffers.reserve(NumBuffers);
|
||||
m_backBuffers.reserve(bufferCount);
|
||||
|
||||
// Create new back buffer
|
||||
D3D9_COMMON_TEXTURE_DESC desc;
|
||||
@ -1010,7 +1039,7 @@ namespace dxvk {
|
||||
// we might need to lock for the BlitGDI fallback path
|
||||
desc.IsLockable = true;
|
||||
|
||||
for (uint32_t i = 0; i < NumBuffers; i++) {
|
||||
for (uint32_t i = 0; i < bufferCount; i++) {
|
||||
D3D9Surface* surface;
|
||||
try {
|
||||
surface = new D3D9Surface(m_parent, &desc, m_parent->IsExtended(), this, nullptr);
|
||||
|
@ -240,17 +240,19 @@ namespace dxvk {
|
||||
bool IsDeviceReset(D3D9WindowContext* wctx);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
bool HasFrontBuffer() const {
|
||||
bool SwapWithFrontBuffer() 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
|
||||
// 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.
|
||||
if (m_presentParams.SwapEffect == D3DSWAPEFFECT_DISCARD && m_presentParams.BackBufferCount == 1 && m_presentParams.Windowed)
|
||||
return false;
|
||||
|
Loading…
x
Reference in New Issue
Block a user