Skip to content

Commit 28030a1

Browse files
Synchronize changes from 1.6 branch [ci skip]
abafccd Addendum #2 to e556d42
2 parents af6a8fd + abafccd commit 28030a1

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");
@@ -356,23 +384,79 @@ HRESULT CDirect3DEvents9::DrawPrimitiveShader(IDirect3DDevice9* pDevice, D3DPRIM
356384

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

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

421+
bool bCompletedAnyPass = false;
422+
bool bEncounteredDeviceLoss = false;
364423
for (uint uiPass = 0; uiPass < uiNumPasses; uiPass++)
365424
{
366-
pD3DEffect->BeginPass(uiPass);
425+
HRESULT hrBeginPass = pD3DEffect->BeginPass(uiPass);
426+
if (FAILED(hrBeginPass))
427+
{
428+
if (hrBeginPass != D3DERR_DEVICELOST && hrBeginPass != D3DERR_DEVICENOTRESET)
429+
WriteDebugEvent(SString("DrawPrimitiveShader: BeginPass %u failed %08x", uiPass, hrBeginPass));
430+
else
431+
bEncounteredDeviceLoss = true;
432+
break;
433+
}
367434

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

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

377461
// If we didn't get the effect to save the shader state, clear some things here
378462
if (dwFlags & D3DXFX_DONOTSAVESHADERSTATE)
@@ -382,6 +466,9 @@ HRESULT CDirect3DEvents9::DrawPrimitiveShader(IDirect3DDevice9* pDevice, D3DPRIM
382466
}
383467

384468
SAFE_RELEASE(pOriginalVertexShader);
469+
470+
if (!bCompletedAnyPass && !bIsLayer && !bEncounteredDeviceLoss)
471+
return DrawPrimitiveGuarded(pDevice, PrimitiveType, StartVertex, PrimitiveCount);
385472
}
386473

387474
return D3D_OK;
@@ -511,12 +598,41 @@ HRESULT CDirect3DEvents9::DrawIndexedPrimitiveShader(IDirect3DDevice9* pDevice,
511598
dassert(pShaderItem == g_pActiveShader);
512599
g_pDeviceState->FrameStats.iNumShadersReuseSetup++;
513600

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

521637
return DrawIndexedPrimitiveGuarded(pDevice, PrimitiveType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
522638
}
@@ -526,14 +642,11 @@ HRESULT CDirect3DEvents9::DrawIndexedPrimitiveShader(IDirect3DDevice9* pDevice,
526642
CShaderInstance* pShaderInstance = pShaderItem->m_pShaderInstance;
527643

528644
// Add normal stream if shader wants it
529-
if (pShaderInstance->m_pEffectWrap->m_pEffectTemplate->m_bRequiresNormals)
645+
CAdditionalVertexStreamManager* pAdditionalStreamManager = CAdditionalVertexStreamManager::GetExistingSingleton();
646+
if (pShaderInstance->m_pEffectWrap->m_pEffectTemplate->m_bRequiresNormals && pAdditionalStreamManager)
530647
{
531648
// Find/create/set additional vertex stream
532-
if (CAdditionalVertexStreamManager* pAdditionalStreamManager = CAdditionalVertexStreamManager::GetExistingSingleton())
533-
{
534-
pAdditionalStreamManager->MaybeSetAdditionalVertexStream(PrimitiveType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex,
535-
primCount);
536-
}
649+
pAdditionalStreamManager->MaybeSetAdditionalVertexStream(PrimitiveType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
537650
}
538651

539652
// Apply custom parameters
@@ -549,22 +662,68 @@ HRESULT CDirect3DEvents9::DrawIndexedPrimitiveShader(IDirect3DDevice9* pDevice,
549662

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

553687
DWORD dwFlags = D3DXFX_DONOTSAVESHADERSTATE; // D3DXFX_DONOTSAVE(SHADER|SAMPLER)STATE
554688
uint uiNumPasses = 0;
555-
pShaderInstance->m_pEffectWrap->Begin(&uiNumPasses, dwFlags);
689+
HRESULT hrBegin = pShaderInstance->m_pEffectWrap->Begin(&uiNumPasses, dwFlags);
690+
if (FAILED(hrBegin) || uiNumPasses == 0)
691+
{
692+
if (FAILED(hrBegin) && hrBegin != D3DERR_DEVICELOST && hrBegin != D3DERR_DEVICENOTRESET)
693+
WriteDebugEvent(SString("DrawIndexedPrimitiveShader: Begin failed %08x", hrBegin));
556694

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

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

565-
DrawIndexedPrimitiveGuarded(pDevice, PrimitiveType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
722+
HRESULT hrDraw = DrawIndexedPrimitiveGuarded(pDevice, PrimitiveType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
723+
if (hrDraw == D3DERR_DEVICELOST || hrDraw == D3DERR_DEVICENOTRESET)
724+
bEncounteredDeviceLoss = true;
566725

567-
if (uiNumPasses == 1 && bCanBecomeActiveShader && pOriginalVertexShader == NULL && g_pCore->IsRenderingGrass())
726+
if (uiNumPasses == 1 && bCanBecomeActiveShader && pOriginalVertexShader == NULL && g_pCore->IsRenderingGrass() && SUCCEEDED(hrDraw))
568727
{
569728
// Make this the active shader for possible reuse
570729
dassert(dwFlags == D3DXFX_DONOTSAVESHADERSTATE);
@@ -573,9 +732,23 @@ HRESULT CDirect3DEvents9::DrawIndexedPrimitiveShader(IDirect3DDevice9* pDevice,
573732
return D3D_OK;
574733
}
575734

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

580753
// If we didn't get the effect to save the shader state, clear some things here
581754
if (dwFlags & D3DXFX_DONOTSAVESHADERSTATE)
@@ -585,10 +758,13 @@ HRESULT CDirect3DEvents9::DrawIndexedPrimitiveShader(IDirect3DDevice9* pDevice,
585758
}
586759

587760
// Unset additional vertex stream
588-
if (CAdditionalVertexStreamManager* pAdditionalStreamManager = CAdditionalVertexStreamManager::GetExistingSingleton())
761+
if (pAdditionalStreamManager)
589762
pAdditionalStreamManager->MaybeUnsetAdditionalVertexStream();
590763

591764
SAFE_RELEASE(pOriginalVertexShader);
765+
766+
if (!bCompletedAnyPass && !bEncounteredDeviceLoss && !bIsLayer)
767+
return DrawIndexedPrimitiveGuarded(pDevice, PrimitiveType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
592768
}
593769

594770
return D3D_OK;
@@ -608,15 +784,14 @@ void CDirect3DEvents9::CloseActiveShader(bool bDeviceOperational)
608784

609785
ID3DXEffect* pD3DEffect = g_pActiveShader->m_pShaderInstance->m_pEffectWrap->m_pD3DEffect;
610786
IDirect3DDevice9* pDevice = g_pGraphics ? g_pGraphics->GetDevice() : nullptr;
611-
HRESULT hrCooperativeLevel = D3D_OK;
612-
if (pDevice)
613-
hrCooperativeLevel = pDevice->TestCooperativeLevel();
614787

615788
bool bAllowDeviceWork = bDeviceOperational;
616-
if (hrCooperativeLevel == D3D_OK)
617-
bAllowDeviceWork = true;
618-
else if (hrCooperativeLevel == D3DERR_DEVICELOST || hrCooperativeLevel == D3DERR_DEVICENOTRESET)
619-
bAllowDeviceWork = false;
789+
if (pDevice)
790+
{
791+
bool bDeviceTemporarilyLost = false;
792+
if (!IsDeviceOperational(pDevice, &bDeviceTemporarilyLost))
793+
bAllowDeviceWork = !bDeviceTemporarilyLost && bDeviceOperational;
794+
}
620795

621796
if (pD3DEffect)
622797
{

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)