Skip to content

Commit

Permalink
Add mip map levels to surface backup
Browse files Browse the repository at this point in the history
  • Loading branch information
elishacloud committed May 9, 2024
1 parent 2748e6b commit 0d5dcaa
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 56 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 7009
#define BUILD_NUMBER 7010
103 changes: 67 additions & 36 deletions ddraw/IDirectDrawSurfaceX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ HRESULT m_IDirectDrawSurfaceX::AddOverlayDirtyRect(LPRECT lpRect)
return ProxyInterface->AddOverlayDirtyRect(lpRect);
}

HRESULT m_IDirectDrawSurfaceX::Blt(LPRECT lpDestRect, LPDIRECTDRAWSURFACE7 lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwFlags, LPDDBLTFX lpDDBltFx, bool DontPresentBlt)
HRESULT m_IDirectDrawSurfaceX::Blt(LPRECT lpDestRect, LPDIRECTDRAWSURFACE7 lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwFlags, LPDDBLTFX lpDDBltFx, DWORD MipMapLevel, bool DontPresentBlt)
{
Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";

Expand Down Expand Up @@ -487,6 +487,13 @@ HRESULT m_IDirectDrawSurfaceX::Blt(LPRECT lpDestRect, LPDIRECTDRAWSURFACE7 lpDDS
return DDERR_NORASTEROPHW;
}

// MipMap level support
if (MipMapLevel)
{
LOG_LIMIT(100, __FUNCTION__ << " Error: Blt from MipMap level Not Implemented " << MipMapLevel);
return DDERR_GENERIC;
}

// Typically, Blt returns immediately with an error if the bitbltter is busy and the bitblt could not be set up. Specify the DDBLT_WAIT flag to request a synchronous bitblt.
const bool BltWait = ((dwFlags & DDBLT_WAIT) && (dwFlags & DDBLT_DONOTWAIT) == 0);

Expand Down Expand Up @@ -749,7 +756,7 @@ HRESULT m_IDirectDrawSurfaceX::Blt(LPRECT lpDestRect, LPDIRECTDRAWSURFACE7 lpDDS
return hr;
}

HRESULT m_IDirectDrawSurfaceX::BltBatch(LPDDBLTBATCH lpDDBltBatch, DWORD dwCount, DWORD dwFlags)
HRESULT m_IDirectDrawSurfaceX::BltBatch(LPDDBLTBATCH lpDDBltBatch, DWORD dwCount, DWORD dwFlags, DWORD MipMapLevel)
{
UNREFERENCED_PARAMETER(dwFlags);

Expand All @@ -775,7 +782,7 @@ HRESULT m_IDirectDrawSurfaceX::BltBatch(LPDDBLTBATCH lpDDBltBatch, DWORD dwCount
{
IsSkipScene |= (lpDDBltBatch[x].lprDest) ? CheckRectforSkipScene(*lpDDBltBatch[x].lprDest) : false;

hr = Blt(lpDDBltBatch[x].lprDest, (LPDIRECTDRAWSURFACE7)lpDDBltBatch[x].lpDDSSrc, lpDDBltBatch[x].lprSrc, lpDDBltBatch[x].dwFlags, lpDDBltBatch[x].lpDDBltFx, true);
hr = Blt(lpDDBltBatch[x].lprDest, (LPDIRECTDRAWSURFACE7)lpDDBltBatch[x].lpDDSSrc, lpDDBltBatch[x].lprSrc, lpDDBltBatch[x].dwFlags, lpDDBltBatch[x].lpDDBltFx, MipMapLevel, true);
if (FAILED(hr))
{
LOG_LIMIT(100, __FUNCTION__ << " Warning: BltBatch failed before the end! " << x << " of " << dwCount << " " << (DDERR)hr);
Expand All @@ -800,7 +807,7 @@ HRESULT m_IDirectDrawSurfaceX::BltBatch(LPDDBLTBATCH lpDDBltBatch, DWORD dwCount
return hr;
}

HRESULT m_IDirectDrawSurfaceX::BltFast(DWORD dwX, DWORD dwY, LPDIRECTDRAWSURFACE7 lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwFlags)
HRESULT m_IDirectDrawSurfaceX::BltFast(DWORD dwX, DWORD dwY, LPDIRECTDRAWSURFACE7 lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwFlags, DWORD MipMapLevel)
{
Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";

Expand Down Expand Up @@ -866,7 +873,7 @@ HRESULT m_IDirectDrawSurfaceX::BltFast(DWORD dwX, DWORD dwY, LPDIRECTDRAWSURFACE
}

// Call Blt
return Blt(pDestRect, lpDDSrcSurface, lpSrcRect, Flags, nullptr);
return Blt(pDestRect, lpDDSrcSurface, lpSrcRect, Flags, nullptr, MipMapLevel);
}

if (lpDDSrcSurface)
Expand Down Expand Up @@ -4010,38 +4017,49 @@ HRESULT m_IDirectDrawSurfaceX::CreateD3d9Surface()
CopyFromEmulatedSurface(nullptr);
RestoreData = true;
}
else if (!Backup.empty())
else if (!LostDeviceBackup.empty())
{
if (Backup.size() == GetSurfaceSize(surfaceFormat, surfaceDesc2.dwWidth, surfaceDesc2.dwHeight, surfaceDesc2.lPitch))
if (LostDeviceBackup[0].Bits.size() == GetSurfaceSize(surfaceFormat, surfaceDesc2.dwWidth, surfaceDesc2.dwHeight, surfaceDesc2.lPitch))
{
IDirect3DSurface9* pDestSurfaceD9 = GetD3D9Surface();
if (pDestSurfaceD9)
for (UINT Level = 0; Level < LostDeviceBackup.size(); Level++)
{
// Get pitch
LONG Pitch = (Format == D3DFMT_DXT1 || Format == D3DFMT_YV12) ? surfaceDesc2.dwWidth * 2 :
(ISDXTEX(Format)) ? surfaceDesc2.dwWidth * 4 :
surfaceDesc2.lPitch;
D3DLOCKED_RECT LockRect = {};
if (FAILED(LockD39Surface(&LockRect, nullptr, 0, Level)))
{
LOG_LIMIT(100, __FUNCTION__ << " Error: failed to restore surface data!");
break;
}

// Copy backup data to surface
RECT Rect = { 0, 0, (LONG)surfaceDesc2.dwWidth, (LONG)surfaceDesc2.dwHeight };
if (SUCCEEDED(D3DXLoadSurfaceFromMemory(pDestSurfaceD9, nullptr, &Rect, Backup.data(), (surfaceFormat == D3DFMT_P8) ? D3DFMT_L8 : surfaceFormat, Pitch, nullptr, &Rect, D3DX_FILTER_NONE, 0)))
Logging::LogDebug() << __FUNCTION__ << " Restoring Direct3D9 texture surface data: " << surfaceFormat;

D3DSURFACE_DESC Desc = {};
if (FAILED(surface.Texture ? surface.Texture->GetLevelDesc(GetD39MipMapLevel(Level), &Desc) : surface.Surface->GetDesc(&Desc)))
{
// Copy surface to emulated surface
if (IsUsingEmulation())
{
CopyToEmulatedSurface(&Rect);
}
RestoreData = true;
LOG_LIMIT(100, __FUNCTION__ << " Error: failed to get surface desc!");
break;
}
else

size_t size = GetSurfaceSize(surfaceFormat, Desc.Width, Desc.Height, LockRect.Pitch);

if (size == LostDeviceBackup[Level].Bits.size())
{
LOG_LIMIT(100, __FUNCTION__ << " Error: failed to restore surface data!");
memcpy(LockRect.pBits, LostDeviceBackup[Level].Bits.data(), size);
}

UnlockD39Surface(Level);

// Copy surface to emulated surface
if (IsUsingEmulation() && Level == 0)
{
CopyToEmulatedSurface(nullptr);
}

RestoreData = true;
}
}
else
{
LOG_LIMIT(100, __FUNCTION__ << " Warning: restore backup surface data size mismatch! Size: " << Backup.size() <<
LOG_LIMIT(100, __FUNCTION__ << " Warning: restore backup surface data size mismatch! Size: " << LostDeviceBackup[0].Bits.size() <<
" Surface pitch: " << surfaceDesc2.lPitch << " " << surfaceDesc2.dwWidth << "x" << surfaceDesc2.dwHeight);
}
}
Expand All @@ -4062,7 +4080,7 @@ HRESULT m_IDirectDrawSurfaceX::CreateD3d9Surface()
}

// Data is no longer needed
Backup.clear();
LostDeviceBackup.clear();
}

ReleaseLockCriticalSection();
Expand Down Expand Up @@ -4471,25 +4489,38 @@ void m_IDirectDrawSurfaceX::ReleaseD9Surface(bool BackupData, bool DeviceLost)
}
if (!IsUsingEmulation() && (surface.Texture || surface.Surface))
{
D3DLOCKED_RECT LockRect = {};
if (SUCCEEDED(LockD39Surface(&LockRect, nullptr, D3DLOCK_READONLY, 0)))
LostDeviceBackup.clear();

for (UINT Level = 0; Level < MaxMipMapLevel; Level++)
{
D3DLOCKED_RECT LockRect = {};
if (FAILED(LockD39Surface(&LockRect, nullptr, D3DLOCK_READONLY, Level)))
{
LOG_LIMIT(100, __FUNCTION__ << " Error: failed to backup surface data!");
break;
}

Logging::LogDebug() << __FUNCTION__ << " Storing Direct3D9 texture surface data: " << surfaceFormat;

size_t size = GetSurfaceSize(surfaceFormat, surfaceDesc2.dwWidth, surfaceDesc2.dwHeight, LockRect.Pitch);
D3DSURFACE_DESC Desc = {};
if (FAILED(surface.Texture ? surface.Texture->GetLevelDesc(GetD39MipMapLevel(Level), &Desc) : surface.Surface->GetDesc(&Desc)))
{
LOG_LIMIT(100, __FUNCTION__ << " Error: failed to get surface desc!");
break;
}

size_t size = GetSurfaceSize(surfaceFormat, Desc.Width, Desc.Height, LockRect.Pitch);

if (size)
{
Backup.resize(size);
DDBACKUP entry;
LostDeviceBackup.push_back(entry);
LostDeviceBackup[Level].Bits.resize(size);

memcpy(Backup.data(), LockRect.pBits, size);
memcpy(LostDeviceBackup[Level].Bits.data(), LockRect.pBits, size);
}

UnlockD39Surface(0);
}
else
{
LOG_LIMIT(100, __FUNCTION__ << " Error: failed to backup surface data!");
UnlockD39Surface(Level);
}
}
}
Expand Down
13 changes: 9 additions & 4 deletions ddraw/IDirectDrawSurfaceX.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ class m_IDirectDrawSurfaceX : public IUnknown, public AddressLookupTableDdrawObj
DWORD Width = 0;
};

struct DDBACKUP
{
std::vector<byte> Bits;
};

// Store a list of attached surfaces
struct ATTACHEDMAP
{
Expand Down Expand Up @@ -165,7 +170,7 @@ class m_IDirectDrawSurfaceX : public IUnknown, public AddressLookupTableDdrawObj
std::vector<RECT> LockRectList; // Rects used to lock the surface
DDRAWEMULATELOCK EmuLock; // For aligning bits after a lock for games that hard code the pitch
std::vector<byte> ByteArray; // Memory used for coping from one surface to the same surface
std::vector<byte> Backup; // Memory used for backing up the surfaceTexture
std::vector<DDBACKUP> LostDeviceBackup; // Memory used for backing up the surfaceTexture
COLORKEY ShaderColorKey; // Used to store color key array for shader
SURFACECREATE ShouldEmulate = SC_NOT_CREATED; // Used to help determine if surface should be emulated

Expand Down Expand Up @@ -335,9 +340,9 @@ class m_IDirectDrawSurfaceX : public IUnknown, public AddressLookupTableDdrawObj
/*** IDirectDrawSurface methods ***/
STDMETHOD(AddAttachedSurface)(THIS_ LPDIRECTDRAWSURFACE7);
STDMETHOD(AddOverlayDirtyRect)(THIS_ LPRECT);
HRESULT Blt(LPRECT, LPDIRECTDRAWSURFACE7, LPRECT, DWORD, LPDDBLTFX, bool DontPresentBlt = false);
STDMETHOD(BltBatch)(THIS_ LPDDBLTBATCH, DWORD, DWORD);
STDMETHOD(BltFast)(THIS_ DWORD, DWORD, LPDIRECTDRAWSURFACE7, LPRECT, DWORD);
HRESULT Blt(LPRECT, LPDIRECTDRAWSURFACE7, LPRECT, DWORD, LPDDBLTFX, DWORD, bool DontPresentBlt = false);
STDMETHOD(BltBatch)(THIS_ LPDDBLTBATCH, DWORD, DWORD, DWORD);
STDMETHOD(BltFast)(THIS_ DWORD, DWORD, LPDIRECTDRAWSURFACE7, LPRECT, DWORD, DWORD);
STDMETHOD(DeleteAttachedSurface)(THIS_ DWORD, LPDIRECTDRAWSURFACE7);
HRESULT EnumAttachedSurfaces(LPVOID, LPDDENUMSURFACESCALLBACK, DWORD);
HRESULT EnumAttachedSurfaces2(LPVOID, LPDDENUMSURFACESCALLBACK7, DWORD);
Expand Down
6 changes: 3 additions & 3 deletions ddraw/Versions/IDirectDrawSurface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ HRESULT m_IDirectDrawSurface::Blt(LPRECT a, LPDIRECTDRAWSURFACE b, LPRECT c, DWO
{
return DDERR_INVALIDOBJECT;
}
return ProxyInterface->Blt(a, (LPDIRECTDRAWSURFACE7)b, c, d, e);
return ProxyInterface->Blt(a, (LPDIRECTDRAWSURFACE7)b, c, d, e, MipMapLevel);
}

HRESULT m_IDirectDrawSurface::BltBatch(LPDDBLTBATCH a, DWORD b, DWORD c)
Expand All @@ -80,7 +80,7 @@ HRESULT m_IDirectDrawSurface::BltBatch(LPDDBLTBATCH a, DWORD b, DWORD c)
{
return DDERR_INVALIDOBJECT;
}
return ProxyInterface->BltBatch(a, b, c);
return ProxyInterface->BltBatch(a, b, c, MipMapLevel);
}

HRESULT m_IDirectDrawSurface::BltFast(DWORD a, DWORD b, LPDIRECTDRAWSURFACE c, LPRECT d, DWORD e)
Expand All @@ -89,7 +89,7 @@ HRESULT m_IDirectDrawSurface::BltFast(DWORD a, DWORD b, LPDIRECTDRAWSURFACE c, L
{
return DDERR_INVALIDOBJECT;
}
return ProxyInterface->BltFast(a, b, (LPDIRECTDRAWSURFACE7)c, d, e);
return ProxyInterface->BltFast(a, b, (LPDIRECTDRAWSURFACE7)c, d, e, MipMapLevel);
}

HRESULT m_IDirectDrawSurface::DeleteAttachedSurface(DWORD a, LPDIRECTDRAWSURFACE b)
Expand Down
6 changes: 3 additions & 3 deletions ddraw/Versions/IDirectDrawSurface2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,17 @@ HRESULT m_IDirectDrawSurface2::AddOverlayDirtyRect(LPRECT a)

HRESULT m_IDirectDrawSurface2::Blt(LPRECT a, LPDIRECTDRAWSURFACE2 b, LPRECT c, DWORD d, LPDDBLTFX e)
{
return ProxyInterface->Blt(a, (LPDIRECTDRAWSURFACE7)b, c, d, e);
return ProxyInterface->Blt(a, (LPDIRECTDRAWSURFACE7)b, c, d, e, MipMapLevel);
}

HRESULT m_IDirectDrawSurface2::BltBatch(LPDDBLTBATCH a, DWORD b, DWORD c)
{
return ProxyInterface->BltBatch(a, b, c);
return ProxyInterface->BltBatch(a, b, c, MipMapLevel);
}

HRESULT m_IDirectDrawSurface2::BltFast(DWORD a, DWORD b, LPDIRECTDRAWSURFACE2 c, LPRECT d, DWORD e)
{
return ProxyInterface->BltFast(a, b, (LPDIRECTDRAWSURFACE7)c, d, e);
return ProxyInterface->BltFast(a, b, (LPDIRECTDRAWSURFACE7)c, d, e, MipMapLevel);
}

HRESULT m_IDirectDrawSurface2::DeleteAttachedSurface(DWORD a, LPDIRECTDRAWSURFACE2 b)
Expand Down
6 changes: 3 additions & 3 deletions ddraw/Versions/IDirectDrawSurface3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,17 @@ HRESULT m_IDirectDrawSurface3::AddOverlayDirtyRect(LPRECT a)

HRESULT m_IDirectDrawSurface3::Blt(LPRECT a, LPDIRECTDRAWSURFACE3 b, LPRECT c, DWORD d, LPDDBLTFX e)
{
return ProxyInterface->Blt(a, (LPDIRECTDRAWSURFACE7)b, c, d, e);
return ProxyInterface->Blt(a, (LPDIRECTDRAWSURFACE7)b, c, d, e, MipMapLevel);
}

HRESULT m_IDirectDrawSurface3::BltBatch(LPDDBLTBATCH a, DWORD b, DWORD c)
{
return ProxyInterface->BltBatch(a, b, c);
return ProxyInterface->BltBatch(a, b, c, MipMapLevel);
}

HRESULT m_IDirectDrawSurface3::BltFast(DWORD a, DWORD b, LPDIRECTDRAWSURFACE3 c, LPRECT d, DWORD e)
{
return ProxyInterface->BltFast(a, b, (LPDIRECTDRAWSURFACE7)c, d, e);
return ProxyInterface->BltFast(a, b, (LPDIRECTDRAWSURFACE7)c, d, e, MipMapLevel);
}

HRESULT m_IDirectDrawSurface3::DeleteAttachedSurface(DWORD a, LPDIRECTDRAWSURFACE3 b)
Expand Down
6 changes: 3 additions & 3 deletions ddraw/Versions/IDirectDrawSurface4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,17 @@ HRESULT m_IDirectDrawSurface4::AddOverlayDirtyRect(LPRECT a)

HRESULT m_IDirectDrawSurface4::Blt(LPRECT a, LPDIRECTDRAWSURFACE4 b, LPRECT c, DWORD d, LPDDBLTFX e)
{
return ProxyInterface->Blt(a, (LPDIRECTDRAWSURFACE7)b, c, d, e);
return ProxyInterface->Blt(a, (LPDIRECTDRAWSURFACE7)b, c, d, e, MipMapLevel);
}

HRESULT m_IDirectDrawSurface4::BltBatch(LPDDBLTBATCH a, DWORD b, DWORD c)
{
return ProxyInterface->BltBatch(a, b, c);
return ProxyInterface->BltBatch(a, b, c, MipMapLevel);
}

HRESULT m_IDirectDrawSurface4::BltFast(DWORD a, DWORD b, LPDIRECTDRAWSURFACE4 c, LPRECT d, DWORD e)
{
return ProxyInterface->BltFast(a, b, (LPDIRECTDRAWSURFACE7)c, d, e);
return ProxyInterface->BltFast(a, b, (LPDIRECTDRAWSURFACE7)c, d, e, MipMapLevel);
}

HRESULT m_IDirectDrawSurface4::DeleteAttachedSurface(DWORD a, LPDIRECTDRAWSURFACE4 b)
Expand Down
6 changes: 3 additions & 3 deletions ddraw/Versions/IDirectDrawSurface7.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,17 @@ HRESULT m_IDirectDrawSurface7::AddOverlayDirtyRect(LPRECT a)

HRESULT m_IDirectDrawSurface7::Blt(LPRECT a, LPDIRECTDRAWSURFACE7 b, LPRECT c, DWORD d, LPDDBLTFX e)
{
return ProxyInterface->Blt(a, b, c, d, e);
return ProxyInterface->Blt(a, b, c, d, e, MipMapLevel);
}

HRESULT m_IDirectDrawSurface7::BltBatch(LPDDBLTBATCH a, DWORD b, DWORD c)
{
return ProxyInterface->BltBatch(a, b, c);
return ProxyInterface->BltBatch(a, b, c, MipMapLevel);
}

HRESULT m_IDirectDrawSurface7::BltFast(DWORD a, DWORD b, LPDIRECTDRAWSURFACE7 c, LPRECT d, DWORD e)
{
return ProxyInterface->BltFast(a, b, c, d, e);
return ProxyInterface->BltFast(a, b, c, d, e, MipMapLevel);
}

HRESULT m_IDirectDrawSurface7::DeleteAttachedSurface(DWORD a, LPDIRECTDRAWSURFACE7 b)
Expand Down

0 comments on commit 0d5dcaa

Please sign in to comment.