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: https://angleproject.googlecode.com/svn/trunk@406 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent d3bd0ad3
......@@ -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 @@ bool Display::initialize()
// 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 @@ bool Display::initialize()
return error(EGL_BAD_ALLOC, false);
}
ASSERT(SUCCEEDED(result));
if (mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(2, 0))
{
terminate();
......@@ -183,13 +186,6 @@ bool Display::initialize()
mConfigSet.mSet.insert(configuration);
}
if (!createDevice())
{
terminate();
return false;
}
}
if (!isInitialized())
......@@ -199,6 +195,11 @@ bool Display::initialize()
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::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value)
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 @@ Surface *Display::createWindowSurface(HWND window, EGLConfig config)
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 @@ void Display::destroyContext(gl::Context *context)
{
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 @@ DWORD Display::convertInterval(GLint interval)
IDirect3DDevice9 *Display::getDevice()
{
if (!mDevice)
{
if (!createDevice())
{
return NULL;
}
}
return mDevice;
}
......@@ -541,4 +571,26 @@ bool Display::getEventQuerySupport()
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
......@@ -68,6 +68,9 @@ class Display
private:
DISALLOW_COPY_AND_ASSIGN(Display);
D3DPRESENT_PARAMETERS getPresentParameters();
const HDC mDc;
HMODULE mD3d9Module;
......
......@@ -37,39 +37,51 @@ Surface::Surface(Display *display, const Config *config, HWND window)
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;
}
}
......
......@@ -29,6 +29,9 @@ class Surface
~Surface();
void release();
void resetSwapChain();
HWND getWindowHandle();
bool swap();
......@@ -48,7 +51,6 @@ class Surface
IDirect3DSurface9 *mDepthStencil;
IDirect3DTexture9 *mFlipTexture;
void resetSwapChain();
bool checkForWindowResize();
void applyFlipState(IDirect3DDevice9 *device);
......
......@@ -825,7 +825,7 @@ EGLBoolean __stdcall eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface
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);
}
......
......@@ -382,6 +382,11 @@ bool Blit::setFormatConvertShaders(GLenum destFormat)
IDirect3DTexture9 *Blit::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect)
{
if (!surface)
{
return NULL;
}
egl::Display *display = getDisplay();
IDirect3DDevice9 *device = getDevice();
......
......@@ -303,7 +303,10 @@ void Context::makeCurrent(egl::Display *display, egl::Surface *surface)
setFramebufferZero(framebufferZero);
defaultRenderTarget->Release();
if (defaultRenderTarget)
{
defaultRenderTarget->Release();
}
if (depthStencil)
{
......@@ -1585,6 +1588,12 @@ bool Context::applyRenderTarget(bool ignoreViewport)
}
IDirect3DSurface9 *renderTarget = framebufferObject->getRenderTarget();
if (!renderTarget)
{
return false; // Context must be lost
}
IDirect3DSurface9 *depthStencil = NULL;
unsigned int renderTargetSerial = framebufferObject->getRenderTargetSerial();
......@@ -2098,6 +2107,12 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
}
IDirect3DSurface9 *renderTarget = framebuffer->getRenderTarget();
if (!renderTarget)
{
return; // Context must be lost, return silently
}
IDirect3DDevice9 *device = getDevice();
D3DSURFACE_DESC desc;
......@@ -2396,6 +2411,11 @@ void Context::clear(GLbitfield mask)
IDirect3DSurface9 *renderTarget = framebufferObject->getRenderTarget();
if (!renderTarget)
{
return; // Context must be lost, return silently
}
D3DSURFACE_DESC desc;
renderTarget->GetDesc(&desc);
......
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