Skip to content

Commit e67948f

Browse files
Synchronize changes from 1.6 master branch [ci skip]
b162464 GPU driver handling tweaks that will improve stability for users affected by a range of graphics device-related issues
2 parents e4c625a + b162464 commit e67948f

File tree

4 files changed

+109
-10
lines changed

4 files changed

+109
-10
lines changed

Client/core/DXHook/CDirect3DEvents9.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,21 @@ void CDirect3DEvents9::OnInvalidate(IDirect3DDevice9* pDevice)
7676
{
7777
WriteDebugEvent("CDirect3DEvents9::OnInvalidate");
7878

79+
// Ensure device is in a valid state before invalidation
80+
// For example, Nvidia drivers can hang if device operations are attempted during invalid states
81+
if (pDevice->TestCooperativeLevel() == D3DERR_DEVICELOST)
82+
{
83+
WriteDebugEvent("OnInvalidate: Device already lost, skipping operations");
84+
return;
85+
}
86+
87+
// Flush any pending operations before invalidation
88+
g_pCore->GetGraphics()->GetRenderItemManager()->SaveReadableDepthBuffer();
89+
g_pCore->GetGraphics()->GetRenderItemManager()->FlushNonAARenderTarget();
90+
91+
// Force completion of all GPU operations
92+
pDevice->EndScene(); // Ensure we're not in scene during invalidation
93+
7994
// Invalidate the VMR9 Manager
8095
// CVideoManager::GetSingleton ().OnLostDevice ();
8196

Client/core/DXHook/CProxyDirect3DDevice9.cpp

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,24 @@ ULONG CProxyDirect3DDevice9::Release()
187187
/*** IDirect3DDevice9 methods ***/
188188
HRESULT CProxyDirect3DDevice9::TestCooperativeLevel()
189189
{
190-
return m_pDevice->TestCooperativeLevel();
190+
HRESULT hResult = m_pDevice->TestCooperativeLevel();
191+
192+
// Log device state transitions for debugging GPU driver issues
193+
static HRESULT lastResult = D3D_OK;
194+
if (hResult != lastResult)
195+
{
196+
WriteDebugEvent(SString("CProxyDirect3DDevice9::TestCooperativeLevel - Device state changed: %08x -> %08x", lastResult, hResult));
197+
lastResult = hResult;
198+
199+
// Additional safety for when transitioning to/from lost states
200+
if (hResult == D3DERR_DEVICELOST || hResult == D3DERR_DEVICENOTRESET)
201+
{
202+
// Give the driver a moment to stabilize
203+
Sleep(1);
204+
}
205+
}
206+
207+
return hResult;
191208
}
192209

193210
UINT CProxyDirect3DDevice9::GetAvailableTextureMem()
@@ -356,6 +373,19 @@ HRESULT CProxyDirect3DDevice9::Reset(D3DPRESENT_PARAMETERS* pPresentationParamet
356373
WriteDebugEvent("CProxyDirect3DDevice9::Reset - Invalid presentation parameters");
357374
return D3DERR_INVALIDCALL;
358375
}
376+
377+
// Check cooperative level before attempting reset
378+
HRESULT hCoopLevel = m_pDevice->TestCooperativeLevel();
379+
if (hCoopLevel == D3DERR_DEVICELOST)
380+
{
381+
WriteDebugEvent("Reset: Device still lost, cannot reset yet");
382+
return hCoopLevel;
383+
}
384+
else if (hCoopLevel != D3DERR_DEVICENOTRESET && hCoopLevel != D3D_OK)
385+
{
386+
WriteDebugEvent(SString("CProxyDirect3DDevice9::Reset - Device in unexpected state: %08x", hCoopLevel));
387+
return hCoopLevel;
388+
}
359389

360390
// Save presentation parameters
361391
D3DPRESENT_PARAMETERS presentationParametersOrig = *pPresentationParameters;
@@ -367,6 +397,9 @@ HRESULT CProxyDirect3DDevice9::Reset(D3DPRESENT_PARAMETERS* pPresentationParamet
367397
// Call our event handler.
368398
CDirect3DEvents9::OnInvalidate(m_pDevice);
369399

400+
// Give GPU driver time to complete any pending operations
401+
Sleep(1);
402+
370403
// Call the real reset routine.
371404
hResult = DoResetDevice(m_pDevice, pPresentationParameters, presentationParametersOrig);
372405

@@ -408,8 +441,13 @@ HRESULT CProxyDirect3DDevice9::Reset(D3DPRESENT_PARAMETERS* pPresentationParamet
408441
// Update our data.
409442
m_pData->StoreViewport(0, 0, pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight);
410443

411-
// Call our event handler.
412-
CDirect3DEvents9::OnRestore(m_pDevice);
444+
// Ensure scene state is properly restored
445+
// Call our event handler.
446+
CDirect3DEvents9::OnRestore(m_pDevice);
447+
448+
// Additional sync point for GPU driver
449+
m_pDevice->BeginScene();
450+
m_pDevice->EndScene();
413451

414452
WriteDebugEvent(SString(" BackBufferWidth:%d Height:%d Format:%d Count:%d", pPresentationParameters->BackBufferWidth,
415453
pPresentationParameters->BackBufferHeight, pPresentationParameters->BackBufferFormat, pPresentationParameters->BackBufferCount));

Client/core/Graphics/CGraphics.cpp

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1515,10 +1515,11 @@ void CGraphics::DrawTexture(CTextureItem* pTexture, float fX, float fY, float fS
15151515
D3DXVECTOR2 scaling(fScaleX * fFileWidth / fCutWidth, fScaleY * fFileHeight / fCutHeight);
15161516
D3DXVECTOR2 rotationCenter(fFileWidth * fScaleX * fCenterX, fFileHeight * fScaleX * fCenterY);
15171517
D3DXVECTOR2 position(fX - fFileWidth * fScaleX * fCenterX, fY - fFileHeight * fScaleY * fCenterY);
1518-
D3DXMatrixTransformation2D(&matrix, NULL, NULL, &scaling, &rotationCenter, DegreesToRadians(fRotation), &position);
1518+
const D3DXVECTOR2* pRotationCenter = fRotation != 0.0f ? &rotationCenter : NULL;
1519+
D3DXMatrixTransformation2D(&matrix, NULL, NULL, &scaling, pRotationCenter, DegreesToRadians(fRotation), &position);
15191520
CheckModes(EDrawMode::DX_SPRITE, m_ActiveBlendMode);
15201521
m_pDXSprite->SetTransform(&matrix);
1521-
m_pDXSprite->Draw((IDirect3DTexture9*)pTexture->m_pD3DTexture, &cutImagePos, NULL, NULL, /*ModifyColorForBlendMode (*/ dwColor /*, blendMode )*/);
1522+
m_pDXSprite->Draw((IDirect3DTexture9*)pTexture->m_pD3DTexture, &cutImagePos, NULL, NULL, dwColor);
15221523
EndDrawBatch();
15231524
}
15241525

@@ -1763,7 +1764,7 @@ void CGraphics::DrawQueueItem(const sDrawQueueItem& Item)
17631764
D3DXVECTOR2 scaling(Item.Text.fScaleX, Item.Text.fScaleY);
17641765
D3DXVECTOR2 translation(fPosFracX * Item.Text.fScaleX, fPosFracY * Item.Text.fScaleY); // Sub-pixel positioning
17651766
D3DXVECTOR2 rotcenter(Item.Text.fRotationCenterX, Item.Text.fRotationCenterY);
1766-
D3DXVECTOR2* pRotcenter = Item.Text.fRotation ? &rotcenter : NULL;
1767+
const D3DXVECTOR2* pRotcenter = Item.Text.fRotation != 0.0f ? &rotcenter : NULL;
17671768
D3DXMatrixTransformation2D(&matrix, NULL, 0.0f, &scaling, pRotcenter, DegreesToRadians(Item.Text.fRotation), &translation);
17681769
CheckModes(EDrawMode::DX_SPRITE, Item.blendMode);
17691770
m_pDXSprite->SetTransform(&matrix);
@@ -1789,7 +1790,7 @@ void CGraphics::DrawQueueItem(const sDrawQueueItem& Item)
17891790
const float fCutWidth = cutImagePos.right - cutImagePos.left;
17901791
const float fCutHeight = cutImagePos.bottom - cutImagePos.top;
17911792
const D3DXVECTOR2 scaling(Item.Texture.fWidth / fCutWidth, Item.Texture.fHeight / fCutHeight);
1792-
const D3DXVECTOR2 rotationCenter(Item.Texture.fWidth * 0.5f + Item.Texture.fRotCenOffX, Item.Texture.fHeight * 0.5f + Item.Texture.fRotCenOffY);
1793+
const D3DXVECTOR2 rotationCenter(fFileWidth * 0.5f + Item.Texture.fRotCenOffX, fFileHeight * 0.5f + Item.Texture.fRotCenOffY);
17931794
const D3DXVECTOR2 position(Item.Texture.fX, Item.Texture.fY);
17941795
const D3DXVECTOR2* pRotationCenter = Item.Texture.fRotation ? &rotationCenter : NULL;
17951796
D3DXMATRIX matrix;
@@ -2003,9 +2004,23 @@ void CGraphics::MaybeLeavingMTARenderZone()
20032004
////////////////////////////////////////////////////////////////
20042005
void CGraphics::SaveGTARenderStates()
20052006
{
2007+
// Prevent GPU driver hang by checking device state before creating state blocks
2008+
if (m_pDevice->TestCooperativeLevel() != D3D_OK)
2009+
{
2010+
WriteDebugEvent("CGraphics::SaveGTARenderStates - Device not cooperative, skipping state block creation");
2011+
return;
2012+
}
2013+
20062014
SAFE_RELEASE(m_pSavedStateBlock);
2007-
// Create a state block.
2008-
m_pDevice->CreateStateBlock(D3DSBT_ALL, &m_pSavedStateBlock);
2015+
2016+
// Add error handling for state block creation
2017+
HRESULT hr = m_pDevice->CreateStateBlock(D3DSBT_ALL, &m_pSavedStateBlock);
2018+
if (FAILED(hr))
2019+
{
2020+
WriteDebugEvent(SString("CGraphics::SaveGTARenderStates - Failed to create state block: %08x", hr));
2021+
m_pSavedStateBlock = nullptr;
2022+
return;
2023+
}
20092024

20102025
// Make sure linear sampling is enabled
20112026
m_pDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
@@ -2025,6 +2040,14 @@ void CGraphics::SaveGTARenderStates()
20252040
////////////////////////////////////////////////////////////////
20262041
void CGraphics::RestoreGTARenderStates()
20272042
{
2043+
// Check device state before attempting to restore
2044+
if (m_pDevice->TestCooperativeLevel() != D3D_OK)
2045+
{
2046+
WriteDebugEvent("CGraphics::RestoreGTARenderStates - Device not cooperative, skipping state restoration");
2047+
SAFE_RELEASE(m_pSavedStateBlock);
2048+
return;
2049+
}
2050+
20282051
// Restore these transforms to fix various weird stuff
20292052
m_pDevice->SetTransform(D3DTS_PROJECTION, &g_pDeviceState->TransformState.PROJECTION);
20302053
m_pDevice->SetTransform(D3DTS_WORLD, &g_pDeviceState->TransformState.WORLD);
@@ -2033,7 +2056,12 @@ void CGraphics::RestoreGTARenderStates()
20332056
// Restore the render states
20342057
if (m_pSavedStateBlock)
20352058
{
2036-
m_pSavedStateBlock->Apply();
2059+
// Error handling for state block apply
2060+
HRESULT hr = m_pSavedStateBlock->Apply();
2061+
if (FAILED(hr))
2062+
{
2063+
WriteDebugEvent(SString("RestoreGTARenderStates: Failed to apply state block: %08x", hr));
2064+
}
20372065
SAFE_RELEASE(m_pSavedStateBlock);
20382066
}
20392067
}

Client/core/Graphics/CRenderItemManager.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,6 +1181,19 @@ void CRenderItemManager::SaveReadableDepthBuffer()
11811181
{
11821182
m_bUsingReadableDepthBuffer = false;
11831183

1184+
// Ensure device operations are synchronous for GPU driver (especially Nvidia) compatibility
1185+
IDirect3DSurface9* pCurrentDepthSurface = nullptr;
1186+
if (SUCCEEDED(m_pDevice->GetDepthStencilSurface(&pCurrentDepthSurface)))
1187+
{
1188+
// Force GPU to complete any pending depth buffer operations
1189+
D3DLOCKED_RECT lockedRect;
1190+
if (SUCCEEDED(pCurrentDepthSurface->LockRect(&lockedRect, nullptr, D3DLOCK_READONLY | D3DLOCK_DONOTWAIT)))
1191+
{
1192+
pCurrentDepthSurface->UnlockRect();
1193+
}
1194+
SAFE_RELEASE(pCurrentDepthSurface);
1195+
}
1196+
11841197
if (m_pNonAADepthSurface2)
11851198
{
11861199
// If using AA hacks, change to the other depth buffer we created
@@ -1196,6 +1209,11 @@ void CRenderItemManager::SaveReadableDepthBuffer()
11961209
SAFE_RELEASE(m_pSavedSceneDepthSurface);
11971210
}
11981211
}
1212+
1213+
// Additional sync point for GPU driver
1214+
// Force immediate execution of depth buffer state changes
1215+
m_pDevice->BeginScene();
1216+
m_pDevice->EndScene();
11991217
}
12001218
}
12011219

0 commit comments

Comments
 (0)