Reset a lost device before releasing it

TRAC #13622 This prevents the driver from getting stuck in an undefined state and returning errors when trying to create a new device or querying capabilities. Signed-off-by: Daniel Koch Author: Nicolas Capens git-svn-id: https://angleproject.googlecode.com/svn/trunk@436 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent 677a1517
...@@ -95,12 +95,22 @@ bool Display::initialize() ...@@ -95,12 +95,22 @@ bool Display::initialize()
// UNIMPLEMENTED(); // FIXME: Determine which adapter index the device context corresponds to // UNIMPLEMENTED(); // FIXME: Determine which adapter index the device context corresponds to
} }
HRESULT result = mD3d9->GetDeviceCaps(mAdapter, mDeviceType, &mDeviceCaps); HRESULT result;
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) do
{ {
return error(EGL_BAD_ALLOC, false); result = mD3d9->GetDeviceCaps(mAdapter, mDeviceType, &mDeviceCaps);
if (result == D3DERR_NOTAVAILABLE)
{
Sleep(0); // Give the driver some time to initialize/recover
}
else if (FAILED(result)) // D3DERR_OUTOFVIDEOMEMORY, E_OUTOFMEMORY, D3DERR_INVALIDDEVICE, or another error we can't recover from
{
return error(EGL_BAD_ALLOC, false);
}
} }
while(result == D3DERR_NOTAVAILABLE);
ASSERT(SUCCEEDED(result)); ASSERT(SUCCEEDED(result));
...@@ -204,18 +214,24 @@ bool Display::initialize() ...@@ -204,18 +214,24 @@ bool Display::initialize()
void Display::terminate() void Display::terminate()
{ {
while (!mSurfaceSet.empty()) while (!mSurfaceSet.empty())
{ {
destroySurface(*mSurfaceSet.begin()); destroySurface(*mSurfaceSet.begin());
} }
while (!mContextSet.empty()) while (!mContextSet.empty())
{ {
destroyContext(*mContextSet.begin()); destroyContext(*mContextSet.begin());
} }
if (mDevice) if (mDevice)
{ {
// If the device is lost, reset it first to prevent leaving the driver in an unstable state
if (FAILED(mDevice->TestCooperativeLevel()))
{
resetDevice();
}
mDevice->Release(); mDevice->Release();
mDevice = NULL; mDevice = NULL;
} }
...@@ -314,7 +330,7 @@ bool Display::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value) ...@@ -314,7 +330,7 @@ bool Display::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value)
bool Display::createDevice() bool Display::createDevice()
{ {
D3DPRESENT_PARAMETERS presentParameters = getPresentParameters(); D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES; DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES;
HRESULT result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice); HRESULT result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice);
...@@ -343,6 +359,29 @@ bool Display::createDevice() ...@@ -343,6 +359,29 @@ bool Display::createDevice()
return true; return true;
} }
bool Display::resetDevice()
{
D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
HRESULT result;
do
{
Sleep(0); // Give the graphics driver some CPU time
result = mDevice->Reset(&presentParameters);
}
while (result == D3DERR_DEVICELOST);
if (FAILED(result))
{
return error(EGL_BAD_ALLOC, false);
}
ASSERT(SUCCEEDED(result));
return true;
}
Surface *Display::createWindowSurface(HWND window, EGLConfig config) Surface *Display::createWindowSurface(HWND window, EGLConfig config)
{ {
const Config *configuration = mConfigSet.get(config); const Config *configuration = mConfigSet.get(config);
...@@ -364,24 +403,11 @@ EGLContext Display::createContext(EGLConfig configHandle, const gl::Context *sha ...@@ -364,24 +403,11 @@ EGLContext Display::createContext(EGLConfig configHandle, const gl::Context *sha
} }
else if (FAILED(mDevice->TestCooperativeLevel())) // Lost device else if (FAILED(mDevice->TestCooperativeLevel())) // Lost device
{ {
D3DPRESENT_PARAMETERS presentParameters = getPresentParameters(); if (!resetDevice())
HRESULT result;
do
{ {
Sleep(0); // Give the graphics driver some CPU time return NULL;
result = mDevice->Reset(&presentParameters);
}
while (result == D3DERR_DEVICELOST);
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DEVICEREMOVED || result == D3DERR_DRIVERINTERNALERROR)
{
return error(EGL_BAD_ALLOC, (EGLContext)NULL);
} }
ASSERT(SUCCEEDED(result));
// Restore any surfaces that may have been lost // Restore any surfaces that may have been lost
for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
{ {
...@@ -565,7 +591,7 @@ bool Display::getEventQuerySupport() ...@@ -565,7 +591,7 @@ bool Display::getEventQuerySupport()
return result != D3DERR_NOTAVAILABLE; return result != D3DERR_NOTAVAILABLE;
} }
D3DPRESENT_PARAMETERS Display::getPresentParameters() D3DPRESENT_PARAMETERS Display::getDefaultPresentParameters()
{ {
D3DPRESENT_PARAMETERS presentParameters = {0}; D3DPRESENT_PARAMETERS presentParameters = {0};
......
...@@ -68,7 +68,7 @@ class Display ...@@ -68,7 +68,7 @@ class Display
private: private:
DISALLOW_COPY_AND_ASSIGN(Display); DISALLOW_COPY_AND_ASSIGN(Display);
D3DPRESENT_PARAMETERS getPresentParameters(); D3DPRESENT_PARAMETERS getDefaultPresentParameters();
const HDC mDc; const HDC mDc;
...@@ -95,6 +95,7 @@ class Display ...@@ -95,6 +95,7 @@ class Display
ContextSet mContextSet; ContextSet mContextSet;
bool createDevice(); bool createDevice();
bool resetDevice();
}; };
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment