diff options
Diffstat (limited to 'Source/ThirdParty/ANGLE/src/libEGL')
-rw-r--r-- | Source/ThirdParty/ANGLE/src/libEGL/Config.cpp | 7 | ||||
-rw-r--r-- | Source/ThirdParty/ANGLE/src/libEGL/Display.cpp | 301 | ||||
-rw-r--r-- | Source/ThirdParty/ANGLE/src/libEGL/Display.h | 19 | ||||
-rw-r--r-- | Source/ThirdParty/ANGLE/src/libEGL/Surface.cpp | 266 | ||||
-rw-r--r-- | Source/ThirdParty/ANGLE/src/libEGL/Surface.h | 19 | ||||
-rw-r--r-- | Source/ThirdParty/ANGLE/src/libEGL/libEGL.cpp | 35 |
6 files changed, 462 insertions, 185 deletions
diff --git a/Source/ThirdParty/ANGLE/src/libEGL/Config.cpp b/Source/ThirdParty/ANGLE/src/libEGL/Config.cpp index 21d4661..284f61d 100644 --- a/Source/ThirdParty/ANGLE/src/libEGL/Config.cpp +++ b/Source/ThirdParty/ANGLE/src/libEGL/Config.cpp @@ -94,13 +94,6 @@ void Config::set(D3DDISPLAYMODE displayMode, EGLint minInterval, EGLint maxInter mBlueSize = 5; mAlphaSize = 0; break; - case D3DFMT_X1R5G5B5: - mBufferSize = 16; - mRedSize = 5; - mGreenSize = 5; - mBlueSize = 5; - mAlphaSize = 0; - break; case D3DFMT_X8R8G8B8: mBufferSize = 32; mRedSize = 8; diff --git a/Source/ThirdParty/ANGLE/src/libEGL/Display.cpp b/Source/ThirdParty/ANGLE/src/libEGL/Display.cpp index e2802da..6f1a335 100644 --- a/Source/ThirdParty/ANGLE/src/libEGL/Display.cpp +++ b/Source/ThirdParty/ANGLE/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 { @@ -40,7 +41,6 @@ Display::Display(HDC deviceContext) : mDc(deviceContext) mMinSwapInterval = 1; mMaxSwapInterval = 1; - setSwapInterval(1); } Display::~Display() @@ -77,7 +77,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)); @@ -95,11 +95,26 @@ bool Display::initialize() // UNIMPLEMENTED(); // FIXME: Determine which adapter index the device context corresponds to } - HRESULT result = mD3d9->GetDeviceCaps(mAdapter, mDeviceType, &mDeviceCaps); - - if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + HRESULT result; + + // Give up on getting device caps after about one second. + for (int i = 0; i < 10; ++i) { - return error(EGL_BAD_ALLOC, false); + result = mD3d9->GetDeviceCaps(mAdapter, mDeviceType, &mDeviceCaps); + + if (SUCCEEDED(result)) + { + break; + } + else if (result == D3DERR_NOTAVAILABLE) + { + Sleep(100); // 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 + { + terminate(); + return error(EGL_BAD_ALLOC, false); + } } if (mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(2, 0)) @@ -108,6 +123,14 @@ bool Display::initialize() return error(EGL_NOT_INITIALIZED, false); } + // When DirectX9 is running with an older DirectX8 driver, a StretchRect from a regular texture to a render target texture is not supported. + // This is required by Texture2D::convertToRenderTarget. + if ((mDeviceCaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) == 0) + { + terminate(); + return error(EGL_NOT_INITIALIZED, false); + } + mMinSwapInterval = 4; mMaxSwapInterval = 0; @@ -123,7 +146,7 @@ bool Display::initialize() // D3DFMT_A2R10G10B10, // The color_ramp conformance test uses ReadPixels with UNSIGNED_BYTE causing it to think that rendering skipped a colour value. D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, - D3DFMT_X1R5G5B5, + // D3DFMT_X1R5G5B5, // Has no compatible OpenGL ES renderbuffer format D3DFMT_X8R8G8B8 }; @@ -183,13 +206,6 @@ bool Display::initialize() mConfigSet.mSet.insert(configuration); } - - if (!createDevice()) - { - terminate(); - - return false; - } } if (!isInitialized()) @@ -199,23 +215,34 @@ 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; } void Display::terminate() { - for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) + while (!mSurfaceSet.empty()) { - delete *surface; + destroySurface(*mSurfaceSet.begin()); } - for (ContextSet::iterator context = mContextSet.begin(); context != mContextSet.end(); context++) + while (!mContextSet.empty()) { - glDestroyContext(*context); + destroyContext(*mContextSet.begin()); } 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 = NULL; } @@ -314,33 +341,12 @@ 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 = getDefaultPresentParameters(); DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES; HRESULT result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice); - if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DEVICELOST) { return error(EGL_BAD_ALLOC, false); } @@ -349,14 +355,13 @@ bool Display::createDevice() { result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParameters, &mDevice); - if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + if (FAILED(result)) { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_NOTAVAILABLE || result == D3DERR_DEVICELOST); return error(EGL_BAD_ALLOC, false); } } - ASSERT(SUCCEEDED(result)); - // Permanent non-default states mDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE); @@ -365,6 +370,29 @@ bool Display::createDevice() 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) { const Config *configuration = mConfigSet.get(config); @@ -377,6 +405,27 @@ 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 + { + if (!resetDevice()) + { + return NULL; + } + + // 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 +444,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() @@ -430,37 +487,26 @@ bool Display::hasExistingWindowSurface(HWND window) return false; } -void Display::setSwapInterval(GLint interval) +EGLint Display::getMinSwapInterval() { - mSwapInterval = interval; - mSwapInterval = std::max(mSwapInterval, mMinSwapInterval); - mSwapInterval = std::min(mSwapInterval, mMaxSwapInterval); - - mPresentInterval = convertInterval(mSwapInterval); + return mMinSwapInterval; } -DWORD Display::getPresentInterval() +EGLint Display::getMaxSwapInterval() { - return mPresentInterval; + return mMaxSwapInterval; } -DWORD Display::convertInterval(GLint interval) +IDirect3DDevice9 *Display::getDevice() { - switch(interval) + if (!mDevice) { - case 0: return D3DPRESENT_INTERVAL_IMMEDIATE; - case 1: return D3DPRESENT_INTERVAL_ONE; - case 2: return D3DPRESENT_INTERVAL_TWO; - case 3: return D3DPRESENT_INTERVAL_THREE; - case 4: return D3DPRESENT_INTERVAL_FOUR; - default: UNREACHABLE(); + if (!createDevice()) + { + return NULL; + } } - return D3DPRESENT_INTERVAL_DEFAULT; -} - -IDirect3DDevice9 *Display::getDevice() -{ return mDevice; } @@ -487,4 +533,127 @@ bool Display::getCompressedTextureSupport() return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT1)); } + +bool Display::getFloatTextureSupport(bool *filtering, bool *renderable) +{ + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER, + D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) && + SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER, + D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F)); + + *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, + D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F))&& + SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, + D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F)); + + if (!filtering && !renderable) + { + return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, + D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) && + SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, + D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F)); + } + else + { + return true; + } +} + +bool Display::getHalfFloatTextureSupport(bool *filtering, bool *renderable) +{ + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER, + D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) && + SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER, + D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F)); + + *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, + D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) && + SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, + D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F)); + + if (!filtering && !renderable) + { + return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, + D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) && + SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, + D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F)); + } + else + { + return true; + } +} + +bool Display::getLuminanceTextureSupport() +{ + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_L8)); +} + +bool Display::getLuminanceAlphaTextureSupport() +{ + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_A8L8)); +} + +D3DPOOL Display::getBufferPool(DWORD usage) const +{ + if (mD3d9ex != NULL) + { + return D3DPOOL_DEFAULT; + } + else + { + if (!(usage & D3DUSAGE_DYNAMIC)) + { + return D3DPOOL_MANAGED; + } + } + + return D3DPOOL_DEFAULT; +} + +bool Display::getEventQuerySupport() +{ + IDirect3DQuery9 *query; + HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, &query); + if (SUCCEEDED(result)) + { + query->Release(); + } + + return result != D3DERR_NOTAVAILABLE; +} + +D3DPRESENT_PARAMETERS Display::getDefaultPresentParameters() +{ + 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 = D3DPRESENT_INTERVAL_DEFAULT; + presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD; + presentParameters.Windowed = TRUE; + + return presentParameters; } +}
\ No newline at end of file diff --git a/Source/ThirdParty/ANGLE/src/libEGL/Display.h b/Source/ThirdParty/ANGLE/src/libEGL/Display.h index bd33012..4b74e1e 100644 --- a/Source/ThirdParty/ANGLE/src/libEGL/Display.h +++ b/Source/ThirdParty/ANGLE/src/libEGL/Display.h @@ -54,17 +54,25 @@ class Display bool isValidSurface(egl::Surface *surface); bool hasExistingWindowSurface(HWND window); - void setSwapInterval(GLint interval); - DWORD getPresentInterval(); - static DWORD convertInterval(GLint interval); + EGLint getMinSwapInterval(); + EGLint getMaxSwapInterval(); virtual IDirect3DDevice9 *getDevice(); virtual D3DCAPS9 getDeviceCaps(); virtual void getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray); virtual bool getCompressedTextureSupport(); + virtual bool getEventQuerySupport(); + virtual bool getFloatTextureSupport(bool *filtering, bool *renderable); + virtual bool getHalfFloatTextureSupport(bool *filtering, bool *renderable); + virtual bool getLuminanceTextureSupport(); + virtual bool getLuminanceAlphaTextureSupport(); + virtual D3DPOOL getBufferPool(DWORD usage) const; private: DISALLOW_COPY_AND_ASSIGN(Display); + + D3DPRESENT_PARAMETERS getDefaultPresentParameters(); + const HDC mDc; HMODULE mD3d9Module; @@ -78,11 +86,9 @@ class Display HWND mDeviceWindow; bool mSceneStarted; - GLint mSwapInterval; EGLint mMaxSwapInterval; EGLint mMinSwapInterval; - DWORD mPresentInterval; - + typedef std::set<Surface*> SurfaceSet; SurfaceSet mSurfaceSet; @@ -92,6 +98,7 @@ class Display ContextSet mContextSet; bool createDevice(); + bool resetDevice(); }; } diff --git a/Source/ThirdParty/ANGLE/src/libEGL/Surface.cpp b/Source/ThirdParty/ANGLE/src/libEGL/Surface.cpp index a5638d4..2736a7f 100644 --- a/Source/ThirdParty/ANGLE/src/libEGL/Surface.cpp +++ b/Source/ThirdParty/ANGLE/src/libEGL/Surface.cpp @@ -8,6 +8,8 @@ // such as the client area of a window, including any back buffers. // Implements EGLSurface and related functionality. [EGL 1.4] section 2.2 page 3. +#include <tchar.h> + #include "libEGL/Surface.h" #include "common/debug.h" @@ -23,7 +25,6 @@ Surface::Surface(Display *display, const Config *config, HWND window) mSwapChain = NULL; mDepthStencil = NULL; mBackBuffer = NULL; - mRenderTarget = NULL; mFlipTexture = NULL; mFlipState = NULL; mPreFlipState = NULL; @@ -31,52 +32,86 @@ Surface::Surface(Display *display, const Config *config, HWND window) mPixelAspectRatio = (EGLint)(1.0 * EGL_DISPLAY_SCALING); // FIXME: Determine actual pixel aspect ratio mRenderBuffer = EGL_BACK_BUFFER; mSwapBehavior = EGL_BUFFER_PRESERVED; + mSwapInterval = -1; + setSwapInterval(1); + subclassWindow(); resetSwapChain(); } Surface::~Surface() { + unsubclassWindow(); + release(); +} + +void Surface::release() +{ if (mSwapChain) { mSwapChain->Release(); + mSwapChain = NULL; } if (mBackBuffer) { mBackBuffer->Release(); - } - - if (mRenderTarget) - { - mRenderTarget->Release(); + mBackBuffer = 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; } } void Surface::resetSwapChain() { + RECT windowRect; + if (!GetClientRect(getWindowHandle(), &windowRect)) + { + ASSERT(false); + + ERR("Could not retrieve the window dimensions"); + return; + } + + resetSwapChain(windowRect.right - windowRect.left, windowRect.bottom - windowRect.top); +} + +void Surface::resetSwapChain(int backbufferWidth, int backbufferHeight) +{ IDirect3DDevice9 *device = mDisplay->getDevice(); + if (device == NULL) + { + return; + } + + // Evict all non-render target textures to system memory and release all resources + // before reallocating them to free up as much video memory as possible. + device->EvictManagedResources(); + release(); + D3DPRESENT_PARAMETERS presentParameters = {0}; presentParameters.AutoDepthStencilFormat = mConfig->mDepthStencilFormat; @@ -87,96 +122,57 @@ void Surface::resetSwapChain() presentParameters.hDeviceWindow = getWindowHandle(); presentParameters.MultiSampleQuality = 0; // FIXME: Unimplemented presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; // FIXME: Unimplemented - presentParameters.PresentationInterval = Display::convertInterval(mConfig->mMinSwapInterval); + presentParameters.PresentationInterval = mPresentInterval; presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD; presentParameters.Windowed = TRUE; + presentParameters.BackBufferWidth = backbufferWidth; + presentParameters.BackBufferHeight = backbufferHeight; - RECT windowRect; - if (!GetClientRect(getWindowHandle(), &windowRect)) - { - ASSERT(false); - return; - } - - presentParameters.BackBufferWidth = windowRect.right - windowRect.left; - presentParameters.BackBufferHeight = windowRect.bottom - windowRect.top; - - IDirect3DSwapChain9 *swapChain = NULL; - HRESULT result = device->CreateAdditionalSwapChain(&presentParameters, &swapChain); + HRESULT result = device->CreateAdditionalSwapChain(&presentParameters, &mSwapChain); if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); ERR("Could not create additional swap chains: %08lX", result); + release(); return error(EGL_BAD_ALLOC); } - IDirect3DSurface9 *depthStencilSurface = NULL; result = device->CreateDepthStencilSurface(presentParameters.BackBufferWidth, presentParameters.BackBufferHeight, presentParameters.AutoDepthStencilFormat, presentParameters.MultiSampleType, - presentParameters.MultiSampleQuality, FALSE, &depthStencilSurface, NULL); + presentParameters.MultiSampleQuality, FALSE, &mDepthStencil, NULL); if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - swapChain->Release(); - ERR("Could not create depthstencil surface for new swap chain: %08lX", result); - return error(EGL_BAD_ALLOC); - } - - IDirect3DSurface9 *renderTarget = NULL; - result = device->CreateRenderTarget(presentParameters.BackBufferWidth, presentParameters.BackBufferHeight, presentParameters.BackBufferFormat, - presentParameters.MultiSampleType, presentParameters.MultiSampleQuality, FALSE, &renderTarget, NULL); - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - - swapChain->Release(); - depthStencilSurface->Release(); - - ERR("Could not create render target surface for new swap chain: %08lX", result); + release(); return error(EGL_BAD_ALLOC); } ASSERT(SUCCEEDED(result)); - IDirect3DTexture9 *flipTexture = NULL; result = device->CreateTexture(presentParameters.BackBufferWidth, presentParameters.BackBufferHeight, 1, D3DUSAGE_RENDERTARGET, - presentParameters.BackBufferFormat, D3DPOOL_DEFAULT, &flipTexture, NULL); + presentParameters.BackBufferFormat, D3DPOOL_DEFAULT, &mFlipTexture, NULL); if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - swapChain->Release(); - depthStencilSurface->Release(); - renderTarget->Release(); - ERR("Could not create flip texture for new swap chain: %08lX", result); + release(); return error(EGL_BAD_ALLOC); } - IDirect3DSurface9 *backBuffer = NULL; - swapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &backBuffer); - - if (mSwapChain) mSwapChain->Release(); - if (mDepthStencil) mDepthStencil->Release(); - if (mBackBuffer) mBackBuffer->Release(); - if (mRenderTarget) mRenderTarget->Release(); - if (mFlipTexture) mFlipTexture->Release(); - + mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer); mWidth = presentParameters.BackBufferWidth; mHeight = presentParameters.BackBufferHeight; - mSwapChain = swapChain; - mDepthStencil = depthStencilSurface; - mBackBuffer = backBuffer; - mRenderTarget = renderTarget; - mFlipTexture = flipTexture; + mPresentIntervalDirty = false; + + InvalidateRect(mWindow, NULL, FALSE); // The flip state block recorded mFlipTexture so it is now invalid. releaseRecordedState(device); @@ -199,6 +195,7 @@ void Surface::writeRecordableFlipState(IDirect3DDevice9 *device) device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE); + device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); device->SetPixelShader(NULL); device->SetVertexShader(NULL); @@ -206,7 +203,7 @@ void Surface::writeRecordableFlipState(IDirect3DDevice9 *device) device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); - device->SetTexture(0, NULL); // The actual texture will change after resizing. But the pre-flip state block must save/restore the texture. + device->SetTexture(0, NULL); // The actual texture will change after resizing. But the pre-flip state block must save/restore the texture. device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); device->SetSamplerState(0, D3DSAMP_SRGBTEXTURE, FALSE); @@ -214,7 +211,10 @@ void Surface::writeRecordableFlipState(IDirect3DDevice9 *device) device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); - device->SetStreamSourceFreq(0, 1); // DrawPrimitiveUP only cares about stream 0, not the rest. + RECT scissorRect = {0}; // Scissoring is disabled for flipping, but we need this to capture and restore the old rectangle + device->SetScissorRect(&scissorRect); + D3DVIEWPORT9 viewport = {0, 0, mWidth, mHeight, 0.0f, 1.0f}; + device->SetViewport(&viewport); } void Surface::applyFlipState(IDirect3DDevice9 *device) @@ -275,8 +275,6 @@ void Surface::applyFlipState(IDirect3DDevice9 *device) void Surface::restoreState(IDirect3DDevice9 *device) { - mPreFlipState->Apply(); - device->SetRenderTarget(0, mPreFlipBackBuffer); device->SetDepthStencilSurface(mPreFlipDepthStencil); @@ -291,6 +289,8 @@ void Surface::restoreState(IDirect3DDevice9 *device) mPreFlipDepthStencil->Release(); mPreFlipDepthStencil = NULL; } + + mPreFlipState->Apply(); } // On the next flip, this will cause the state to be recorded from scratch. @@ -309,8 +309,58 @@ void Surface::releaseRecordedState(IDirect3DDevice9 *device) mPreFlipState = NULL; } } +#define kSurfaceProperty _TEXT("Egl::SurfaceOwner") +#define kParentWndProc _TEXT("Egl::SurfaceParentWndProc") + +static LRESULT CALLBACK SurfaceWindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { + if (message == WM_SIZE) { + Surface* surf = reinterpret_cast<Surface*>(GetProp(hwnd, kSurfaceProperty)); + if(surf) { + surf->checkForOutOfDateSwapChain(); + } + } + WNDPROC prevWndFunc = reinterpret_cast<WNDPROC >(GetProp(hwnd, kParentWndProc)); + return CallWindowProc(prevWndFunc, hwnd, message, wparam, lparam); +} -bool Surface::checkForWindowResize() +void Surface::subclassWindow() +{ + SetLastError(0); + LONG oldWndProc = SetWindowLong(mWindow, GWL_WNDPROC, reinterpret_cast<LONG>(SurfaceWindowProc)); + if(oldWndProc == 0 && GetLastError() != ERROR_SUCCESS) { + mWindowSubclassed = false; + return; + } + + SetProp(mWindow, kSurfaceProperty, reinterpret_cast<HANDLE>(this)); + SetProp(mWindow, kParentWndProc, reinterpret_cast<HANDLE>(oldWndProc)); + mWindowSubclassed = true; +} + +void Surface::unsubclassWindow() +{ + if(!mWindowSubclassed) + return; + + // un-subclass + LONG parentWndFunc = reinterpret_cast<LONG>(GetProp(mWindow, kParentWndProc)); + + // Check the windowproc is still SurfaceWindowProc. + // If this assert fails, then it is likely the application has subclassed the + // hwnd as well and did not unsubclass before destroying its EGL context. The + // application should be modified to either subclass before initializing the + // EGL context, or to unsubclass before destroying the EGL context. + if(parentWndFunc) { + LONG prevWndFunc = SetWindowLong(mWindow, GWL_WNDPROC, parentWndFunc); + ASSERT(prevWndFunc == reinterpret_cast<LONG>(SurfaceWindowProc)); + } + + RemoveProp(mWindow, kSurfaceProperty); + RemoveProp(mWindow, kParentWndProc); + mWindowSubclassed = false; +} + +bool Surface::checkForOutOfDateSwapChain() { RECT client; if (!GetClientRect(getWindowHandle(), &client)) @@ -319,10 +369,14 @@ bool Surface::checkForWindowResize() return false; } - if (getWidth() != client.right - client.left || getHeight() != client.bottom - client.top) - { - resetSwapChain(); + // Grow the buffer now, if the window has grown. We need to grow now to avoid losing information. + int clientWidth = client.right - client.left; + int clientHeight = client.bottom - client.top; + bool sizeDirty = clientWidth != getWidth() || clientHeight != getHeight(); + if (sizeDirty || mPresentIntervalDirty) + { + resetSwapChain(clientWidth, clientHeight); if (static_cast<egl::Surface*>(getCurrentDrawSurface()) == this) { glMakeCurrent(glGetCurrentContext(), static_cast<egl::Display*>(getCurrentDisplay()), this); @@ -330,57 +384,51 @@ bool Surface::checkForWindowResize() return true; } - return false; } -bool Surface::swap() +DWORD Surface::convertInterval(EGLint interval) { - if (mSwapChain) + switch(interval) { - IDirect3DTexture9 *flipTexture = mFlipTexture; - flipTexture->AddRef(); - - IDirect3DSurface9 *renderTarget = mRenderTarget; - renderTarget->AddRef(); + case 0: return D3DPRESENT_INTERVAL_IMMEDIATE; + case 1: return D3DPRESENT_INTERVAL_ONE; + case 2: return D3DPRESENT_INTERVAL_TWO; + case 3: return D3DPRESENT_INTERVAL_THREE; + case 4: return D3DPRESENT_INTERVAL_FOUR; + default: UNREACHABLE(); + } - EGLint oldWidth = mWidth; - EGLint oldHeight = mHeight; + return D3DPRESENT_INTERVAL_DEFAULT; +} - checkForWindowResize(); +bool Surface::swap() +{ + if (mSwapChain) + { IDirect3DDevice9 *device = mDisplay->getDevice(); - IDirect3DSurface9 *textureSurface; - flipTexture->GetSurfaceLevel(0, &textureSurface); - - mDisplay->endScene(); - device->StretchRect(renderTarget, NULL, textureSurface, NULL, D3DTEXF_NONE); - renderTarget->Release(); - applyFlipState(device); - device->SetTexture(0, flipTexture); - - float xscale = (float)mWidth / oldWidth; - float yscale = (float)mHeight / oldHeight; + device->SetTexture(0, mFlipTexture); // Render the texture upside down into the back buffer - // Texcoords are chosen to pin a potentially resized image into the upper-left corner without scaling. - float quad[4][6] = {{ 0 - 0.5f, 0 - 0.5f, 0.0f, 1.0f, 0.0f, 1.0f }, - {mWidth - 0.5f, 0 - 0.5f, 0.0f, 1.0f, xscale, 1.0f }, - {mWidth - 0.5f, mHeight - 0.5f, 0.0f, 1.0f, xscale, 1.0f-yscale}, - { 0 - 0.5f, mHeight - 0.5f, 0.0f, 1.0f, 0.0f, 1.0f-yscale}}; // x, y, z, rhw, u, v + // Texcoords are chosen to flip the renderTarget about its Y axis. + float w = static_cast<float>(getWidth()); + float h = static_cast<float>(getHeight()); + float quad[4][6] = {{0 - 0.5f, 0 - 0.5f, 0.0f, 1.0f, 0.0f, 1.0f}, + {w - 0.5f, 0 - 0.5f, 0.0f, 1.0f, 1.0f, 1.0f}, + {w - 0.5f, h - 0.5f, 0.0f, 1.0f, 1.0f, 0.0f}, + {0 - 0.5f, h - 0.5f, 0.0f, 1.0f, 0.0f, 0.0f}}; // x, y, z, rhw, u, v mDisplay->startScene(); device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, 6 * sizeof(float)); - flipTexture->Release(); - textureSurface->Release(); - restoreState(device); mDisplay->endScene(); - HRESULT result = mSwapChain->Present(NULL, NULL, NULL, NULL, mDisplay->getPresentInterval()); + + HRESULT result = mSwapChain->Present(NULL, NULL, NULL, NULL, 0); if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DRIVERINTERNALERROR) { @@ -394,6 +442,7 @@ bool Surface::swap() ASSERT(SUCCEEDED(result)); + checkForOutOfDateSwapChain(); } return true; @@ -411,12 +460,14 @@ EGLint Surface::getHeight() const IDirect3DSurface9 *Surface::getRenderTarget() { - if (mRenderTarget) + IDirect3DSurface9 *textureSurface = NULL; + + if (mFlipTexture) { - mRenderTarget->AddRef(); + mFlipTexture->GetSurfaceLevel(0, &textureSurface); } - return mRenderTarget; + return textureSurface; } IDirect3DSurface9 *Surface::getDepthStencil() @@ -428,4 +479,19 @@ IDirect3DSurface9 *Surface::getDepthStencil() return mDepthStencil; } + +void Surface::setSwapInterval(EGLint interval) +{ + if (mSwapInterval == interval) + { + return; + } + + mSwapInterval = interval; + mSwapInterval = std::max(mSwapInterval, mDisplay->getMinSwapInterval()); + mSwapInterval = std::min(mSwapInterval, mDisplay->getMaxSwapInterval()); + + mPresentInterval = convertInterval(mSwapInterval); + mPresentIntervalDirty = true; +} } diff --git a/Source/ThirdParty/ANGLE/src/libEGL/Surface.h b/Source/ThirdParty/ANGLE/src/libEGL/Surface.h index 5bc912c..422d3d5 100644 --- a/Source/ThirdParty/ANGLE/src/libEGL/Surface.h +++ b/Source/ThirdParty/ANGLE/src/libEGL/Surface.h @@ -29,6 +29,9 @@ class Surface ~Surface(); + void release(); + void resetSwapChain(); + HWND getWindowHandle(); bool swap(); @@ -38,18 +41,22 @@ class Surface virtual IDirect3DSurface9 *getRenderTarget(); virtual IDirect3DSurface9 *getDepthStencil(); - private: + void setSwapInterval(EGLint interval); + bool checkForOutOfDateSwapChain(); // Returns true if swapchain changed due to resize or interval update + +private: DISALLOW_COPY_AND_ASSIGN(Surface); Display *const mDisplay; IDirect3DSwapChain9 *mSwapChain; IDirect3DSurface9 *mBackBuffer; - IDirect3DSurface9 *mRenderTarget; IDirect3DSurface9 *mDepthStencil; IDirect3DTexture9 *mFlipTexture; - void resetSwapChain(); - bool checkForWindowResize(); + void subclassWindow(); + void unsubclassWindow(); + void resetSwapChain(int backbufferWidth, int backbufferHeight); + static DWORD convertInterval(EGLint interval); void applyFlipState(IDirect3DDevice9 *device); void restoreState(IDirect3DDevice9 *device); @@ -61,6 +68,7 @@ class Surface IDirect3DSurface9 *mPreFlipDepthStencil; const HWND mWindow; // Window that the surface is created for. + bool mWindowSubclassed; // Indicates whether we successfully subclassed mWindow for WM_RESIZE hooking const egl::Config *mConfig; // EGL config surface was created with EGLint mHeight; // Height of surface EGLint mWidth; // Width of surface @@ -77,6 +85,9 @@ class Surface // EGLenum textureTarget; // Type of texture: 2D or no texture // EGLenum vgAlphaFormat; // Alpha format for OpenVG // EGLenum vgColorSpace; // Color space for OpenVG + EGLint mSwapInterval; + DWORD mPresentInterval; + bool mPresentIntervalDirty; }; } diff --git a/Source/ThirdParty/ANGLE/src/libEGL/libEGL.cpp b/Source/ThirdParty/ANGLE/src/libEGL/libEGL.cpp index 5ceb6ef..8dfe6e5 100644 --- a/Source/ThirdParty/ANGLE/src/libEGL/libEGL.cpp +++ b/Source/ThirdParty/ANGLE/src/libEGL/libEGL.cpp @@ -360,6 +360,8 @@ EGLSurface __stdcall eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EG default: return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); } + + attrib_list += 2; } } @@ -746,7 +748,14 @@ EGLBoolean __stdcall eglSwapInterval(EGLDisplay dpy, EGLint interval) return EGL_FALSE; } - display->setSwapInterval(interval); + egl::Surface *draw_surface = static_cast<egl::Surface*>(egl::getCurrentDrawSurface()); + + if (draw_surface == NULL) + { + return error(EGL_BAD_SURFACE, EGL_FALSE); + } + + draw_surface->setSwapInterval(interval); return success(EGL_TRUE); } @@ -765,6 +774,28 @@ EGLContext __stdcall eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLConte try { + // Get the requested client version (default is 1) and check it is two. + EGLint client_version = 1; + if (attrib_list) + { + for (const EGLint* attribute = attrib_list; attribute[0] != EGL_NONE; attribute += 2) + { + if (attribute[0] == EGL_CONTEXT_CLIENT_VERSION) + { + client_version = attribute[1]; + } + else + { + return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); + } + } + } + + if (client_version != 2) + { + return error(EGL_BAD_CONFIG, EGL_NO_CONTEXT); + } + egl::Display *display = static_cast<egl::Display*>(dpy); if (!validate(display, config)) @@ -825,7 +856,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); } |