1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-01-18 20:52:10 +01:00

[d3d9] Fix swapchain surface refs once and for all

The refcounting for d3d9 swapchain surfaces is very funny.
They don't actually hold any form of reference to their parent, unlike the surface->texture relationship.

When a swapchain is destroyed, the surfaces become orphans (like offscreen rendertargets) if they are still reffed.

Calling GetContainer on them when orphaned will return E_NOINTERFACE and nullptr for __uuidof(IDirect3DSwapChain)

Fixes some potential lingering refs on the device.
This commit is contained in:
Joshua Ashton 2020-04-26 12:58:19 +01:00 committed by Joshie
parent 353c7f7671
commit 9f4baf3f55
4 changed files with 20 additions and 21 deletions

View File

@ -30,7 +30,7 @@ namespace dxvk {
pBaseTexture,
pBaseTexture) { }
void D3D9Surface::AddRefPrivate(bool swapchain) {
void D3D9Surface::AddRefPrivate() {
if (m_baseTexture != nullptr) {
D3DRESOURCETYPE type = m_baseTexture->GetType();
if (type == D3DRTYPE_TEXTURE)
@ -40,15 +40,11 @@ namespace dxvk {
return;
}
else if (m_container != nullptr && !swapchain) {
// Container must be a swapchain if it isn't a base texture.
static_cast<D3D9SwapChainEx*>(m_container)->AddRefPrivate();
}
D3D9SurfaceBase::AddRefPrivate();
}
void D3D9Surface::ReleasePrivate(bool swapchain) {
void D3D9Surface::ReleasePrivate() {
if (m_baseTexture != nullptr) {
D3DRESOURCETYPE type = m_baseTexture->GetType();
if (type == D3DRTYPE_TEXTURE)
@ -58,10 +54,6 @@ namespace dxvk {
return;
}
else if (m_container != nullptr && !swapchain) {
// Container must be a swapchain if it isn't a base texture.
static_cast<D3D9SwapChainEx*>(m_container)->ReleasePrivate();
}
D3D9SurfaceBase::ReleasePrivate();
}
@ -188,4 +180,9 @@ namespace dxvk {
return D3D_OK;
}
void D3D9Surface::ClearContainer() {
m_container = nullptr;
}
}

View File

@ -29,9 +29,9 @@ namespace dxvk {
UINT MipLevel,
IDirect3DBaseTexture9* pBaseTexture);
void AddRefPrivate(bool swapchain = false);
void AddRefPrivate();
void ReleasePrivate(bool swapchain = false);
void ReleasePrivate();
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
@ -56,6 +56,8 @@ namespace dxvk {
};
}
void ClearContainer();
private:
D3D9GDIDesc m_dcDesc;

View File

@ -177,6 +177,8 @@ namespace dxvk {
D3D9SwapChainEx::~D3D9SwapChainEx() {
DestroyBackBuffers();
ResetWindowProc(m_window);
RestoreDisplayMode(m_monitor);
@ -463,7 +465,7 @@ namespace dxvk {
return D3DERR_INVALIDCALL;
}
*ppBackBuffer = ref(m_backBuffers[iBackBuffer]);
*ppBackBuffer = ref(m_backBuffers[iBackBuffer].ptr());
return D3D_OK;
}
@ -712,7 +714,7 @@ namespace dxvk {
if (iBackBuffer >= m_presentParams.BackBufferCount)
return nullptr;
return m_backBuffers[iBackBuffer];
return m_backBuffers[iBackBuffer].ptr();
}
@ -876,7 +878,7 @@ 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++)
m_backBuffers[i]->Swap(m_backBuffers[i - 1]);
m_backBuffers[i]->Swap(m_backBuffers[i - 1].ptr());
m_parent->m_flags.set(D3D9DeviceFlag::DirtyFramebuffer);
}
@ -1011,8 +1013,8 @@ namespace dxvk {
void D3D9SwapChainEx::DestroyBackBuffers() {
for (auto* backBuffer : m_backBuffers)
backBuffer->ReleasePrivate(true);
for (auto& backBuffer : m_backBuffers)
backBuffer->ClearContainer();
m_backBuffers.clear();
}
@ -1043,10 +1045,8 @@ namespace dxvk {
desc.Usage = D3DUSAGE_RENDERTARGET;
desc.Discard = FALSE;
for (uint32_t i = 0; i < m_backBuffers.size(); i++) {
for (uint32_t i = 0; i < m_backBuffers.size(); i++)
m_backBuffers[i] = new D3D9Surface(m_parent, &desc, this);
m_backBuffers[i]->AddRefPrivate(true);
}
auto swapImage = m_backBuffers[0]->GetCommonTexture()->GetImage();

View File

@ -129,7 +129,7 @@ namespace dxvk {
DxvkLogicOpState m_loState;
DxvkBlendMode m_blendMode;
std::vector<D3D9Surface*> m_backBuffers;
std::vector<Com<D3D9Surface, false>> m_backBuffers;
RECT m_srcRect;
RECT m_dstRect;