1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-01-09 22:46:08 +01:00
dxvk/src/d3d9/d3d9_surface.cpp
Joshua Ashton 9f4baf3f55 [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.
2020-04-26 13:32:22 +01:00

189 lines
5.0 KiB
C++

#include "d3d9_surface.h"
#include "d3d9_texture.h"
#include "d3d9_swapchain.h"
#include "d3d9_device.h"
namespace dxvk {
D3D9Surface::D3D9Surface(
D3D9DeviceEx* pDevice,
const D3D9_COMMON_TEXTURE_DESC* pDesc,
IUnknown* pContainer)
: D3D9SurfaceBase(
pDevice,
new D3D9CommonTexture( pDevice, pDesc, D3DRTYPE_TEXTURE),
0, 0,
nullptr,
pContainer) { }
D3D9Surface::D3D9Surface(
D3D9DeviceEx* pDevice,
D3D9CommonTexture* pTexture,
UINT Face,
UINT MipLevel,
IDirect3DBaseTexture9* pBaseTexture)
: D3D9SurfaceBase(
pDevice,
pTexture,
Face, MipLevel,
pBaseTexture,
pBaseTexture) { }
void D3D9Surface::AddRefPrivate() {
if (m_baseTexture != nullptr) {
D3DRESOURCETYPE type = m_baseTexture->GetType();
if (type == D3DRTYPE_TEXTURE)
static_cast<D3D9Texture2D*> (m_baseTexture)->AddRefPrivate();
else //if (type == D3DRTYPE_CUBETEXTURE)
static_cast<D3D9TextureCube*>(m_baseTexture)->AddRefPrivate();
return;
}
D3D9SurfaceBase::AddRefPrivate();
}
void D3D9Surface::ReleasePrivate() {
if (m_baseTexture != nullptr) {
D3DRESOURCETYPE type = m_baseTexture->GetType();
if (type == D3DRTYPE_TEXTURE)
static_cast<D3D9Texture2D*> (m_baseTexture)->ReleasePrivate();
else //if (type == D3DRTYPE_CUBETEXTURE)
static_cast<D3D9TextureCube*>(m_baseTexture)->ReleasePrivate();
return;
}
D3D9SurfaceBase::ReleasePrivate();
}
HRESULT STDMETHODCALLTYPE D3D9Surface::QueryInterface(REFIID riid, void** ppvObject) {
if (ppvObject == nullptr)
return E_POINTER;
*ppvObject = nullptr;
if (riid == __uuidof(IUnknown)
|| riid == __uuidof(IDirect3DResource9)
|| riid == __uuidof(IDirect3DSurface9)) {
*ppvObject = ref(this);
return S_OK;
}
Logger::warn("D3D9Surface::QueryInterface: Unknown interface query");
Logger::warn(str::format(riid));
return E_NOINTERFACE;
}
D3DRESOURCETYPE STDMETHODCALLTYPE D3D9Surface::GetType() {
return D3DRTYPE_SURFACE;
}
HRESULT STDMETHODCALLTYPE D3D9Surface::GetDesc(D3DSURFACE_DESC *pDesc) {
if (pDesc == nullptr)
return D3DERR_INVALIDCALL;
auto& desc = *(m_texture->Desc());
pDesc->Format = static_cast<D3DFORMAT>(desc.Format);
pDesc->Type = D3DRTYPE_SURFACE;
pDesc->Usage = desc.Usage;
pDesc->Pool = desc.Pool;
pDesc->MultiSampleType = desc.MultiSample;
pDesc->MultiSampleQuality = desc.MultisampleQuality;
pDesc->Width = std::max(1u, desc.Width >> m_mipLevel);
pDesc->Height = std::max(1u, desc.Height >> m_mipLevel);
return D3D_OK;
}
HRESULT STDMETHODCALLTYPE D3D9Surface::LockRect(D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
D3DBOX box;
if (pRect != nullptr) {
box.Left = pRect->left;
box.Right = pRect->right;
box.Top = pRect->top;
box.Bottom = pRect->bottom;
box.Front = 0;
box.Back = 1;
}
D3DLOCKED_BOX lockedBox;
HRESULT hr = m_parent->LockImage(
m_texture,
m_face, m_mipLevel,
&lockedBox,
pRect != nullptr ? &box : nullptr,
Flags);
pLockedRect->pBits = lockedBox.pBits;
pLockedRect->Pitch = lockedBox.RowPitch;
return hr;
}
HRESULT STDMETHODCALLTYPE D3D9Surface::UnlockRect() {
return m_parent->UnlockImage(
m_texture,
m_face, m_mipLevel);
}
HRESULT STDMETHODCALLTYPE D3D9Surface::GetDC(HDC *phDC) {
if (phDC == nullptr)
return D3DERR_INVALIDCALL;
const D3D9_COMMON_TEXTURE_DESC& desc = *m_texture->Desc();
D3DLOCKED_RECT lockedRect;
HRESULT hr = LockRect(&lockedRect, nullptr, 0);
if (FAILED(hr))
return hr;
D3DKMT_CREATEDCFROMMEMORY createInfo;
// In...
createInfo.pMemory = lockedRect.pBits;
createInfo.Format = static_cast<D3DFORMAT>(desc.Format);
createInfo.Width = desc.Width;
createInfo.Height = desc.Height;
createInfo.Pitch = lockedRect.Pitch;
createInfo.hDeviceDc = CreateCompatibleDC(NULL);
createInfo.pColorTable = nullptr;
// Out...
createInfo.hBitmap = nullptr;
createInfo.hDc = nullptr;
D3DKMTCreateDCFromMemory(&createInfo);
DeleteDC(createInfo.hDeviceDc);
// These should now be set...
m_dcDesc.hDC = createInfo.hDc;
m_dcDesc.hBitmap = createInfo.hBitmap;
*phDC = m_dcDesc.hDC;
return D3D_OK;
}
HRESULT STDMETHODCALLTYPE D3D9Surface::ReleaseDC(HDC hDC) {
if (m_dcDesc.hDC == nullptr || m_dcDesc.hDC != hDC)
return D3DERR_INVALIDCALL;
D3DKMTDestroyDCFromMemory(&m_dcDesc);
HRESULT hr = UnlockRect();
if (FAILED(hr))
return hr;
return D3D_OK;
}
void D3D9Surface::ClearContainer() {
m_container = nullptr;
}
}