Responding to a Lost Device

  CU_MDX_LostDevice.zip (63.4 KiB, 2,508 hits)


  CUnitFramework.zip (101.1 KiB, 20,514 hits)

Extract the C-Unit Framework
inside the project (not solution) directory.

When a device is in fullscreen mode, many of the resources that the application is using (textures, buffers, etc.) are stored in video memory. When the user Alt-Tabs to go to another application, video memory may be given over to other applications and the original data may be lost. When this occurs, the Device.Present method will throw an exception. This is what is known as a lost device. To get back to the normal operational state, we must reset the device whenever it is lost. In this tutorial, I will explain how the C-Unit Framework handles a lost device.

/// Render the current frame.
private void OnRenderFrame()
{
if ( ( this.WindowState == FormWindowState.Minimized ) ||
m_graphics.Device == null || m_graphics.Device.IsDisposed || m_state.FormClosing ||
m_state.DeviceLost )
{
return;
}

try
{
m_gameStates.OnRenderFrame( m_graphics.Device, m_timer.ElapsedTime );
}
catch ( DeviceLostException )
{
// The device is lost
System.Threading.Thread.Sleep( 50 );
if ( !m_state.DeviceLost )
{
Pause( true, true );
m_state.DeviceLost = true;
}
}
}

As stated above, when the device is lost, the Device.Present method will throw a DeviceLostException. Since this method is called in one of the GameStates, we’ll surround the StateManager’s OnRenderDevice with a try block to catch the DeviceLostException. When we catch the exception, we flag the Device as being lost.

/// Application idle event. Updates and renders frames.
/// Sending object
/// Event arguments
private void OnApplicationIdle( object sender, EventArgs e )
{
if ( m_graphics.Device == null )
{
return;
}
while ( AppStillIdle )
{
if ( !m_graphics.Device.IsDisposed && !m_state.FormClosing && !m_state.DeviceLost &&
this.WindowState != FormWindowState.Minimized && m_state.Initialized )
{
OnUpdateFrame();
OnRenderFrame();
}
else if ( m_state.DeviceLost )
{
RegainLostDevice();
}
}
}

When the Device is flagged as lost, the Framework will call the RegainLostDevice method:

/// Tries to regain a lost device.
private void RegainLostDevice()
{
// Check for lost device
if ( !m_graphics.Device.CheckCooperativeLevel() )
{
ResultCode code = m_graphics.Device.CheckCooperativeLevelResult();
if ( code == ResultCode.DeviceLost )
{
// The device has been lost but cannot be reset at this time.  
// So wait until it can be reset.
System.Threading.Thread.Sleep( 50 );
return;
}
try
{
m_state.DisableResize = true;
m_graphics.Reset();
m_state.DeviceLost = false;
m_state.DisableResize = false;
Pause( false, false );
}
catch ( DeviceLostException )
{
// The device was lost again, so continue waiting until it can be reset.
System.Threading.Thread.Sleep( 50 );
}
}
}

When a device is lost, the Device.CheckCooperativeLevel method returns false and we should try to regain the Device. To see if we can reset the Device, we call Device.CheckCooperativeLevelResult, which returns a ResultCode. This result code has 2 possible values when the Device is lost: DeviceLost and DeviceNotReset. A DeviceLost result code means that the device is lost but cannot be reset yet. When we see this result code, we pause the program thread for a bit and then return out of the method. A DeviceNotReset result code means that we can attempt to reset the device to return to normal. There is a chance that when we reset the device, the device will have become lost again. If this is the case, Device.Reset will throw a DeviceLostException. We catch this exception, pause for a bit and return just like we did when the result code was DeviceLost.

// Set device events
m_graphics.Device.DeviceLost += new System.EventHandler( this.OnLostDevice );
m_graphics.Device.DeviceReset += new System.EventHandler( this.OnResetDevice );
m_graphics.Device.Disposing += new System.EventHandler( this.OnDestroyDevice );

Since we’ve hooked the DeviceLost and DeviceReset events of the device, our OnLostDevice and OnResetDevice methods will be called automatically when the device is lost and reset.

And that’s all I have to say about that.