Skip to content

Commit 309bfab

Browse files
committed
Addendum #2 to e556d42
1 parent e58cd39 commit 309bfab

File tree

2 files changed

+234
-41
lines changed

2 files changed

+234
-41
lines changed

Client/core/DXHook/CDirect3DEvents9.cpp

Lines changed: 203 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,34 @@ static EDiagnosticDebugType ms_DiagnosticDebug = EDiagnosticDebug::NONE;
3131
// To reuse shader setups between calls to DrawIndexedPrimitive
3232
CShaderItem* g_pActiveShader = NULL;
3333

34+
namespace
35+
{
36+
bool IsDeviceOperational(IDirect3DDevice9* pDevice, bool* pbTemporarilyLost = nullptr)
37+
{
38+
if (pbTemporarilyLost)
39+
*pbTemporarilyLost = false;
40+
41+
if (!pDevice)
42+
return false;
43+
44+
const HRESULT hr = pDevice->TestCooperativeLevel();
45+
if (hr == D3D_OK)
46+
return true;
47+
48+
if (hr == D3DERR_DEVICELOST || hr == D3DERR_DEVICENOTRESET)
49+
{
50+
if (pbTemporarilyLost)
51+
*pbTemporarilyLost = true;
52+
}
53+
else
54+
{
55+
WriteDebugEvent(SString("IsDeviceOperational: unexpected cooperative level %08x", hr));
56+
}
57+
58+
return false;
59+
}
60+
}
61+
3462
void CDirect3DEvents9::OnDirect3DDeviceCreate(IDirect3DDevice9* pDevice)
3563
{
3664
WriteDebugEvent("CDirect3DEvents9::OnDirect3DDeviceCreate");
@@ -358,23 +386,79 @@ HRESULT CDirect3DEvents9::DrawPrimitiveShader(IDirect3DDevice9* pDevice, D3DPRIM
358386

359387
// Do shader passes
360388
ID3DXEffect* pD3DEffect = pShaderInstance->m_pEffectWrap->m_pD3DEffect;
389+
bool bEffectDeviceTemporarilyLost = false;
390+
bool bEffectDeviceOperational = true;
391+
if (pD3DEffect)
392+
{
393+
IDirect3DDevice9* pEffectDevice = nullptr;
394+
if (SUCCEEDED(pD3DEffect->GetDevice(&pEffectDevice)) && pEffectDevice)
395+
{
396+
bEffectDeviceOperational = IsDeviceOperational(pEffectDevice, &bEffectDeviceTemporarilyLost);
397+
SAFE_RELEASE(pEffectDevice);
398+
}
399+
}
400+
401+
if (!bEffectDeviceOperational)
402+
{
403+
SAFE_RELEASE(pOriginalVertexShader);
404+
if (!bIsLayer && !bEffectDeviceTemporarilyLost)
405+
return DrawPrimitiveGuarded(pDevice, PrimitiveType, StartVertex, PrimitiveCount);
406+
return D3D_OK;
407+
}
361408

362409
DWORD dwFlags = D3DXFX_DONOTSAVESHADERSTATE; // D3DXFX_DONOTSAVE(SHADER|SAMPLER)STATE
363410
uint uiNumPasses = 0;
364-
pShaderInstance->m_pEffectWrap->Begin(&uiNumPasses, dwFlags);
411+
HRESULT hrBegin = pShaderInstance->m_pEffectWrap->Begin(&uiNumPasses, dwFlags);
412+
if (FAILED(hrBegin) || uiNumPasses == 0)
413+
{
414+
if (FAILED(hrBegin) && hrBegin != D3DERR_DEVICELOST && hrBegin != D3DERR_DEVICENOTRESET)
415+
WriteDebugEvent(SString("DrawPrimitiveShader: Begin failed %08x", hrBegin));
416+
417+
SAFE_RELEASE(pOriginalVertexShader);
418+
if (!bIsLayer && hrBegin != D3DERR_DEVICELOST && hrBegin != D3DERR_DEVICENOTRESET)
419+
return DrawPrimitiveGuarded(pDevice, PrimitiveType, StartVertex, PrimitiveCount);
420+
return D3D_OK;
421+
}
365422

423+
bool bCompletedAnyPass = false;
424+
bool bEncounteredDeviceLoss = false;
366425
for (uint uiPass = 0; uiPass < uiNumPasses; uiPass++)
367426
{
368-
pD3DEffect->BeginPass(uiPass);
427+
HRESULT hrBeginPass = pD3DEffect->BeginPass(uiPass);
428+
if (FAILED(hrBeginPass))
429+
{
430+
if (hrBeginPass != D3DERR_DEVICELOST && hrBeginPass != D3DERR_DEVICENOTRESET)
431+
WriteDebugEvent(SString("DrawPrimitiveShader: BeginPass %u failed %08x", uiPass, hrBeginPass));
432+
else
433+
bEncounteredDeviceLoss = true;
434+
break;
435+
}
369436

370437
// Apply original vertex shader if original draw was using it (i.e. for ped animation)
371438
if (pOriginalVertexShader)
372439
pDevice->SetVertexShader(pOriginalVertexShader);
373440

374-
DrawPrimitiveGuarded(pDevice, PrimitiveType, StartVertex, PrimitiveCount);
375-
pD3DEffect->EndPass();
441+
HRESULT hrDraw = DrawPrimitiveGuarded(pDevice, PrimitiveType, StartVertex, PrimitiveCount);
442+
if (hrDraw == D3DERR_DEVICELOST || hrDraw == D3DERR_DEVICENOTRESET)
443+
bEncounteredDeviceLoss = true;
444+
445+
HRESULT hrEndPass = pD3DEffect->EndPass();
446+
if (FAILED(hrEndPass))
447+
{
448+
if (hrEndPass != D3DERR_DEVICELOST && hrEndPass != D3DERR_DEVICENOTRESET)
449+
WriteDebugEvent(SString("DrawPrimitiveShader: EndPass %u failed %08x", uiPass, hrEndPass));
450+
else
451+
bEncounteredDeviceLoss = true;
452+
break;
453+
}
454+
455+
if (SUCCEEDED(hrDraw))
456+
bCompletedAnyPass = true;
376457
}
377-
pShaderInstance->m_pEffectWrap->End();
458+
459+
HRESULT hrEnd = pShaderInstance->m_pEffectWrap->End(bEffectDeviceOperational && !bEncounteredDeviceLoss);
460+
if (FAILED(hrEnd) && hrEnd != D3DERR_DEVICELOST && hrEnd != D3DERR_DEVICENOTRESET)
461+
WriteDebugEvent(SString("DrawPrimitiveShader: End failed %08x", hrEnd));
378462

379463
// If we didn't get the effect to save the shader state, clear some things here
380464
if (dwFlags & D3DXFX_DONOTSAVESHADERSTATE)
@@ -384,6 +468,9 @@ HRESULT CDirect3DEvents9::DrawPrimitiveShader(IDirect3DDevice9* pDevice, D3DPRIM
384468
}
385469

386470
SAFE_RELEASE(pOriginalVertexShader);
471+
472+
if (!bCompletedAnyPass && !bIsLayer && !bEncounteredDeviceLoss)
473+
return DrawPrimitiveGuarded(pDevice, PrimitiveType, StartVertex, PrimitiveCount);
387474
}
388475

389476
return D3D_OK;
@@ -513,12 +600,41 @@ HRESULT CDirect3DEvents9::DrawIndexedPrimitiveShader(IDirect3DDevice9* pDevice,
513600
dassert(pShaderItem == g_pActiveShader);
514601
g_pDeviceState->FrameStats.iNumShadersReuseSetup++;
515602

516-
// Transfer any state changes to the active shader
603+
// Transfer any state changes to the active shader, but ensure the device still accepts work
517604
CShaderInstance* pShaderInstance = g_pActiveShader->m_pShaderInstance;
518-
bool bChanged = pShaderInstance->m_pEffectWrap->ApplyCommonHandles();
605+
ID3DXEffect* pActiveEffect = pShaderInstance->m_pEffectWrap->m_pD3DEffect;
606+
607+
bool bDeviceTemporarilyLost = false;
608+
bool bDeviceOperational = true;
609+
if (pActiveEffect)
610+
{
611+
IDirect3DDevice9* pEffectDevice = nullptr;
612+
if (SUCCEEDED(pActiveEffect->GetDevice(&pEffectDevice)) && pEffectDevice)
613+
{
614+
bDeviceOperational = IsDeviceOperational(pEffectDevice, &bDeviceTemporarilyLost);
615+
SAFE_RELEASE(pEffectDevice);
616+
}
617+
}
618+
619+
if (!bDeviceOperational)
620+
{
621+
CloseActiveShader(false);
622+
return D3D_OK;
623+
}
624+
625+
bool bChanged = pShaderInstance->m_pEffectWrap->ApplyCommonHandles();
519626
bChanged |= pShaderInstance->m_pEffectWrap->ApplyMappedHandles();
520627
if (bChanged)
521-
pShaderInstance->m_pEffectWrap->m_pD3DEffect->CommitChanges();
628+
{
629+
HRESULT hrCommit = pShaderInstance->m_pEffectWrap->m_pD3DEffect->CommitChanges();
630+
if (FAILED(hrCommit))
631+
{
632+
if (hrCommit != D3DERR_DEVICELOST && hrCommit != D3DERR_DEVICENOTRESET)
633+
WriteDebugEvent(SString("DrawIndexedPrimitiveShader: CommitChanges failed %08x", hrCommit));
634+
CloseActiveShader(false);
635+
return D3D_OK;
636+
}
637+
}
522638

523639
return DrawIndexedPrimitiveGuarded(pDevice, PrimitiveType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
524640
}
@@ -528,14 +644,11 @@ HRESULT CDirect3DEvents9::DrawIndexedPrimitiveShader(IDirect3DDevice9* pDevice,
528644
CShaderInstance* pShaderInstance = pShaderItem->m_pShaderInstance;
529645

530646
// Add normal stream if shader wants it
531-
if (pShaderInstance->m_pEffectWrap->m_pEffectTemplate->m_bRequiresNormals)
647+
CAdditionalVertexStreamManager* pAdditionalStreamManager = CAdditionalVertexStreamManager::GetExistingSingleton();
648+
if (pShaderInstance->m_pEffectWrap->m_pEffectTemplate->m_bRequiresNormals && pAdditionalStreamManager)
532649
{
533650
// Find/create/set additional vertex stream
534-
if (CAdditionalVertexStreamManager* pAdditionalStreamManager = CAdditionalVertexStreamManager::GetExistingSingleton())
535-
{
536-
pAdditionalStreamManager->MaybeSetAdditionalVertexStream(PrimitiveType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex,
537-
primCount);
538-
}
651+
pAdditionalStreamManager->MaybeSetAdditionalVertexStream(PrimitiveType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
539652
}
540653

541654
// Apply custom parameters
@@ -551,22 +664,68 @@ HRESULT CDirect3DEvents9::DrawIndexedPrimitiveShader(IDirect3DDevice9* pDevice,
551664

552665
// Do shader passes
553666
ID3DXEffect* pD3DEffect = pShaderInstance->m_pEffectWrap->m_pD3DEffect;
667+
bool bEffectDeviceTemporarilyLost = false;
668+
bool bEffectDeviceOperational = true;
669+
if (pD3DEffect)
670+
{
671+
IDirect3DDevice9* pEffectDevice = nullptr;
672+
if (SUCCEEDED(pD3DEffect->GetDevice(&pEffectDevice)) && pEffectDevice)
673+
{
674+
bEffectDeviceOperational = IsDeviceOperational(pEffectDevice, &bEffectDeviceTemporarilyLost);
675+
SAFE_RELEASE(pEffectDevice);
676+
}
677+
}
678+
679+
if (!bEffectDeviceOperational)
680+
{
681+
SAFE_RELEASE(pOriginalVertexShader);
682+
if (pAdditionalStreamManager)
683+
pAdditionalStreamManager->MaybeUnsetAdditionalVertexStream();
684+
if (!bEffectDeviceTemporarilyLost && !bIsLayer)
685+
return DrawIndexedPrimitiveGuarded(pDevice, PrimitiveType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
686+
return D3D_OK;
687+
}
554688

555689
DWORD dwFlags = D3DXFX_DONOTSAVESHADERSTATE; // D3DXFX_DONOTSAVE(SHADER|SAMPLER)STATE
556690
uint uiNumPasses = 0;
557-
pShaderInstance->m_pEffectWrap->Begin(&uiNumPasses, dwFlags);
691+
HRESULT hrBegin = pShaderInstance->m_pEffectWrap->Begin(&uiNumPasses, dwFlags);
692+
if (FAILED(hrBegin) || uiNumPasses == 0)
693+
{
694+
if (FAILED(hrBegin) && hrBegin != D3DERR_DEVICELOST && hrBegin != D3DERR_DEVICENOTRESET)
695+
WriteDebugEvent(SString("DrawIndexedPrimitiveShader: Begin failed %08x", hrBegin));
558696

697+
SAFE_RELEASE(pOriginalVertexShader);
698+
if (pAdditionalStreamManager)
699+
pAdditionalStreamManager->MaybeUnsetAdditionalVertexStream();
700+
701+
if (hrBegin != D3DERR_DEVICELOST && hrBegin != D3DERR_DEVICENOTRESET && !bIsLayer)
702+
return DrawIndexedPrimitiveGuarded(pDevice, PrimitiveType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
703+
return D3D_OK;
704+
}
705+
706+
bool bCompletedAnyPass = false;
707+
bool bEncounteredDeviceLoss = false;
559708
for (uint uiPass = 0; uiPass < uiNumPasses; uiPass++)
560709
{
561-
pD3DEffect->BeginPass(uiPass);
710+
HRESULT hrBeginPass = pD3DEffect->BeginPass(uiPass);
711+
if (FAILED(hrBeginPass))
712+
{
713+
if (hrBeginPass != D3DERR_DEVICELOST && hrBeginPass != D3DERR_DEVICENOTRESET)
714+
WriteDebugEvent(SString("DrawIndexedPrimitiveShader: BeginPass %u failed %08x", uiPass, hrBeginPass));
715+
else
716+
bEncounteredDeviceLoss = true;
717+
break;
718+
}
562719

563720
// Apply original vertex shader if original draw was using it (i.e. for ped animation)
564721
if (pOriginalVertexShader)
565722
pDevice->SetVertexShader(pOriginalVertexShader);
566723

567-
DrawIndexedPrimitiveGuarded(pDevice, PrimitiveType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
724+
HRESULT hrDraw = DrawIndexedPrimitiveGuarded(pDevice, PrimitiveType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
725+
if (hrDraw == D3DERR_DEVICELOST || hrDraw == D3DERR_DEVICENOTRESET)
726+
bEncounteredDeviceLoss = true;
568727

569-
if (uiNumPasses == 1 && bCanBecomeActiveShader && pOriginalVertexShader == NULL && g_pCore->IsRenderingGrass())
728+
if (uiNumPasses == 1 && bCanBecomeActiveShader && pOriginalVertexShader == NULL && g_pCore->IsRenderingGrass() && SUCCEEDED(hrDraw))
570729
{
571730
// Make this the active shader for possible reuse
572731
dassert(dwFlags == D3DXFX_DONOTSAVESHADERSTATE);
@@ -575,9 +734,23 @@ HRESULT CDirect3DEvents9::DrawIndexedPrimitiveShader(IDirect3DDevice9* pDevice,
575734
return D3D_OK;
576735
}
577736

578-
pD3DEffect->EndPass();
737+
HRESULT hrEndPass = pD3DEffect->EndPass();
738+
if (FAILED(hrEndPass))
739+
{
740+
if (hrEndPass != D3DERR_DEVICELOST && hrEndPass != D3DERR_DEVICENOTRESET)
741+
WriteDebugEvent(SString("DrawIndexedPrimitiveShader: EndPass %u failed %08x", uiPass, hrEndPass));
742+
else
743+
bEncounteredDeviceLoss = true;
744+
break;
745+
}
746+
747+
if (SUCCEEDED(hrDraw))
748+
bCompletedAnyPass = true;
579749
}
580-
pShaderInstance->m_pEffectWrap->End();
750+
751+
HRESULT hrEnd = pShaderInstance->m_pEffectWrap->End(bEffectDeviceOperational && !bEncounteredDeviceLoss);
752+
if (FAILED(hrEnd) && hrEnd != D3DERR_DEVICELOST && hrEnd != D3DERR_DEVICENOTRESET)
753+
WriteDebugEvent(SString("DrawIndexedPrimitiveShader: End failed %08x", hrEnd));
581754

582755
// If we didn't get the effect to save the shader state, clear some things here
583756
if (dwFlags & D3DXFX_DONOTSAVESHADERSTATE)
@@ -587,10 +760,13 @@ HRESULT CDirect3DEvents9::DrawIndexedPrimitiveShader(IDirect3DDevice9* pDevice,
587760
}
588761

589762
// Unset additional vertex stream
590-
if (CAdditionalVertexStreamManager* pAdditionalStreamManager = CAdditionalVertexStreamManager::GetExistingSingleton())
763+
if (pAdditionalStreamManager)
591764
pAdditionalStreamManager->MaybeUnsetAdditionalVertexStream();
592765

593766
SAFE_RELEASE(pOriginalVertexShader);
767+
768+
if (!bCompletedAnyPass && !bEncounteredDeviceLoss && !bIsLayer)
769+
return DrawIndexedPrimitiveGuarded(pDevice, PrimitiveType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
594770
}
595771

596772
return D3D_OK;
@@ -610,15 +786,14 @@ void CDirect3DEvents9::CloseActiveShader(bool bDeviceOperational)
610786

611787
ID3DXEffect* pD3DEffect = g_pActiveShader->m_pShaderInstance->m_pEffectWrap->m_pD3DEffect;
612788
IDirect3DDevice9* pDevice = g_pGraphics ? g_pGraphics->GetDevice() : nullptr;
613-
HRESULT hrCooperativeLevel = D3D_OK;
614-
if (pDevice)
615-
hrCooperativeLevel = pDevice->TestCooperativeLevel();
616789

617790
bool bAllowDeviceWork = bDeviceOperational;
618-
if (hrCooperativeLevel == D3D_OK)
619-
bAllowDeviceWork = true;
620-
else if (hrCooperativeLevel == D3DERR_DEVICELOST || hrCooperativeLevel == D3DERR_DEVICENOTRESET)
621-
bAllowDeviceWork = false;
791+
if (pDevice)
792+
{
793+
bool bDeviceTemporarilyLost = false;
794+
if (!IsDeviceOperational(pDevice, &bDeviceTemporarilyLost))
795+
bAllowDeviceWork = !bDeviceTemporarilyLost && bDeviceOperational;
796+
}
622797

623798
if (pD3DEffect)
624799
{

Client/core/Graphics/CRenderItem.EffectParameters.cpp

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -367,25 +367,43 @@ HRESULT CEffectParameters::Begin(UINT* pPasses, DWORD Flags, bool bWorldRender)
367367
CGraphics::GetSingleton().GetRenderItemManager()->SaveReadableDepthBuffer();
368368
}
369369

370-
for (uint i = 0; i < m_SecondaryRenderTargetList.size(); i++)
370+
LPDIRECT3DDEVICE9 pDevice = nullptr;
371+
m_pD3DEffect->GetDevice(&pDevice);
372+
373+
bool bCanBindRenderTargets = (pDevice != nullptr);
374+
if (pDevice)
375+
{
376+
const HRESULT hrCooperativeLevel = pDevice->TestCooperativeLevel();
377+
if (hrCooperativeLevel != D3D_OK)
378+
{
379+
bCanBindRenderTargets = false;
380+
if (hrCooperativeLevel != D3DERR_DEVICELOST && hrCooperativeLevel != D3DERR_DEVICENOTRESET)
381+
WriteDebugEvent(SString("CEffectParameters::Begin: unexpected cooperative level %08x", hrCooperativeLevel));
382+
}
383+
}
384+
385+
if (bCanBindRenderTargets)
371386
{
372-
D3DXHANDLE hTexture = m_SecondaryRenderTargetList[i];
373-
IDirect3DBaseTexture9* pD3DTexture = NULL;
374-
HRESULT hr = m_pD3DEffect->GetTexture(hTexture, &pD3DTexture);
375-
if (hr == D3D_OK && pD3DTexture && pD3DTexture->GetType() == D3DRTYPE_TEXTURE)
387+
for (uint i = 0; i < m_SecondaryRenderTargetList.size(); i++)
376388
{
377-
IDirect3DSurface9* pD3DSurface = NULL;
378-
HRESULT hr = ((IDirect3DTexture9*)pD3DTexture)->GetSurfaceLevel(0, &pD3DSurface);
379-
if (hr == D3D_OK && pD3DSurface)
389+
D3DXHANDLE hTexture = m_SecondaryRenderTargetList[i];
390+
IDirect3DBaseTexture9* pD3DTexture = nullptr;
391+
HRESULT hr = m_pD3DEffect->GetTexture(hTexture, &pD3DTexture);
392+
if (hr == D3D_OK && pD3DTexture && pD3DTexture->GetType() == D3DRTYPE_TEXTURE)
380393
{
381-
LPDIRECT3DDEVICE9 pDevice;
382-
m_pD3DEffect->GetDevice(&pDevice);
383-
pDevice->SetRenderTarget(i + 1, pD3DSurface);
384-
SAFE_RELEASE(pD3DSurface);
394+
IDirect3DSurface9* pD3DSurface = nullptr;
395+
HRESULT hrSurface = ((IDirect3DTexture9*)pD3DTexture)->GetSurfaceLevel(0, &pD3DSurface);
396+
if (hrSurface == D3D_OK && pD3DSurface)
397+
{
398+
pDevice->SetRenderTarget(i + 1, pD3DSurface);
399+
SAFE_RELEASE(pD3DSurface);
400+
}
401+
SAFE_RELEASE(pD3DTexture);
385402
}
386-
SAFE_RELEASE(pD3DTexture);
387403
}
388404
}
405+
406+
SAFE_RELEASE(pDevice);
389407
return m_pD3DEffect->Begin(pPasses, Flags);
390408
}
391409

0 commit comments

Comments
 (0)