summaryrefslogtreecommitdiffstats
path: root/Source/ThirdParty/ANGLE/src/libEGL/Surface.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/ThirdParty/ANGLE/src/libEGL/Surface.cpp')
-rw-r--r--Source/ThirdParty/ANGLE/src/libEGL/Surface.cpp266
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;
+}
}