Skip to content

Commit

Permalink
Correct handling of Direct3D Depth Stencil Buffer
Browse files Browse the repository at this point in the history
  • Loading branch information
elishacloud committed Jul 4, 2024
1 parent aba79e1 commit 36e8c51
Show file tree
Hide file tree
Showing 10 changed files with 194 additions and 141 deletions.
2 changes: 1 addition & 1 deletion Dllmain/BuildNo.rc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
#define BUILD_NUMBER 7070
#define BUILD_NUMBER 7071
25 changes: 10 additions & 15 deletions ddraw/IDirect3DDeviceX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4031,16 +4031,17 @@ void m_IDirect3DDeviceX::InitDevice(DWORD DirectXVersion)
if (ddrawParent)
{
d3d9Device = ddrawParent->GetDirect3D9Device();
}

// Get device surface interface
if (CurrentRenderTarget)
{
CurrentRenderTarget->QueryInterface(IID_GetInterfaceX, (LPVOID*)&DeviceSurface);

if (DeviceSurface)
ddrawParent->SetD3DDevice(this);
if (CurrentRenderTarget)
{
DeviceSurface->AttachD9BackBuffer();
m_IDirectDrawSurfaceX* lpDDSrcSurfaceX = nullptr;

CurrentRenderTarget->QueryInterface(IID_GetInterfaceX, (LPVOID*)&lpDDSrcSurfaceX);
if (lpDDSrcSurfaceX)
{
lpCurrentRenderTargetX = lpDDSrcSurfaceX;
ddrawParent->SetRenderTargetSurface(lpCurrentRenderTargetX);
}
}
}

Expand All @@ -4058,12 +4059,6 @@ void m_IDirect3DDeviceX::ReleaseDevice()
if (ddrawParent && !Config.Exiting)
{
ddrawParent->ClearD3DDevice();

// Clear device surface interface
if (DeviceSurface && ddrawParent->DoesSurfaceExist(DeviceSurface))
{
DeviceSurface->DetachD9BackBuffer();
}
}
}

Expand Down
10 changes: 7 additions & 3 deletions ddraw/IDirect3DDeviceX.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class m_IDirect3DDeviceX : public IUnknown, public AddressLookupTableDdrawObject

// Convert Device
m_IDirectDrawX *ddrawParent = nullptr;
m_IDirectDrawSurfaceX* DeviceSurface = nullptr;
m_IDirectDrawSurfaceX* lpCurrentRenderTargetX = nullptr;
LPDIRECT3DDEVICE9 *d3d9Device = nullptr;
LPDIRECT3DPIXELSHADER9* colorkeyPixelShader = nullptr;
LPDIRECT3DVIEWPORT3 lpCurrentViewport = nullptr;
Expand Down Expand Up @@ -289,9 +289,13 @@ class m_IDirect3DDeviceX : public IUnknown, public AddressLookupTableDdrawObject
ddrawParent = ddraw;

// Store D3DDevice
if (ddrawParent && DeviceSurface)
if (ddrawParent)
{
ddrawParent->SetD3DDevice(this, DeviceSurface);
ddrawParent->SetD3DDevice(this);
if (lpCurrentRenderTargetX)
{
ddrawParent->SetRenderTargetSurface(lpCurrentRenderTargetX);
}
}
}
void ClearDdraw() { ddrawParent = nullptr; colorkeyPixelShader = nullptr; }
Expand Down
12 changes: 5 additions & 7 deletions ddraw/IDirect3DX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -624,13 +624,6 @@ HRESULT m_IDirect3DX::CreateDevice(REFCLSID rclsid, LPDIRECTDRAWSURFACE7 lpDDS,

*lplpD3DDevice = (LPDIRECT3DDEVICE7)p_IDirect3DDeviceX->GetWrapperInterfaceX(DirectXVersion);

SetCriticalSection();
if (ddrawParent)
{
ddrawParent->SetD3DDevice(p_IDirect3DDeviceX, DdrawSurface3D);
}
ReleaseCriticalSection();

return D3D_OK;
}

Expand Down Expand Up @@ -882,6 +875,11 @@ void m_IDirect3DX::InitDirect3D(DWORD DirectXVersion)
return;
}

if (ddrawParent)
{
ddrawParent->SetD3D(this);
}

// Get Cap9 cache
GetCap9Cache();

Expand Down
2 changes: 1 addition & 1 deletion ddraw/IDirect3DX.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,6 @@ class m_IDirect3DX : public IUnknown, public AddressLookupTableDdrawObject
ULONG Release(DWORD DirectXVersion);

// Functions handling the ddraw parent interface
void SetDdrawParent(m_IDirectDrawX *ddraw) { ddrawParent = ddraw; GetCap9Cache(); }
void SetDdrawParent(m_IDirectDrawX* ddraw) { ddrawParent = ddraw; GetCap9Cache(); ddrawParent->SetD3D(this); }
void ClearDdraw() { ddrawParent = nullptr; }
};
135 changes: 83 additions & 52 deletions ddraw/IDirectDrawSurfaceX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ HRESULT m_IDirectDrawSurfaceX::QueryInterface(REFIID riid, LPVOID FAR* ppvObj, D
lpD3DDeviceX->SetDdrawParent(ddrawParent);

SetCriticalSection();
ddrawParent->SetD3DDevice(lpD3DDeviceX, this);
ddrawParent->SetD3DDevice(lpD3DDeviceX);
ReleaseCriticalSection();
}
}
Expand Down Expand Up @@ -359,35 +359,41 @@ HRESULT m_IDirectDrawSurfaceX::AddAttachedSurface(LPDIRECTDRAWSURFACE7 lpDDSurfa
return c_hr;
}

m_IDirectDrawSurfaceX *lpAttachedSurface = nullptr;
m_IDirectDrawSurfaceX *lpAttachedSurfaceX = nullptr;

lpDDSurface->QueryInterface(IID_GetInterfaceX, (LPVOID*)&lpAttachedSurface);
lpDDSurface->QueryInterface(IID_GetInterfaceX, (LPVOID*)&lpAttachedSurfaceX);

if (lpAttachedSurface == this)
if (lpAttachedSurfaceX == this)
{
LOG_LIMIT(100, __FUNCTION__ << " Error: cannot attach self");
return DDERR_CANNOTATTACHSURFACE;
}

if (!ddrawParent->DoesSurfaceExist(lpAttachedSurface))
if (!ddrawParent->DoesSurfaceExist(lpAttachedSurfaceX))
{
LOG_LIMIT(100, __FUNCTION__ << " Error: invalid surface!");
return DDERR_INVALIDPARAMS;
}

if (DoesAttachedSurfaceExist(lpAttachedSurface))
if (DoesAttachedSurfaceExist(lpAttachedSurfaceX))
{
LOG_LIMIT(100, __FUNCTION__ << " Error: attached surface already exists");
return DDERR_SURFACEALREADYATTACHED;
}

DWORD AttachedSurfaceCaps = lpAttachedSurface->GetSurfaceCaps().dwCaps;
if (lpAttachedSurfaceX->IsDepthBuffer() && GetAttachedZBuffer())
{
LOG_LIMIT(100, __FUNCTION__ << " Error: zbuffer surface already exists");
return DDERR_CANNOTATTACHSURFACE;
}

DWORD AttachedSurfaceCaps = lpAttachedSurfaceX->GetSurfaceCaps().dwCaps;
if (!(((AttachedSurfaceCaps & DDSCAPS_BACKBUFFER) && (surfaceDesc2.ddsCaps.dwCaps & DDSCAPS_FRONTBUFFER)) ||
((AttachedSurfaceCaps & DDSCAPS_FRONTBUFFER) && (surfaceDesc2.ddsCaps.dwCaps & DDSCAPS_BACKBUFFER)) ||
((AttachedSurfaceCaps & DDSCAPS_MIPMAP) && (surfaceDesc2.ddsCaps.dwCaps & DDSCAPS_MIPMAP)) ||
(AttachedSurfaceCaps & DDSCAPS_ZBUFFER)))
{
LOG_LIMIT(100, __FUNCTION__ << " Error: cannot attach surface with this method. dwCaps: " << lpAttachedSurface->GetSurfaceCaps().dwCaps);
LOG_LIMIT(100, __FUNCTION__ << " Error: cannot attach surface with this method. dwCaps: " << lpAttachedSurfaceX->GetSurfaceCaps());
return DDERR_CANNOTATTACHSURFACE;
}

Expand All @@ -398,7 +404,25 @@ HRESULT m_IDirectDrawSurfaceX::AddAttachedSurface(LPDIRECTDRAWSURFACE7 lpDDSurfa
return DDERR_CANNOTATTACHSURFACE;
}

AddAttachedSurfaceToMap(lpAttachedSurface, true);
// Set depth buffer
if (lpAttachedSurfaceX->IsDepthBuffer())
{
// Verify depth buffer's with and height
if ((surfaceDesc2.dwFlags & (DDSD_WIDTH | DDSD_HEIGHT)) == (DDSD_WIDTH | DDSD_HEIGHT) &&
(surfaceDesc2.dwWidth != lpAttachedSurfaceX->surfaceDesc2.dwWidth || surfaceDesc2.dwHeight != lpAttachedSurfaceX->surfaceDesc2.dwHeight))
{
lpAttachedSurfaceX->ReleaseD9Surface(false, false);
lpAttachedSurfaceX->surfaceDesc2.dwWidth = surfaceDesc2.dwWidth;
lpAttachedSurfaceX->surfaceDesc2.dwHeight = surfaceDesc2.dwHeight;
}
// Set depth stencil
if (ddrawParent->GetRenderTargetSurface() == this)
{
ddrawParent->SetDepthStencilSurface(lpAttachedSurfaceX);
}
}

AddAttachedSurfaceToMap(lpAttachedSurfaceX, true);

lpDDSurface->AddRef();

Expand Down Expand Up @@ -962,23 +986,30 @@ HRESULT m_IDirectDrawSurfaceX::DeleteAttachedSurface(DWORD dwFlags, LPDIRECTDRAW
return DDERR_INVALIDPARAMS;
}

m_IDirectDrawSurfaceX *lpAttachedSurface = nullptr;
m_IDirectDrawSurfaceX *lpAttachedSurfaceX = nullptr;

lpDDSAttachedSurface->QueryInterface(IID_GetInterfaceX, (LPVOID*)&lpAttachedSurface);
lpDDSAttachedSurface->QueryInterface(IID_GetInterfaceX, (LPVOID*)&lpAttachedSurfaceX);

if (!DoesAttachedSurfaceExist(lpAttachedSurface))
if (!DoesAttachedSurfaceExist(lpAttachedSurfaceX))
{
LOG_LIMIT(100, __FUNCTION__ << " Error: could not find attached surface");
return DDERR_SURFACENOTATTACHED;
}

if (!WasAttachedSurfaceAdded(lpAttachedSurface))
if (!WasAttachedSurfaceAdded(lpAttachedSurfaceX))
{
LOG_LIMIT(100, __FUNCTION__ << " Error: only surfaces added with AddAttachedSurface can be deleted with this method");
return DDERR_CANNOTDETACHSURFACE;
}

RemoveAttachedSurfaceFromMap(lpAttachedSurface);
// clear zbuffer
if (lpAttachedSurfaceX->IsDepthBuffer() &&
(ddrawParent->GetDepthStencilSurface() == lpAttachedSurfaceX || ddrawParent->GetRenderTargetSurface() == this))
{
ddrawParent->SetDepthStencilSurface(nullptr);
}

RemoveAttachedSurfaceFromMap(lpAttachedSurfaceX);

lpDDSAttachedSurface->Release();

Expand All @@ -993,6 +1024,18 @@ HRESULT m_IDirectDrawSurfaceX::DeleteAttachedSurface(DWORD dwFlags, LPDIRECTDRAW
return ProxyInterface->DeleteAttachedSurface(dwFlags, lpDDSAttachedSurface);
}

m_IDirectDrawSurfaceX* m_IDirectDrawSurfaceX::GetAttachedZBuffer()
{
for (auto& it : AttachedSurfaceMap)
{
if (it.second.pSurface->IsDepthBuffer())
{
return it.second.pSurface;
}
}
return nullptr;
}

HRESULT m_IDirectDrawSurfaceX::GetMipMapSubLevel(LPDIRECTDRAWSURFACE7 FAR* lplpDDAttachedSurface, DWORD MipMapLevel, DWORD DirectXVersion)
{
// Check for device interface to ensure correct max MipMap level
Expand Down Expand Up @@ -1608,20 +1651,6 @@ HRESULT m_IDirectDrawSurfaceX::GetAttachedSurface2(LPDDSCAPS2 lpDDSCaps2, LPDIRE
return DDERR_NOTFOUND;
}

// Handle zbuffer
if ((lpDDSCaps2->dwCaps && DDSCAPS_ZBUFFER) && (IsRenderingTarget() || (GetSurfaceCaps().dwCaps & DDSCAPS_BACKBUFFER)))
{
m_IDirectDrawSurfaceX* m_SurfaceX = ddrawParent->GetDepthStencilSurface();
if (m_SurfaceX)
{
*lplpDDAttachedSurface = (LPDIRECTDRAWSURFACE7)m_SurfaceX->GetWrapperInterfaceX(DirectXVersion);

(*lplpDDAttachedSurface)->AddRef();

return DD_OK;
}
}

LOG_LIMIT(100, __FUNCTION__ << " Error: failed to find attached surface that matches the capabilities requested: " << *lpDDSCaps2 <<
" Attached number of surfaces: " << AttachedSurfaceMap.size() << " MaxMipMapLevel: " << MaxMipMapLevel);
return DDERR_NOTFOUND;
Expand Down Expand Up @@ -4447,16 +4476,16 @@ HRESULT m_IDirectDrawSurfaceX::CreateDCSurface()
// Update surface description
void m_IDirectDrawSurfaceX::UpdateSurfaceDesc()
{
if ((surfaceDesc2.dwFlags & (DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT)) != (DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT))
// Check for device interface
if (FAILED(CheckInterface(__FUNCTION__, false, false, false)))
{
// Check for device interface
if (FAILED(CheckInterface(__FUNCTION__, false, false, false)))
{
return;
}
return;
}

bool IsChanged = false;
if ((surfaceDesc2.dwFlags & (DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT)) != (DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT))
{
// Get resolution
bool IsChanged = false;
DWORD Width, Height, RefreshRate, BPP;
ddrawParent->GetSurfaceDisplay(Width, Height, BPP, RefreshRate);

Expand Down Expand Up @@ -4517,6 +4546,21 @@ void m_IDirectDrawSurfaceX::UpdateSurfaceDesc()
{
surfaceFormat = GetDisplayFormat(surfaceDesc2.ddpfPixelFormat);
}
// Set attached stencil surface size
if (IsChanged && (surfaceDesc2.dwFlags & (DDSD_WIDTH | DDSD_HEIGHT)) == (DDSD_WIDTH | DDSD_HEIGHT))
{
m_IDirectDrawSurfaceX* lpAttachedSurfaceX = GetAttachedZBuffer();
if (lpAttachedSurfaceX && (surfaceDesc2.dwWidth != lpAttachedSurfaceX->surfaceDesc2.dwWidth || surfaceDesc2.dwHeight != lpAttachedSurfaceX->surfaceDesc2.dwHeight))
{
lpAttachedSurfaceX->ReleaseD9Surface(false, false);
lpAttachedSurfaceX->surfaceDesc2.dwWidth = surfaceDesc2.dwWidth;
lpAttachedSurfaceX->surfaceDesc2.dwHeight = surfaceDesc2.dwHeight;
if (ddrawParent->GetRenderTargetSurface() == this)
{
ddrawParent->SetDepthStencilSurface(lpAttachedSurfaceX);
}
}
}
}

// Release surface and vertext buffer
Expand Down Expand Up @@ -4657,11 +4701,12 @@ void m_IDirectDrawSurfaceX::ReleaseD9Surface(bool BackupData, bool ResetSurface)
ReleaseD9ContextSurface();

// Release d3d9 3D surface
if (surface.Surface && (!ResetSurface || IsD9UsingVideoMemory()))
if (surface.Surface && (!ResetSurface || IsD9UsingVideoMemory() || IsDepthBuffer()))
{
Logging::LogDebug() << __FUNCTION__ << " Releasing Direct3D9 surface";
if (IsDepthBuffer() && d3d9Device && *d3d9Device)
if (IsDepthBuffer() && d3d9Device && *d3d9Device && ddrawParent && ddrawParent->GetDepthStencilSurface() == this)
{
(*d3d9Device)->SetRenderState(D3DRS_ZENABLE, FALSE);
(*d3d9Device)->SetDepthStencilSurface(nullptr);
}
ULONG ref = surface.Surface->Release();
Expand Down Expand Up @@ -4753,20 +4798,6 @@ inline void m_IDirectDrawSurfaceX::ReleaseDCSurface()
}
}

bool m_IDirectDrawSurfaceX::SetDepthSencil()
{
if (IsDepthBuffer() &&
SUCCEEDED(CheckInterface(__FUNCTION__, true, true, false)) &&
SUCCEEDED((*d3d9Device)->SetDepthStencilSurface(surface.Surface)))
{
(*d3d9Device)->SetRenderState(D3DRS_ZENABLE, TRUE);
return true;
}

LOG_LIMIT(100, __FUNCTION__ << " Error: failed to set depth buffer surface!");
return false;
}

// Present surface
HRESULT m_IDirectDrawSurfaceX::PresentSurface(bool IsSkipScene)
{
Expand Down Expand Up @@ -5867,7 +5898,7 @@ HRESULT m_IDirectDrawSurfaceX::CopySurface(m_IDirectDrawSurfaceX* pSourceSurface
UnlockSrc = true;

// Check if source and destination memory addresses are overlapping
if (this == pSourceSurface)
if (pSourceSurface == this)
{
size_t size = SrcRectWidth * ByteCount * SrcRectHeight;
if (size > ByteArray.size())
Expand Down
6 changes: 1 addition & 5 deletions ddraw/IDirectDrawSurfaceX.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,6 @@ class m_IDirectDrawSurfaceX : public IUnknown, public AddressLookupTableDdrawObj
LONG overlayY = 0;
DWORD Priority = 0;

bool Is3DRenderingTarget = false; // Surface used for Direct3D rendering target, called from m_IDirect3DX::CreateDevice()
bool Using3D = false; // Direct3D is being used on top of DirectDraw
bool DCRequiresEmulation = false;
bool SurfaceRequiresEmulation = false;
Expand Down Expand Up @@ -434,7 +433,6 @@ class m_IDirectDrawSurfaceX : public IUnknown, public AddressLookupTableDdrawObj
// Direct3D9 interface functions
void ReleaseD9ContextSurface();
void ReleaseD9Surface(bool BackupData, bool ResetSurface);
bool SetDepthSencil();
HRESULT PresentSurface(bool isSkipScene);
void ResetSurfaceDisplay();

Expand All @@ -451,7 +449,6 @@ class m_IDirectDrawSurfaceX : public IUnknown, public AddressLookupTableDdrawObj
inline bool IsSurfaceManaged() { return (surfaceDesc2.ddsCaps.dwCaps2 & (DDSCAPS2_TEXTUREMANAGE | DDSCAPS2_D3DTEXTUREMANAGE)) != 0; }
inline bool IsUsingEmulation() { return (surface.emu && surface.emu->DC && surface.emu->GameDC && surface.emu->pBits); }
inline bool IsEmulationDCReady() { return (IsUsingEmulation() && !surface.emu->UsingGameDC); }
inline bool IsRenderingTarget() { return Is3DRenderingTarget; }
inline bool IsSurfaceDirty() { return surface.IsDirtyFlag; }
inline DWORD GetD39MipMapLevel(DWORD MipMapLevel) { return min(MipMapLevel, MaxMipMapLevel - 1); }
bool GetColorKeyForShader(float(&lowColorKey)[4], float(&highColorKey)[4]);
Expand All @@ -469,8 +466,7 @@ class m_IDirectDrawSurfaceX : public IUnknown, public AddressLookupTableDdrawObj
}
return false;
}
inline void AttachD9BackBuffer() { Is3DRenderingTarget = true; }
inline void DetachD9BackBuffer() { Is3DRenderingTarget = false; }
m_IDirectDrawSurfaceX* GetAttachedZBuffer();
LPDIRECT3DTEXTURE9 Get3DDrawTexture();
LPDIRECT3DSURFACE9 Get3DSurface();
LPDIRECT3DTEXTURE9 Get3DTexture();
Expand Down
Loading

0 comments on commit 36e8c51

Please sign in to comment.