[d3d9] Use most recently used swapchain for GetFrontBufferData

This commit is contained in:
Robin Kertels 2024-02-07 00:12:01 +01:00 committed by Joshie
parent eaa732d0b3
commit a0e39e94fa
3 changed files with 49 additions and 1 deletions

View File

@ -1093,7 +1093,12 @@ namespace dxvk {
if (unlikely(iSwapChain != 0))
return D3DERR_INVALIDCALL;
return m_implicitSwapchain->GetFrontBufferData(pDestSurface);
D3D9DeviceLock lock = LockDevice();
// In windowed mode, GetFrontBufferData takes a screenshot of the entire screen.
// We use the last used swapchain as a workaround.
// Total War: Medieval 2 relies on this.
return m_mostRecentlyUsedSwapchain->GetFrontBufferData(pDestSurface);
}
@ -7839,6 +7844,7 @@ namespace dxvk {
}
else
m_implicitSwapchain = new D3D9SwapChainEx(this, pPresentationParameters, pFullscreenDisplayMode);
m_mostRecentlyUsedSwapchain = m_implicitSwapchain.ptr();
if (pPresentationParameters->EnableAutoDepthStencil) {
D3D9_COMMON_TEXTURE_DESC desc;

View File

@ -1241,6 +1241,34 @@ namespace dxvk {
uint64_t GetCurrentSequenceNumber();
/**
* @brief Get the swapchain that was used the most recently for presenting
* Has to be externally synchronized.
*
* @return D3D9SwapChainEx* Swapchain
*/
D3D9SwapChainEx* GetMostRecentlyUsedSwapchain() {
return m_mostRecentlyUsedSwapchain;
}
/**
* @brief Set the swapchain that was used the most recently for presenting
* Has to be externally synchronized.
*
* @param swapchain Swapchain
*/
void SetMostRecentlyUsedSwapchain(D3D9SwapChainEx* swapchain) {
m_mostRecentlyUsedSwapchain = swapchain;
}
/**
* @brief Reset the most recently swapchain back to the implicit one
* Has to be externally synchronized.
*/
void ResetMostRecentlyUsedSwapchain() {
m_mostRecentlyUsedSwapchain = m_implicitSwapchain.ptr();
}
Com<D3D9InterfaceEx> m_parent;
D3DDEVTYPE m_deviceType;
HWND m_window;
@ -1403,6 +1431,8 @@ namespace dxvk {
HWND m_fullscreenWindow = NULL;
std::atomic<uint32_t> m_losableResourceCounter = { 0 };
D3D9SwapChainEx* m_mostRecentlyUsedSwapchain = nullptr;
#ifdef D3D9_ALLOW_UNMAPPING
lru_list<D3D9CommonTexture*> m_mappedTextures;
#endif

View File

@ -65,6 +65,16 @@ namespace dxvk {
if (this_thread::isInModuleDetachment())
return;
{
// Locking here and in Device::GetFrontBufferData
// ensures that other threads don't accidentally access a stale pointer.
D3D9DeviceLock lock = m_parent->LockDevice();
if (m_parent->GetMostRecentlyUsedSwapchain() == this) {
m_parent->ResetMostRecentlyUsedSwapchain();
}
}
DestroyBackBuffers();
ResetWindowProc(m_window);
@ -112,6 +122,8 @@ namespace dxvk {
DWORD dwFlags) {
D3D9DeviceLock lock = m_parent->LockDevice();
m_parent->SetMostRecentlyUsedSwapchain(this);
if (unlikely(m_parent->IsDeviceLost()))
return D3DERR_DEVICELOST;