From 4699d4162a36ee26eb03346eccd5ab1f48168466 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Mon, 13 Apr 2020 01:42:04 +0100 Subject: [PATCH] [d3d9] Implement swapchain containers for surfaces Fixes a crash in L.A. Noire. Closes #1564 --- src/d3d9/d3d9_device.cpp | 8 +++---- src/d3d9/d3d9_subresource.h | 11 +++++---- src/d3d9/d3d9_surface.cpp | 46 ++++++++++++++++++++++++++----------- src/d3d9/d3d9_surface.h | 5 ++-- src/d3d9/d3d9_swapchain.cpp | 8 +++---- src/d3d9/d3d9_swapchain.h | 2 +- src/d3d9/d3d9_volume.cpp | 10 ++++++-- 7 files changed, 59 insertions(+), 31 deletions(-) diff --git a/src/d3d9/d3d9_device.cpp b/src/d3d9/d3d9_device.cpp index d443ee51..645adad0 100644 --- a/src/d3d9/d3d9_device.cpp +++ b/src/d3d9/d3d9_device.cpp @@ -3318,7 +3318,7 @@ namespace dxvk { return D3DERR_INVALIDCALL; try { - const Com surface = new D3D9Surface(this, &desc); + const Com surface = new D3D9Surface(this, &desc, nullptr); m_initializer->InitTexture(surface->GetCommonTexture()); *ppSurface = surface.ref(); return D3D_OK; @@ -3361,7 +3361,7 @@ namespace dxvk { return D3DERR_INVALIDCALL; try { - const Com surface = new D3D9Surface(this, &desc); + const Com surface = new D3D9Surface(this, &desc, nullptr); m_initializer->InitTexture(surface->GetCommonTexture()); *ppSurface = surface.ref(); return D3D_OK; @@ -3406,7 +3406,7 @@ namespace dxvk { return D3DERR_INVALIDCALL; try { - const Com surface = new D3D9Surface(this, &desc); + const Com surface = new D3D9Surface(this, &desc, nullptr); m_initializer->InitTexture(surface->GetCommonTexture()); *ppSurface = surface.ref(); return D3D_OK; @@ -6695,7 +6695,7 @@ namespace dxvk { if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc))) return D3DERR_NOTAVAILABLE; - m_autoDepthStencil = new D3D9Surface(this, &desc); + m_autoDepthStencil = new D3D9Surface(this, &desc, nullptr); m_initializer->InitTexture(m_autoDepthStencil->GetCommonTexture()); SetDepthStencilSurface(m_autoDepthStencil.ptr()); } diff --git a/src/d3d9/d3d9_subresource.h b/src/d3d9/d3d9_subresource.h index c96d8243..c853ed05 100644 --- a/src/d3d9/d3d9_subresource.h +++ b/src/d3d9/d3d9_subresource.h @@ -15,8 +15,10 @@ namespace dxvk { D3D9CommonTexture* pTexture, UINT Face, UINT MipLevel, - IDirect3DBaseTexture9* pContainer) + IDirect3DBaseTexture9* pBaseTexture, + IUnknown* pContainer) : D3D9Resource ( pDevice ) + , m_baseTexture ( pBaseTexture ) , m_container ( pContainer ) , m_texture ( pTexture ) , m_face ( Face ) @@ -25,7 +27,7 @@ namespace dxvk { ~D3D9Subresource() { // We own the texture! - if (m_container == nullptr) + if (m_baseTexture == nullptr) delete m_texture; } @@ -108,7 +110,7 @@ namespace dxvk { } IDirect3DBaseTexture9* GetBaseTexture() { - return m_container; + return m_baseTexture; } void Swap(D3D9Subresource* Other) { @@ -121,7 +123,8 @@ namespace dxvk { protected: - IDirect3DBaseTexture9* m_container; + IUnknown* m_container; + IDirect3DBaseTexture9* m_baseTexture; D3D9CommonTexture* m_texture; UINT m_face; diff --git a/src/d3d9/d3d9_surface.cpp b/src/d3d9/d3d9_surface.cpp index f4189d5d..7ecbb8fd 100644 --- a/src/d3d9/d3d9_surface.cpp +++ b/src/d3d9/d3d9_surface.cpp @@ -1,5 +1,6 @@ #include "d3d9_surface.h" #include "d3d9_texture.h" +#include "d3d9_swapchain.h" #include "d3d9_device.h" @@ -7,34 +8,44 @@ namespace dxvk { D3D9Surface::D3D9Surface( D3D9DeviceEx* pDevice, - const D3D9_COMMON_TEXTURE_DESC* pDesc) + const D3D9_COMMON_TEXTURE_DESC* pDesc, + IUnknown* pContainer) : D3D9SurfaceBase( pDevice, new D3D9CommonTexture( pDevice, pDesc, D3DRTYPE_TEXTURE), 0, 0, - nullptr) { } + nullptr, + pContainer) { } D3D9Surface::D3D9Surface( D3D9DeviceEx* pDevice, D3D9CommonTexture* pTexture, UINT Face, UINT MipLevel, - IDirect3DBaseTexture9* pContainer) + IDirect3DBaseTexture9* pBaseTexture) : D3D9SurfaceBase( pDevice, pTexture, Face, MipLevel, - pContainer) { } + pBaseTexture, + pBaseTexture) { } void D3D9Surface::AddRefPrivate() { - IDirect3DBaseTexture9* pContainer = this->m_container; + IDirect3DBaseTexture9* pBaseTexture = this->m_baseTexture; + IUnknown* pSwapChain = this->m_container; - if (pContainer != nullptr) { - D3DRESOURCETYPE type = pContainer->GetType(); + if (pBaseTexture != nullptr) { + D3DRESOURCETYPE type = pBaseTexture->GetType(); if (type == D3DRTYPE_TEXTURE) - reinterpret_cast (pContainer)->AddRefPrivate(); + reinterpret_cast (pBaseTexture)->AddRefPrivate(); else //if (type == D3DRTYPE_CUBETEXTURE) - reinterpret_cast(pContainer)->AddRefPrivate(); + reinterpret_cast(pBaseTexture)->AddRefPrivate(); + + return; + } + else if (pSwapChain != nullptr) { + // Container must be a swapchain if it isn't a base texture. + reinterpret_cast(pSwapChain)->AddRefPrivate(); return; } @@ -43,14 +54,21 @@ namespace dxvk { } void D3D9Surface::ReleasePrivate() { - IDirect3DBaseTexture9* pContainer = this->m_container; + IDirect3DBaseTexture9* pBaseTexture = this->m_baseTexture; + IUnknown* pSwapChain = this->m_container; - if (pContainer != nullptr) { - D3DRESOURCETYPE type = pContainer->GetType(); + if (pBaseTexture != nullptr) { + D3DRESOURCETYPE type = pBaseTexture->GetType(); if (type == D3DRTYPE_TEXTURE) - reinterpret_cast (pContainer)->ReleasePrivate(); + reinterpret_cast (pBaseTexture)->ReleasePrivate(); else //if (type == D3DRTYPE_CUBETEXTURE) - reinterpret_cast(pContainer)->ReleasePrivate(); + reinterpret_cast(pBaseTexture)->ReleasePrivate(); + + return; + } + else if (pSwapChain != nullptr) { + // Container must be a swapchain if it isn't a base texture. + reinterpret_cast(pSwapChain)->ReleasePrivate(); return; } diff --git a/src/d3d9/d3d9_surface.h b/src/d3d9/d3d9_surface.h index 6e68bbae..d7c8f2b9 100644 --- a/src/d3d9/d3d9_surface.h +++ b/src/d3d9/d3d9_surface.h @@ -19,14 +19,15 @@ namespace dxvk { D3D9Surface( D3D9DeviceEx* pDevice, - const D3D9_COMMON_TEXTURE_DESC* pDesc); + const D3D9_COMMON_TEXTURE_DESC* pDesc, + IUnknown* pContainer); D3D9Surface( D3D9DeviceEx* pDevice, D3D9CommonTexture* pTexture, UINT Face, UINT MipLevel, - IDirect3DBaseTexture9* pContainer); + IDirect3DBaseTexture9* pBaseTexture); void AddRefPrivate(); diff --git a/src/d3d9/d3d9_swapchain.cpp b/src/d3d9/d3d9_swapchain.cpp index f28f62dd..80d1c94d 100644 --- a/src/d3d9/d3d9_swapchain.cpp +++ b/src/d3d9/d3d9_swapchain.cpp @@ -463,7 +463,7 @@ namespace dxvk { return D3DERR_INVALIDCALL; } - *ppBackBuffer = m_backBuffers[iBackBuffer].ref(); + *ppBackBuffer = ref(m_backBuffers[iBackBuffer].get()); return D3D_OK; } @@ -712,7 +712,7 @@ namespace dxvk { if (iBackBuffer >= m_presentParams.BackBufferCount) return nullptr; - return m_backBuffers[iBackBuffer].ptr(); + return m_backBuffers[iBackBuffer].get(); } @@ -876,7 +876,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].ptr()); + m_backBuffers[i]->Swap(m_backBuffers[i - 1].get()); m_parent->m_flags.set(D3D9DeviceFlag::DirtyFramebuffer); } @@ -1035,7 +1035,7 @@ namespace dxvk { desc.Discard = FALSE; for (uint32_t i = 0; i < m_backBuffers.size(); i++) - m_backBuffers[i] = new D3D9Surface(m_parent, &desc); + m_backBuffers[i] = std::make_unique(m_parent, &desc, this); auto swapImage = m_backBuffers[0]->GetCommonTexture()->GetImage(); diff --git a/src/d3d9/d3d9_swapchain.h b/src/d3d9/d3d9_swapchain.h index fded7fd7..1ed49807 100644 --- a/src/d3d9/d3d9_swapchain.h +++ b/src/d3d9/d3d9_swapchain.h @@ -129,7 +129,7 @@ namespace dxvk { DxvkLogicOpState m_loState; DxvkBlendMode m_blendMode; - std::vector> m_backBuffers; + std::vector> m_backBuffers; RECT m_srcRect; RECT m_dstRect; diff --git a/src/d3d9/d3d9_volume.cpp b/src/d3d9/d3d9_volume.cpp index b52b35b4..855a7a32 100644 --- a/src/d3d9/d3d9_volume.cpp +++ b/src/d3d9/d3d9_volume.cpp @@ -12,6 +12,7 @@ namespace dxvk { pDevice, new D3D9CommonTexture( pDevice, pDesc, D3DRTYPE_VOLUMETEXTURE ), 0, 0, + nullptr, nullptr) { } @@ -25,11 +26,14 @@ namespace dxvk { pDevice, pTexture, Face, MipLevel, + pContainer, pContainer) { } void D3D9Volume::AddRefPrivate() { - IDirect3DBaseTexture9* pContainer = this->m_container; + IDirect3DBaseTexture9* pContainer = this->m_baseTexture; + + // Can't have a swapchain container for a volume. if (pContainer != nullptr) { reinterpret_cast (pContainer)->AddRefPrivate(); @@ -41,7 +45,9 @@ namespace dxvk { void D3D9Volume::ReleasePrivate() { - IDirect3DBaseTexture9* pContainer = this->m_container; + IDirect3DBaseTexture9* pContainer = this->m_baseTexture; + + // Can't have a swapchain container for a volume. if (pContainer != nullptr) { reinterpret_cast (pContainer)->ReleasePrivate();