Skip to content

Commit e556d42

Browse files
committed
Further reduce the likelihood of alt-tab freezes (Not fully eliminated yet)
1 parent 24e9e4f commit e556d42

7 files changed

+101
-48
lines changed

Client/core/CAdditionalVertexStreamManager.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -290,15 +290,21 @@ void CAdditionalVertexStreamManager::MaybeUnsetAdditionalVertexStream()
290290
if (!m_pDevice)
291291
return;
292292

293-
HRESULT hr;
294293
if (m_pOldVertexDeclaration)
295294
{
296-
// Set prev declaration
297-
hr = g_pProxyDevice->SetVertexDeclaration(m_pOldVertexDeclaration);
298-
SAFE_RELEASE(m_pOldVertexDeclaration);
295+
HRESULT hr = m_pDevice->TestCooperativeLevel();
296+
const bool bDeviceOperational = (hr == D3D_OK);
297+
298+
if (bDeviceOperational)
299+
{
300+
// Set prev declaration
301+
g_pProxyDevice->SetVertexDeclaration(m_pOldVertexDeclaration);
299302

300-
// Unset additional stream
301-
hr = m_pDevice->SetStreamSource(2, nullptr, 0, 0);
303+
// Unset additional stream
304+
m_pDevice->SetStreamSource(2, nullptr, 0, 0);
305+
}
306+
307+
SAFE_RELEASE(m_pOldVertexDeclaration);
302308
}
303309
}
304310

Client/core/DXHook/CDirect3DEvents9.cpp

Lines changed: 58 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -80,33 +80,41 @@ void CDirect3DEvents9::OnInvalidate(IDirect3DDevice9* pDevice)
8080
{
8181
WriteDebugEvent("CDirect3DEvents9::OnInvalidate");
8282

83-
// Ensure device is in a valid state before invalidation
84-
// For example, Nvidia drivers can hang if device operations are attempted during invalid states
85-
if (pDevice->TestCooperativeLevel() == D3DERR_DEVICELOST)
86-
{
87-
WriteDebugEvent("OnInvalidate: Device already lost, skipping operations");
88-
return;
89-
}
83+
const HRESULT hrCooperativeLevel = pDevice->TestCooperativeLevel();
84+
const bool bDeviceOperational = (hrCooperativeLevel == D3D_OK);
85+
const bool bDeviceTemporarilyLost =
86+
(hrCooperativeLevel == D3DERR_DEVICELOST || hrCooperativeLevel == D3DERR_DEVICENOTRESET);
9087

91-
// Flush any pending operations before invalidation
92-
g_pCore->GetGraphics()->GetRenderItemManager()->SaveReadableDepthBuffer();
93-
g_pCore->GetGraphics()->GetRenderItemManager()->FlushNonAARenderTarget();
94-
95-
// Force completion of all GPU operations if a scene is currently active
96-
if (g_bInMTAScene || g_bInGTAScene)
88+
if (!bDeviceOperational && !bDeviceTemporarilyLost)
89+
WriteDebugEvent(SString("OnInvalidate: unexpected cooperative level %08x", hrCooperativeLevel));
90+
91+
if (bDeviceOperational)
9792
{
98-
const HRESULT hrEndScene = pDevice->EndScene();
99-
if (SUCCEEDED(hrEndScene))
100-
{
101-
g_bInMTAScene = false;
102-
g_bInGTAScene = false;
103-
}
104-
else
93+
// Flush any pending operations before invalidation while the device still accepts work
94+
g_pCore->GetGraphics()->GetRenderItemManager()->SaveReadableDepthBuffer();
95+
g_pCore->GetGraphics()->GetRenderItemManager()->FlushNonAARenderTarget();
96+
97+
if (g_bInMTAScene || g_bInGTAScene)
10598
{
106-
WriteDebugEvent(SString("OnInvalidate: EndScene failed: %08x", hrEndScene));
99+
const HRESULT hrEndScene = pDevice->EndScene();
100+
if (FAILED(hrEndScene))
101+
WriteDebugEvent(SString("OnInvalidate: EndScene failed: %08x", hrEndScene));
107102
}
103+
104+
CloseActiveShader();
105+
}
106+
else
107+
{
108+
if (g_bInMTAScene || g_bInGTAScene)
109+
WriteDebugEvent("OnInvalidate: device lost, skipping EndScene and pending GPU work");
110+
111+
// Prevent reuse of partially configured shader state across device resets without touching the lost device
112+
CloseActiveShader(false);
108113
}
109-
114+
115+
g_bInMTAScene = false;
116+
g_bInGTAScene = false;
117+
110118
// Invalidate the VMR9 Manager
111119
// CVideoManager::GetSingleton ().OnLostDevice ();
112120

@@ -591,26 +599,43 @@ HRESULT CDirect3DEvents9::DrawIndexedPrimitiveShader(IDirect3DDevice9* pDevice,
591599
// Finish the active shader if there is one
592600
//
593601
/////////////////////////////////////////////////////////////
594-
void CDirect3DEvents9::CloseActiveShader()
602+
void CDirect3DEvents9::CloseActiveShader(bool bDeviceOperational)
595603
{
596604
if (!g_pActiveShader)
597605
return;
598606

599607
ID3DXEffect* pD3DEffect = g_pActiveShader->m_pShaderInstance->m_pEffectWrap->m_pD3DEffect;
608+
IDirect3DDevice9* pDevice = g_pGraphics ? g_pGraphics->GetDevice() : nullptr;
609+
HRESULT hrCooperativeLevel = D3D_OK;
610+
if (pDevice)
611+
hrCooperativeLevel = pDevice->TestCooperativeLevel();
612+
613+
bool bAllowDeviceWork = bDeviceOperational;
614+
if (hrCooperativeLevel == D3D_OK)
615+
bAllowDeviceWork = true;
616+
else if (hrCooperativeLevel == D3DERR_DEVICELOST || hrCooperativeLevel == D3DERR_DEVICENOTRESET)
617+
bAllowDeviceWork = false;
618+
619+
if (pD3DEffect)
620+
{
621+
HRESULT hrEndPass = pD3DEffect->EndPass();
622+
if (FAILED(hrEndPass) && hrEndPass != D3DERR_DEVICELOST && hrEndPass != D3DERR_DEVICENOTRESET)
623+
WriteDebugEvent(SString("CloseActiveShader: EndPass failed: %08x", hrEndPass));
624+
}
600625

601-
pD3DEffect->EndPass();
602-
603-
g_pActiveShader->m_pShaderInstance->m_pEffectWrap->End();
604-
g_pActiveShader = NULL;
605-
606-
// We didn't get the effect to save the shader state, clear some things here
607-
IDirect3DDevice9* pDevice = g_pGraphics->GetDevice();
608-
pDevice->SetVertexShader(NULL);
609-
pDevice->SetPixelShader(NULL);
626+
// When the device is lost we intentionally skip touching the GPU beyond the required End call; the effect will be reset later.
627+
g_pActiveShader->m_pShaderInstance->m_pEffectWrap->End(bAllowDeviceWork);
628+
g_pActiveShader = nullptr;
610629

611-
// Unset additional vertex stream
612630
if (CAdditionalVertexStreamManager* pAdditionalStreamManager = CAdditionalVertexStreamManager::GetExistingSingleton())
613631
pAdditionalStreamManager->MaybeUnsetAdditionalVertexStream();
632+
633+
if (bAllowDeviceWork && pDevice)
634+
{
635+
// We didn't get the effect to save the shader state, clear some things here
636+
pDevice->SetVertexShader(nullptr);
637+
pDevice->SetPixelShader(nullptr);
638+
}
614639
}
615640

616641
/////////////////////////////////////////////////////////////

Client/core/DXHook/CDirect3DEvents9.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class CDirect3DEvents9
4545
static HRESULT SetVertexDeclaration(IDirect3DDevice9* pDevice, IDirect3DVertexDeclaration9* pDecl);
4646
static void CheckForScreenShot();
4747
static ERenderFormat DiscoverReadableDepthFormat(IDirect3DDevice9* pDevice, D3DMULTISAMPLE_TYPE multisampleType, bool bWindowed);
48-
static void CloseActiveShader();
48+
static void CloseActiveShader(bool bDeviceOperational = true);
4949

5050
static IDirect3DVertexBuffer9* GetRealVertexBuffer(IDirect3DVertexBuffer9* pVertexBuffer);
5151
static IDirect3DIndexBuffer9* GetRealIndexBuffer(IDirect3DIndexBuffer9* pIndexBuffer);

Client/core/Graphics/CRenderItem.EffectParameters.cpp

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -397,15 +397,37 @@ HRESULT CEffectParameters::Begin(UINT* pPasses, DWORD Flags, bool bWorldRender)
397397
// Ensures secondary render targets are unset
398398
//
399399
////////////////////////////////////////////////////////////////
400-
HRESULT CEffectParameters::End()
400+
HRESULT CEffectParameters::End(bool bDeviceOperational)
401401
{
402+
if (!m_pD3DEffect)
403+
return D3D_OK;
404+
402405
HRESULT hResult = m_pD3DEffect->End();
403-
for (uint i = 0; i < m_SecondaryRenderTargetList.size(); i++)
406+
407+
if (!m_SecondaryRenderTargetList.empty())
404408
{
405-
LPDIRECT3DDEVICE9 pDevice;
409+
LPDIRECT3DDEVICE9 pDevice = nullptr;
406410
m_pD3DEffect->GetDevice(&pDevice);
407-
pDevice->SetRenderTarget(i + 1, NULL);
411+
412+
if (pDevice)
413+
{
414+
bool bCanTouchDevice = bDeviceOperational;
415+
if (!bCanTouchDevice)
416+
{
417+
const HRESULT hrCooperativeLevel = pDevice->TestCooperativeLevel();
418+
bCanTouchDevice = (hrCooperativeLevel == D3D_OK);
419+
}
420+
421+
if (bCanTouchDevice)
422+
{
423+
for (uint i = 0; i < m_SecondaryRenderTargetList.size(); i++)
424+
pDevice->SetRenderTarget(i + 1, nullptr);
425+
}
426+
427+
SAFE_RELEASE(pDevice);
428+
}
408429
}
430+
409431
return hResult;
410432
}
411433

Client/core/Graphics/CRenderItem.EffectParameters.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ class CEffectParameters : public CRenderItem
9595
bool ApplyCommonHandles();
9696
bool ApplyMappedHandles();
9797
HRESULT Begin(UINT* pPasses, DWORD Flags, bool bWorldRender = true);
98-
HRESULT End();
98+
HRESULT End(bool bDeviceOperational = true);
9999
void NotifyModifiedParameter(D3DXHANDLE hParameter);
100100
const std::set<D3DXHANDLE>& GetModifiedParameters();
101101
void RestoreParametersDefaultValue(const std::vector<D3DXHANDLE>& parameterList);

Client/core/Graphics/CRenderItem.EffectWrap.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,9 @@ HRESULT CEffectWrap::Begin(UINT* pPasses, DWORD Flags, bool bWorldRender)
9595
// Ensures secondary render targets are unset
9696
//
9797
////////////////////////////////////////////////////////////////
98-
HRESULT CEffectWrap::End()
98+
HRESULT CEffectWrap::End(bool bDeviceOperational)
9999
{
100-
return m_pEffectTemplate->End();
100+
return m_pEffectTemplate->End(bDeviceOperational);
101101
}
102102

103103
////////////////////////////////////////////////////////////////

Client/sdk/core/CRenderItemManagerInterface.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ class CEffectWrap : public CRenderItem
332332
virtual void OnLostDevice();
333333
virtual void OnResetDevice();
334334
HRESULT Begin(UINT* pPasses, DWORD Flags, bool bWorldRender = true);
335-
HRESULT End();
335+
HRESULT End(bool bDeviceOperational = true);
336336
bool ApplyCommonHandles();
337337
bool ApplyMappedHandles();
338338

0 commit comments

Comments
 (0)