Implemented recovering from a lost device by context recreation.
TRAC #13222
Singed-off-by: Daniel Koch
Author: Nicolas Capens <nicolas@transgaming.com>
git-svn-id: http://angleproject.googlecode.com/svn/trunk@406 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libEGL/Display.cpp b/src/libEGL/Display.cpp
index 5aede45..43cbf32 100644
--- a/src/libEGL/Display.cpp
+++ b/src/libEGL/Display.cpp
@@ -17,7 +17,8 @@
#include "libEGL/main.h"
-#define REF_RAST 0 // Can also be enabled by defining FORCE_REF_RAST in the project's predefined macros
+#define REF_RAST 0 // Can also be enabled by defining FORCE_REF_RAST in the project's predefined macros
+#define ENABLE_D3D9EX 1 // Enables use of the IDirect3D9Ex interface, when available
namespace egl
{
@@ -77,7 +78,7 @@
// Use Direct3D9Ex if available. Among other things, this version is less
// inclined to report a lost context, for example when the user switches
// desktop. Direct3D9Ex is available in Windows Vista and later if suitable drivers are available.
- if (Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9ex)))
+ if (ENABLE_D3D9EX && Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9ex)))
{
ASSERT(mD3d9ex);
mD3d9ex->QueryInterface(IID_IDirect3D9, reinterpret_cast<void**>(&mD3d9));
@@ -102,6 +103,8 @@
return error(EGL_BAD_ALLOC, false);
}
+ ASSERT(SUCCEEDED(result));
+
if (mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(2, 0))
{
terminate();
@@ -183,13 +186,6 @@
mConfigSet.mSet.insert(configuration);
}
-
- if (!createDevice())
- {
- terminate();
-
- return false;
- }
}
if (!isInitialized())
@@ -199,6 +195,11 @@
return false;
}
+ static const TCHAR windowName[] = TEXT("AngleHiddenWindow");
+ static const TCHAR className[] = TEXT("STATIC");
+
+ mDeviceWindow = CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);
+
return true;
}
@@ -314,28 +315,7 @@
bool Display::createDevice()
{
- static const TCHAR windowName[] = TEXT("AngleHiddenWindow");
- static const TCHAR className[] = TEXT("STATIC");
-
- mDeviceWindow = CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);
-
- D3DPRESENT_PARAMETERS presentParameters = {0};
-
- // The default swap chain is never actually used. Surface will create a new swap chain with the proper parameters.
- presentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
- presentParameters.BackBufferCount = 1;
- presentParameters.BackBufferFormat = D3DFMT_UNKNOWN;
- presentParameters.BackBufferWidth = 1;
- presentParameters.BackBufferHeight = 1;
- presentParameters.EnableAutoDepthStencil = FALSE;
- presentParameters.Flags = 0;
- presentParameters.hDeviceWindow = mDeviceWindow;
- presentParameters.MultiSampleQuality = 0;
- presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
- presentParameters.PresentationInterval = convertInterval(mMinSwapInterval);
- presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
- presentParameters.Windowed = TRUE;
-
+ D3DPRESENT_PARAMETERS presentParameters = getPresentParameters();
DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES;
HRESULT result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice);
@@ -377,6 +357,40 @@
EGLContext Display::createContext(EGLConfig configHandle, const gl::Context *shareContext)
{
+ if (!mDevice)
+ {
+ if (!createDevice())
+ {
+ return NULL;
+ }
+ }
+ else if (FAILED(mDevice->TestCooperativeLevel())) // Lost device
+ {
+ D3DPRESENT_PARAMETERS presentParameters = getPresentParameters();
+ HRESULT result;
+
+ do
+ {
+ Sleep(0); // Give the graphics driver some CPU time
+
+ 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
+ for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
+ {
+ (*surface)->resetSwapChain();
+ }
+ }
+
const egl::Config *config = mConfigSet.get(configHandle);
gl::Context *context = glCreateContext(config, shareContext);
@@ -395,6 +409,14 @@
{
glDestroyContext(context);
mContextSet.erase(context);
+
+ if (mContextSet.empty() && mDevice && FAILED(mDevice->TestCooperativeLevel())) // Last context of a lost device
+ {
+ for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
+ {
+ (*surface)->release();
+ }
+ }
}
bool Display::isInitialized()
@@ -461,6 +483,14 @@
IDirect3DDevice9 *Display::getDevice()
{
+ if (!mDevice)
+ {
+ if (!createDevice())
+ {
+ return NULL;
+ }
+ }
+
return mDevice;
}
@@ -541,4 +571,26 @@
return result != D3DERR_NOTAVAILABLE;
}
+
+D3DPRESENT_PARAMETERS Display::getPresentParameters()
+{
+ D3DPRESENT_PARAMETERS presentParameters = {0};
+
+ // The default swap chain is never actually used. Surface will create a new swap chain with the proper parameters.
+ presentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
+ presentParameters.BackBufferCount = 1;
+ presentParameters.BackBufferFormat = D3DFMT_UNKNOWN;
+ presentParameters.BackBufferWidth = 1;
+ presentParameters.BackBufferHeight = 1;
+ presentParameters.EnableAutoDepthStencil = FALSE;
+ presentParameters.Flags = 0;
+ presentParameters.hDeviceWindow = mDeviceWindow;
+ presentParameters.MultiSampleQuality = 0;
+ presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
+ presentParameters.PresentationInterval = convertInterval(mMinSwapInterval);
+ presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
+ presentParameters.Windowed = TRUE;
+
+ return presentParameters;
}
+}
\ No newline at end of file
diff --git a/src/libEGL/Display.h b/src/libEGL/Display.h
index 8b85efd..4d4f4db 100644
--- a/src/libEGL/Display.h
+++ b/src/libEGL/Display.h
@@ -68,6 +68,9 @@
private:
DISALLOW_COPY_AND_ASSIGN(Display);
+
+ D3DPRESENT_PARAMETERS getPresentParameters();
+
const HDC mDc;
HMODULE mD3d9Module;
diff --git a/src/libEGL/Surface.cpp b/src/libEGL/Surface.cpp
index a5638d4..2dd608e 100644
--- a/src/libEGL/Surface.cpp
+++ b/src/libEGL/Surface.cpp
@@ -37,39 +37,51 @@
Surface::~Surface()
{
+ release();
+}
+
+void Surface::release()
+{
if (mSwapChain)
{
mSwapChain->Release();
+ mSwapChain = NULL;
}
if (mBackBuffer)
{
mBackBuffer->Release();
+ mBackBuffer = NULL;
}
if (mRenderTarget)
{
mRenderTarget->Release();
+ mRenderTarget = NULL;
}
if (mDepthStencil)
{
mDepthStencil->Release();
+ mDepthStencil = NULL;
}
if (mFlipTexture)
{
mFlipTexture->Release();
+ mFlipTexture = NULL;
}
if (mFlipState)
{
mFlipState->Release();
+ mFlipState = NULL;
}
if (mPreFlipState)
{
mPreFlipState->Release();
+ mPreFlipState = NULL;
}
}
diff --git a/src/libEGL/Surface.h b/src/libEGL/Surface.h
index 5bc912c..ae13655 100644
--- a/src/libEGL/Surface.h
+++ b/src/libEGL/Surface.h
@@ -29,6 +29,9 @@
~Surface();
+ void release();
+ void resetSwapChain();
+
HWND getWindowHandle();
bool swap();
@@ -48,7 +51,6 @@
IDirect3DSurface9 *mDepthStencil;
IDirect3DTexture9 *mFlipTexture;
- void resetSwapChain();
bool checkForWindowResize();
void applyFlipState(IDirect3DDevice9 *device);
diff --git a/src/libEGL/libEGL.cpp b/src/libEGL/libEGL.cpp
index 5ceb6ef..aedc669 100644
--- a/src/libEGL/libEGL.cpp
+++ b/src/libEGL/libEGL.cpp
@@ -825,7 +825,7 @@
gl::Context *context = static_cast<gl::Context*>(ctx);
IDirect3DDevice9 *device = display->getDevice();
- if (!device || device->TestCooperativeLevel() != D3D_OK)
+ if (!device || FAILED(device->TestCooperativeLevel()))
{
return error(EGL_CONTEXT_LOST, EGL_FALSE);
}
diff --git a/src/libGLESv2/Blit.cpp b/src/libGLESv2/Blit.cpp
index 00c878f..e964865 100644
--- a/src/libGLESv2/Blit.cpp
+++ b/src/libGLESv2/Blit.cpp
@@ -382,6 +382,11 @@
IDirect3DTexture9 *Blit::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect)
{
+ if (!surface)
+ {
+ return NULL;
+ }
+
egl::Display *display = getDisplay();
IDirect3DDevice9 *device = getDevice();
diff --git a/src/libGLESv2/Context.cpp b/src/libGLESv2/Context.cpp
index b68f5f1..9c1ada4 100644
--- a/src/libGLESv2/Context.cpp
+++ b/src/libGLESv2/Context.cpp
@@ -303,7 +303,10 @@
setFramebufferZero(framebufferZero);
- defaultRenderTarget->Release();
+ if (defaultRenderTarget)
+ {
+ defaultRenderTarget->Release();
+ }
if (depthStencil)
{
@@ -1585,6 +1588,12 @@
}
IDirect3DSurface9 *renderTarget = framebufferObject->getRenderTarget();
+
+ if (!renderTarget)
+ {
+ return false; // Context must be lost
+ }
+
IDirect3DSurface9 *depthStencil = NULL;
unsigned int renderTargetSerial = framebufferObject->getRenderTargetSerial();
@@ -2098,6 +2107,12 @@
}
IDirect3DSurface9 *renderTarget = framebuffer->getRenderTarget();
+
+ if (!renderTarget)
+ {
+ return; // Context must be lost, return silently
+ }
+
IDirect3DDevice9 *device = getDevice();
D3DSURFACE_DESC desc;
@@ -2396,6 +2411,11 @@
IDirect3DSurface9 *renderTarget = framebufferObject->getRenderTarget();
+ if (!renderTarget)
+ {
+ return; // Context must be lost, return silently
+ }
+
D3DSURFACE_DESC desc;
renderTarget->GetDesc(&desc);