Skip to content

Commit b162464

Browse files
committed
GPU driver handling tweaks that will improve stability for users affected by a range of graphics device-related issues
It includes: - Better device state validation - Added device state checking with TestCooperativeLevel() before creating state blocks - Added error handling and device state validation before restoring render states - Early exit on device calls if device already lost (Avoids dangerous operations like calling to invalidate a device that's already so, due to Alt-Tab) - Ensure completion of GPU operations before invalidation - Properly flushes depth buffers and render targets before invalidation - Improve SaveReadableDepthBuffer in CRenderItemManager.cpp - Added critical sync points for Nvidia compatibility - Added safe depth buffer locking with D3DLOCK_READONLY | D3DLOCK_DONOTWAIT - OnInvalidate fixes in CDirect3DEvents9.cpp I want to specifically target the notorious Nvidia Alt+Tab freeze (Desktop lock-up) issue that affects players with Nvidia graphics cards. 1. Alt+Tabbing during gameplay would cause the DirectX device to lose and restore state 2. Nvidia drivers would hang during state block operations if the device was in an invalid state GPU synchronization issues during depth buffer operations can cause indefinite hangs or suspended waits. We now have: - Safe device state validation before any critical DirectX operations - Proper GPU synchronization during device transitions - Graceful handling of device loss states - Relevant debug logging
1 parent 7eb8700 commit b162464

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)