diff options
Diffstat (limited to 'Source/ThirdParty/ANGLE/src/libEGL/Surface.cpp')
-rw-r--r-- | Source/ThirdParty/ANGLE/src/libEGL/Surface.cpp | 266 |
1 files changed, 166 insertions, 100 deletions
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; +} } |