Device lost handling

Started by
10 comments, last by Hassanbasil 14 years ago
Hello everyone, I'm trying to handle the device lost situation, but i'm missing some few info: first, the code for this should look like this, right?

HRESULT hr = device->TestCooperativeLevel();
if ( hr == D3DERR_DEVICELOST )
{
    while ( 1 )
    {
        hr = device->TestCooperativeLevel();
        if ( hr == D3DERR_DEVICENOTRESET )
        {
            Reset();
            break;
        }
    }
}

if so, all what Reset() should do is release media, reset device then reload media, right? which media should be released, other than meshes? thanks in advance -Hassan
Advertisement
Quote:Original post by Hassanbasil
Hello everyone,

I'm trying to handle the device lost situation, but i'm missing some few info:

first, the code for this should look like this, right?
*** Source Snippet Removed ***
Nope - You shouldn't do a while() loop like that; you're not processing window messages so the device will never get out of the lost state.

Quote:Original post by Hassanbasil
if so, all what Reset() should do is release media, reset device then reload media, right?
which media should be released, other than meshes?
As soon as you get your first D3DERR_DEVICELOST, you should Release() all D3DPOOL_DEFAULT resources, and call OnLostDevice() for any D3DX classes you have.
When you then get D3DERR_DEVICENOTRESET, you should Reset() the device and then re-create any resources you need to and call OnResetDevice() for any D3DX objects that require it. Also note that you may get a D3DERR_DEVICENOTRESET without a D3DERR_DEVICELOST error, in which case you should act as if you got a D3DERR_DEVICELOST error first (I.e. Release() all default pool objects, etc).
Thanks for the reply, so it should look like:
HRESULT hr = device->TestCooperativeLevel();if ( hr == D3DERR_DEVICELOST ){    PreResetStuff();    while ( 1 )    {        HandleMessages();        hr = device->TestCooperativeLevel();        if ( hr == D3DERR_DEVICENOTRESET )        {            Reset();            break;        }    }}


PreResetStuff() should release D3DPOOL_DEFAULT resources, and call OnDeviceLost for meshes/textues/sprites? what does OnDeviceLost() do? saves anything from the mesh? or i need the vertex/index buffers of the object before losing the device and re-create meshes using them?

also, are you saying that if i get the D3DERR_DEVICENOTRESET without D3DERR_DEVICELOST, i should do the same as getting a D3DERR_DEVICELOST?
Quote:Original post by Hassanbasil
Thanks for the reply, so it should look like:
*** Source Snippet Removed ***
Pretty much - that won't handle the case where you get a D3DERR_DEVICENOTRESET without a D3DERR_DEVICELOST error though. I'd do:
HRESULT hr = device->TestCooperativeLevel();if(hr == D3DERR_DEVICELOST || hr == D3DERR_DEVICENOTRESET){    PreResetStuff();    while(hr == D3DERR_DEVICELOST)    {        HandleMessages();        hr = device->TestCooperativeLevel();    }    Reset();}

Note that TestCooperativeLevel() can also return D3DERR_DRIVERINTERNALERROR, in which case you should probably just exit as quickly as possible (The docs says you could re-create the device, but that's a pretty major thing to do).

Quote:Original post by Hassanbasil
PreResetStuff() should release D3DPOOL_DEFAULT resources, and call OnDeviceLost for meshes/textues/sprites? what does OnDeviceLost() do? saves anything from the mesh? or i need the vertex/index buffers of the object before losing the device and re-create meshes using them?
You only need to call OnLostDevice() for D3DX classes that you have instances of that have that as a member function. The documentation says thats for ID3DXEffect, ID3DXFont, ID3DXLine, ID3DXRenderToEnvMap, ID3DXRenderToSurface, and ID3DXSprite). All that does is Release()s the objects internal data structures (E.g. the dynamic vertex buffer maintained by ID3DXSprite).

Quote:Original post by Hassanbasil
also, are you saying that if i get the D3DERR_DEVICENOTRESET without D3DERR_DEVICELOST, i should do the same as getting a D3DERR_DEVICELOST?
See my example above.
Great, once again thanks for the information & tips
I do not open an extra thread for my question, because this is the same topic. On my DX11 engine I can switch between windowed and fullscreen just by pressing alt+return. It apears, that the switch has some problems to get the proper mode, but then all runs well.

I think, I still have to handle the device reset, even on DX11. But why can I switch between the modes without an exception? Is this a feature of SlimDX, of DX11 or maybe Win7? (Aero?)

On Dx9, there I get an exception, if I do not handle the switch correctly. ^^
sorry for bumping this, but i'm getting some problems that i didnt notice last time:

my current handling:
//render	HRESULT hr = device->TestCooperativeLevel ( );	if ( hr == D3DERR_DEVICELOST || hr == D3DERR_DEVICENOTRESET )	{		if ( !HandleLostDevice ( ) )		{			CheckErrors ( );			exit ( 0 );			return;		}	}	else if ( hr == D3DERR_DRIVERINTERNALERROR )	{		PostError ( "Fatal error: Driver cannot be reset due to a driver error", true );		return;	}//HandleLostDevicebool hxCore::HandleLostDevice ( void ){	TextSprite->OnLostDevice ( );	for ( int i = 0; i < SpriteV.size(); i++ )		SpriteV->Sprite->OnLostDevice ( );	for ( int i = 0; i < FontV.size(); i++ )		FontV.font->OnLostDevice ( );	HRESULT hr = device->TestCooperativeLevel ( );	while ( hr == D3DERR_DEVICELOST )	{		hr = device->TestCooperativeLevel ( );		if ( !Loop ( ) ) //window messages handling			return false;		else if ( hr == D3DERR_DRIVERINTERNALERROR )		{			PostError ( "Fatal error: device cannot be reset due to a driver error", true );			return false;		}	}	return Init ( windowWidth, windowHeight, windowDepth, windowMode, maxFps );}//Init		PresentParameters->BackBufferWidth            = Width;		PresentParameters->BackBufferHeight           = Height; 		if ( Depth == 32 )			PresentParameters->AutoDepthStencilFormat = D3DFMT_D24S8;		else if ( Depth == 16 )			PresentParameters->AutoDepthStencilFormat = D3DFMT_D16;		PresentParameters->Windowed                   = windowed;		HRESULT hr = device->Reset ( PresentParameters );		if ( FAILED ( hr ) )		{			char Err[200];			switch ( hr )			{				case D3DERR_DEVICELOST:					if ( !HandleLostDevice ( ) )					{						CheckErrors ( );						exit ( 0 );						return false;					}				break;				case D3DERR_DEVICEREMOVED:					sprintf_s ( Err, 200, "Failed to create the device\nDevice removed" );				break;				case D3DERR_DRIVERINTERNALERROR:					sprintf_s ( Err, 200, "Failed to create the device\nInternal error" );				break;				case D3DERR_OUTOFVIDEOMEMORY :					sprintf_s ( Err, 200, "Failed to create the device\nOut of memory" );				break;				default :					sprintf_s ( Err, 200, "Failed to create the device\nError code: %d", (int)hr );				break;			}			PostError ( this, Err, true );			return false;		}		device->SetSamplerState ( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );		device->SetSamplerState ( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );		device->SetSamplerState ( 0, D3DSAMP_MIPFILTER, D3DTEXF_POINT );		device->SetRenderState  ( D3DRS_AMBIENT, D3DCOLOR_XRGB ( 100, 100, 100 ) );		// set blending factors so that alpha component determines transparency		device->SetRenderState ( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );		device->SetRenderState ( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);		if ( FAILED ( D3DXCreateSprite ( device, &TextSprite ) ) )		{			PostError ( this, "Unable to initiallize text", true );			return false;		}		for ( int i = 0; i < SpriteV.size(); i++ )			if ( SpriteV->vaild )				SpriteV->Create ( SpriteV->texture.fileName );				hFONT font;		font.ID = 0;		D3DXCreateFont ( device, 20, 0, FW_BOLD, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY,			DEFAULT_PITCH | FF_DONTCARE, TEXT ( "Arial" ), &font.font );		FontV.push_back ( font );


this works just fine if i alt+ctrl+delete and get back, but if i ALT-tab or press the start button on keyboard, i get an unhandled exception at TextSprite->OnLostDevice ( );, what's happening there?

P.S. i dont have anything that uses D3DPOOL_DEFAULT at the moment.
Quote:Original post by Hassanbasil
this works just fine if i alt+ctrl+delete and get back, but if i ALT-tab or press the start button on keyboard, i get an unhandled exception at TextSprite->OnLostDevice ( );, what's happening there?
What is the exact error you're getting? It sounds like you've already Release()d the sprite, not initialised it, or already called OnLostDevice() on it (Although I would have thought the last would work).
Quote:What is the exact error you're getting? It sounds like you've already Release()d the sprite, not initialised it, or already called OnLostDevice() on it (Although I would have thought the last would work).


ahh you're a jenious, it seems i've already released it ( yeah, it's hard to debug in full screen mode.. )
so anyway, here's what's happening:
1- i detect a device lost situation, and thus call HandleLostDevice ( mentioned above )
2- it calls Init when it's ready to reset
3- in the init function, i have this:
                if ( !specFlag )		{			TextSprite->Release ( );			for ( int i = 0; i < SpriteV.size(); i++ )				if ( SpriteV->vaild )				{					SpriteV->Sprite->Release ( );					SpriteV->texture.tex->Release ( );				}			for ( int i = 0; i < FontV.size(); i++ )				FontV.font->Release ( );		}		PresentParameters->BackBufferWidth            = Width;		PresentParameters->BackBufferHeight           = Height; 		if ( Depth == 32 )			PresentParameters->AutoDepthStencilFormat = D3DFMT_D24S8;		else if ( Depth == 16 )			PresentParameters->AutoDepthStencilFormat = D3DFMT_D16;		PresentParameters->Windowed                   = windowed;		HRESULT hr = device->Reset ( PresentParameters );		if ( FAILED ( hr ) )		{			char Err[200];			switch ( hr )			{				case D3DERR_DEVICELOST:					if ( !HandleLostDevice ( ) )					{						CheckErrors ( );						exit ( 0 );						return false;					}				break;				case D3DERR_DEVICEREMOVED:					sprintf_s ( Err, 200, "Failed to create the device\nDevice removed" );				break;				case D3DERR_DRIVERINTERNALERROR:					sprintf_s ( Err, 200, "Failed to create the device\nInternal error" );				break;				case D3DERR_OUTOFVIDEOMEMORY :					sprintf_s ( Err, 200, "Failed to create the device\nOut of memory" );				break;				default :					sprintf_s ( Err, 200, "Failed to create the device\nError code: %d", (int)hr );				break;			}			PostError ( this, Err, true );			return false;		}


--specFlag is false over there--
IDirect3DDevice9::Reset() returns D3DERR_DEVICELOST, so i re-call HandleLostDevice there, while the stuff are already released, and there goes the problem, why am i getting D3DERR_DEVICELOST there, when i already knew that i can recover the device from HandleLostDevice at the first place?
When you get D3DERR_DEVICELOST, that means "The device is lost and you can't currently reset it". In your code, you try to call Reset() anyway, even though it's lost (E.g. another app has focus).

If you get D3DERR_DEVICELOST, you need to wait until you get D3DERR_DEVICENOTRESET before you can attempt to reset it.

This topic is closed to new replies.

Advertisement