In the sample you linked that works, an error on Reset
results in return
and the render
function just gets called again. This is normal - there is no reason why Reset
must succeed on the first call, so it's usual to keep retrying rather than showing an error message like in your code.
If you're rendering in the message loop, like in that example, just do the same thing - don't stop when you get an error.
If you don't render in the message loop, but use the WM_PAINT
method, then this is the general pattern that I use - although sometimes I set a timer rather than calling InvalidateRect
, it depends on the app - but this has been robust enough for many applications. You can see how the Reset
will get repeated on failure, rather than throwing an error message on the first fail. It might be an idea to adopt this pattern:
void CMyClass::DrawScene()
{
// perform all dx9 scene drawing
HRESULT hr;
// if device was lost, try to restore it
if (m_bDeviceLost)
{
// is it ok to render again yet?
if (FAILED(hr = m_pD3DDevice->TestCooperativeLevel()))
{
// the device has been lost but cannot be reset at this time
if (hr == D3DERR_DEVICELOST)
{
// request repaint and exit
InvalidateRect(NULL);
return;
}
// the device has been lost and can be reset
if (hr == D3DERR_DEVICENOTRESET)
{
// do lost/reset/restore cycle
OnLostDevice();
hr = m_pD3DDevice->Reset(&m_pD3Dpp);
if (FAILED(hr))
{
// reset failed, try again later
InvalidateRect(NULL);
return;
}
OnResetDevice();
}
}
// flag device status ok now
m_bDeviceLost = false;
}
// ... clear to background and do the drawing ...
// display scene
hr = m_pD3DDevice->Present(NULL, NULL, GetSafeHwnd(), NULL);
m_bDeviceLost = (hr == D3DERR_DEVICELOST);
// request repaint if device has been lost
if (m_bDeviceLost)
{
InvalidateRect(NULL);
}
}
Also, you must ensure that TestCooperativeLevel
and Reset
are called from the same thread that was used to create the device.