@@ -31,6 +31,34 @@ static EDiagnosticDebugType ms_DiagnosticDebug = EDiagnosticDebug::NONE;
3131//  To reuse shader setups between calls to DrawIndexedPrimitive
3232CShaderItem* 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+ 
3462void  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    {
0 commit comments