Sign in to follow this  
Hassanbasil

Device lost handling

Recommended Posts

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

Share this post


Link to post
Share on other sites
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).

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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. ^^

Share this post


Link to post
Share on other sites
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;
}
//HandleLostDevice
bool hxCore::HandleLostDevice ( void )
{
TextSprite->OnLostDevice ( );
for ( int i = 0; i < SpriteV.size(); i++ )
SpriteV[i]->Sprite->OnLostDevice ( );
for ( int i = 0; i < FontV.size(); i++ )
FontV[i].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[i]->vaild )
SpriteV[i]->Create ( SpriteV[i]->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.

Share this post


Link to post
Share on other sites
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).

Share this post


Link to post
Share on other sites
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[i]->vaild )
{
SpriteV[i]->Sprite->Release ( );
SpriteV[i]->texture.tex->Release ( );
}
for ( int i = 0; i < FontV.size(); i++ )
FontV[i].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?

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Well, i already got the D3DERR_DEVICENOTRESET int HandleLostDevice():

HRESULT hr = device->TestCooperativeLevel ( );
while ( hr != D3DERR_DEVICENOTRESET )
{
hr = device->TestCooperativeLevel ( );
if ( !Loop ( ) )
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, 1 );

Share this post


Link to post
Share on other sites
Ahh.. the error seems to be somewhere else, in my window proc, as i call Init when the window is resized, thats why it worked fine with alt+ctrl+delete, i solved it, thanks for your help.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this