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);
}
}
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);
}
}
#2
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;
}
}
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;
}
}
Torque 3D Owner Pat Wilson
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; }