Game Development Community

TGEA 1.7.1 DirectX9 deadlock situation

by Michael Gingerich · in Torque Game Engine Advanced · 10/21/2008 (5:32 am) · 2 replies

TestCooperativeLevel() will keep returning D3DERR_DEVICELOST indefinitely unless the windows message queue is being processed. beginSceneInternal() can go into a deadlock if the DirectX device needs to be reset. This can be repro'ed by alt-tabbing away from full screen during mission load

void GFXPCD3D9Device::beginSceneInternal()
{
// Make sure we have a device
HRESULT res = mD3DDevice->TestCooperativeLevel();

while(res == D3DERR_DEVICELOST)
{
// Lost device! Just keep querying
res = mD3DDevice->TestCooperativeLevel();

Con::warnf("GFXD3D9Device::beginScene - Device needs to be reset, waiting on device...");

// *** need to either process messages here or otherwise exit from this loop to do so ***

Sleep(50);
}

}

#1
10/21/2008 (10:07 am)
Try this:
bool GFXD3D9Device::beginSceneInternal() 
{
   // Make sure we have a device
   HRESULT res = mD3DDevice->TestCooperativeLevel();

   S32 attempts = 0;
   const S32 MaxAttempts = 40;
   const S32 SleepMsPerAttempt = 50;
   while(res == D3DERR_DEVICELOST && attempts < MaxAttempts)
   {
      // Lost device! Just keep querying
      res = mD3DDevice->TestCooperativeLevel();

      Con::warnf("GFXD3D9Device::beginScene - Device needs to be reset, waiting on device...");

      Sleep(SleepMsPerAttempt);
      attempts++;
   }

   if (attempts >= MaxAttempts && res == D3DERR_DEVICELOST)
   {
      Con::errorf("GFXD3D9Device::beginScene - Device lost and reset wait time exceeded, skipping reset (will retry later)");
      mCanCurrentlyRender = false;
      return false;
   }

   // Trigger a reset if we can't get a good result from TestCooperativeLevel.
   if(res == D3DERR_DEVICENOTRESET)
   {
      Con::warnf("GFXD3D9Device::beginScene - Device needs to be reset, resetting device...");

      // Reset the device!
      GFXResource *walk = mResourceListHead;
      while(walk)
      {
         // Find the window target with implicit flag set and reset the device with its presentation params.
         if(GFXD3D9WindowTarget *gdwt = dynamic_cast<GFXD3D9WindowTarget*>(walk))
         {
            if(gdwt->mImplicit)
            {
               reset(gdwt->mPresentationParams);
               break;
            }
         }

         walk = walk->getNextResource();
      }
   }

   HRESULT hr = mD3DDevice->BeginScene();
   D3D9Assert(hr, "GFXD3D9Device::beginSceneInternal - failed to BeginScene");
   mCanCurrentlyRender = SUCCEEDED(hr);
   return mCanCurrentlyRender;      
}
#2
10/21/2008 (12:59 pm)
Thanks.

That might work except for a beginSceneInterval() call here:

void ClipMapBlenderCache::beginRectUpdates( ClipMap::ClipStackEntry &cse )
{

if(!GFX->canCurrentlyRender())
{
mustEndScene = true;
GFX->beginScene();
}
else
{
mustEndScene = false;
}

}