Commit a6e31e58 by nduca@chromium.org

Resize surface on receipt of WM_SIZE to avoid corruption during resize. We hook…

Resize surface on receipt of WM_SIZE to avoid corruption during resize. We hook WM_SIZE using window subclassing. This is a continuation of http://codereview.appspot.com/3038042/ Review URL: http://codereview.appspot.com/3122041 git-svn-id: https://angleproject.googlecode.com/svn/trunk@486 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent 3a053f26
...@@ -40,6 +40,16 @@ LRESULT WINAPI ESWindowProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ...@@ -40,6 +40,16 @@ LRESULT WINAPI ESWindowProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam
case WM_CREATE: case WM_CREATE:
break; break;
case WM_SIZE:
{
ESContext *esContext = (ESContext*)(LONG_PTR) GetWindowLongPtr ( hWnd, GWL_USERDATA );
if ( esContext ) {
esContext->width = LOWORD( lParam );
esContext->height = HIWORD( lParam );
InvalidateRect( esContext->hWnd, NULL, FALSE );
}
}
case WM_PAINT: case WM_PAINT:
{ {
ESContext *esContext = (ESContext*)(LONG_PTR) GetWindowLongPtr ( hWnd, GWL_USERDATA ); ESContext *esContext = (ESContext*)(LONG_PTR) GetWindowLongPtr ( hWnd, GWL_USERDATA );
...@@ -47,7 +57,8 @@ LRESULT WINAPI ESWindowProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ...@@ -47,7 +57,8 @@ LRESULT WINAPI ESWindowProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam
if ( esContext && esContext->drawFunc ) if ( esContext && esContext->drawFunc )
esContext->drawFunc ( esContext ); esContext->drawFunc ( esContext );
ValidateRect( esContext->hWnd, NULL ); if ( esContext )
ValidateRect( esContext->hWnd, NULL );
} }
break; break;
...@@ -103,7 +114,7 @@ GLboolean WinCreate ( ESContext *esContext, LPCTSTR title ) ...@@ -103,7 +114,7 @@ GLboolean WinCreate ( ESContext *esContext, LPCTSTR title )
if (!RegisterClass (&wndclass) ) if (!RegisterClass (&wndclass) )
return FALSE; return FALSE;
wStyle = WS_VISIBLE | WS_POPUP | WS_BORDER | WS_SYSMENU | WS_CAPTION; wStyle = WS_VISIBLE | WS_POPUP | WS_BORDER | WS_SYSMENU | WS_CAPTION | WS_SIZEBOX;
// Adjust the window rectangle so that the client area has // Adjust the window rectangle so that the client area has
// the correct number of pixels // the correct number of pixels
......
...@@ -34,11 +34,13 @@ Surface::Surface(Display *display, const Config *config, HWND window) ...@@ -34,11 +34,13 @@ Surface::Surface(Display *display, const Config *config, HWND window)
mSwapInterval = -1; mSwapInterval = -1;
setSwapInterval(1); setSwapInterval(1);
subclassWindow();
resetSwapChain(); resetSwapChain();
} }
Surface::~Surface() Surface::~Surface()
{ {
unsubclassWindow();
release(); release();
} }
...@@ -89,6 +91,18 @@ void Surface::release() ...@@ -89,6 +91,18 @@ void Surface::release()
void Surface::resetSwapChain() void Surface::resetSwapChain()
{ {
RECT windowRect;
if (!GetClientRect(getWindowHandle(), &windowRect))
{
ASSERT(false);
return;
}
resetSwapChain(windowRect.right - windowRect.left, windowRect.bottom - windowRect.top);
}
void Surface::resetSwapChain(int backbufferWidth, int backbufferHeight)
{
IDirect3DDevice9 *device = mDisplay->getDevice(); IDirect3DDevice9 *device = mDisplay->getDevice();
if (device == NULL) if (device == NULL)
...@@ -109,16 +123,8 @@ void Surface::resetSwapChain() ...@@ -109,16 +123,8 @@ void Surface::resetSwapChain()
presentParameters.PresentationInterval = mPresentInterval; presentParameters.PresentationInterval = mPresentInterval;
presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD; presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
presentParameters.Windowed = TRUE; presentParameters.Windowed = TRUE;
presentParameters.BackBufferWidth = backbufferWidth;
RECT windowRect; presentParameters.BackBufferHeight = backbufferHeight;
if (!GetClientRect(getWindowHandle(), &windowRect))
{
ASSERT(false);
return;
}
presentParameters.BackBufferWidth = windowRect.right - windowRect.left;
presentParameters.BackBufferHeight = windowRect.bottom - windowRect.top;
IDirect3DSwapChain9 *swapChain = NULL; IDirect3DSwapChain9 *swapChain = NULL;
HRESULT result = device->CreateAdditionalSwapChain(&presentParameters, &swapChain); HRESULT result = device->CreateAdditionalSwapChain(&presentParameters, &swapChain);
...@@ -199,6 +205,8 @@ void Surface::resetSwapChain() ...@@ -199,6 +205,8 @@ void Surface::resetSwapChain()
mPresentIntervalDirty = false; mPresentIntervalDirty = false;
InvalidateRect(mWindow, NULL, FALSE);
// The flip state block recorded mFlipTexture so it is now invalid. // The flip state block recorded mFlipTexture so it is now invalid.
releaseRecordedState(device); releaseRecordedState(device);
} }
...@@ -336,6 +344,52 @@ void Surface::releaseRecordedState(IDirect3DDevice9 *device) ...@@ -336,6 +344,52 @@ void Surface::releaseRecordedState(IDirect3DDevice9 *device)
mPreFlipState = NULL; mPreFlipState = NULL;
} }
} }
#define kSurfaceProperty L"Egl::SurfaceOwner"
#define kParentWndProc L"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);
}
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;
// 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.
ASSERT(GetWindowLong(mWindow, GWL_WNDPROC) == reinterpret_cast<LONG>(SurfaceWindowProc));
// un-subclass
LONG prevWndFunc = reinterpret_cast<LONG>(GetProp(mWindow, kParentWndProc));
SetWindowLong(mWindow, GWL_WNDPROC, prevWndFunc);
RemoveProp(mWindow, kSurfaceProperty);
RemoveProp(mWindow, kParentWndProc);
mWindowSubclassed = false;
}
bool Surface::checkForOutOfDateSwapChain() bool Surface::checkForOutOfDateSwapChain()
{ {
...@@ -346,10 +400,14 @@ bool Surface::checkForOutOfDateSwapChain() ...@@ -346,10 +400,14 @@ bool Surface::checkForOutOfDateSwapChain()
return false; return false;
} }
if (getWidth() != client.right - client.left || getHeight() != client.bottom - client.top || mPresentIntervalDirty) // Grow the buffer now, if the window has grown. We need to grow now to avoid losing information.
{ int clientWidth = client.right - client.left;
resetSwapChain(); 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) if (static_cast<egl::Surface*>(getCurrentDrawSurface()) == this)
{ {
glMakeCurrent(glGetCurrentContext(), static_cast<egl::Display*>(getCurrentDisplay()), this); glMakeCurrent(glGetCurrentContext(), static_cast<egl::Display*>(getCurrentDisplay()), this);
...@@ -357,7 +415,6 @@ bool Surface::checkForOutOfDateSwapChain() ...@@ -357,7 +415,6 @@ bool Surface::checkForOutOfDateSwapChain()
return true; return true;
} }
return false; return false;
} }
...@@ -387,11 +444,6 @@ bool Surface::swap() ...@@ -387,11 +444,6 @@ bool Surface::swap()
IDirect3DSurface9 *renderTarget = mRenderTarget; IDirect3DSurface9 *renderTarget = mRenderTarget;
renderTarget->AddRef(); renderTarget->AddRef();
EGLint oldWidth = mWidth;
EGLint oldHeight = mHeight;
checkForOutOfDateSwapChain();
IDirect3DDevice9 *device = mDisplay->getDevice(); IDirect3DDevice9 *device = mDisplay->getDevice();
IDirect3DSurface9 *textureSurface; IDirect3DSurface9 *textureSurface;
...@@ -404,25 +456,26 @@ bool Surface::swap() ...@@ -404,25 +456,26 @@ bool Surface::swap()
applyFlipState(device); applyFlipState(device);
device->SetTexture(0, flipTexture); device->SetTexture(0, flipTexture);
float xscale = (float)mWidth / oldWidth;
float yscale = (float)mHeight / oldHeight;
// Render the texture upside down into the back buffer // 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. // Texcoords are chosen to flip the renderTarget about its Y axis.
float quad[4][6] = {{ 0 - 0.5f, 0 - 0.5f, 0.0f, 1.0f, 0.0f, 1.0f }, float w = static_cast<float>(getWidth());
{mWidth - 0.5f, 0 - 0.5f, 0.0f, 1.0f, xscale, 1.0f }, float h = static_cast<float>(getHeight());
{mWidth - 0.5f, mHeight - 0.5f, 0.0f, 1.0f, xscale, 1.0f-yscale}, float quad[4][6] = {{0 - 0.5f, 0 - 0.5f, 0.0f, 1.0f, 0.0f, 1.0f},
{ 0 - 0.5f, mHeight - 0.5f, 0.0f, 1.0f, 0.0f, 1.0f-yscale}}; // x, y, z, rhw, u, v {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(); mDisplay->startScene();
device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, 6 * sizeof(float)); device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, 6 * sizeof(float));
flipTexture->Release(); flipTexture->Release();
textureSurface->Release(); textureSurface->Release();
restoreState(device); restoreState(device);
mDisplay->endScene(); mDisplay->endScene();
HRESULT result = mSwapChain->Present(NULL, NULL, NULL, NULL, 0); HRESULT result = mSwapChain->Present(NULL, NULL, NULL, NULL, 0);
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DRIVERINTERNALERROR) if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DRIVERINTERNALERROR)
...@@ -437,6 +490,7 @@ bool Surface::swap() ...@@ -437,6 +490,7 @@ bool Surface::swap()
ASSERT(SUCCEEDED(result)); ASSERT(SUCCEEDED(result));
checkForOutOfDateSwapChain();
} }
return true; return true;
......
...@@ -42,8 +42,8 @@ class Surface ...@@ -42,8 +42,8 @@ class Surface
virtual IDirect3DSurface9 *getDepthStencil(); virtual IDirect3DSurface9 *getDepthStencil();
void setSwapInterval(EGLint interval); void setSwapInterval(EGLint interval);
bool checkForOutOfDateSwapChain(); // returns true if swapchain changed due to resize or interval update
private: private:
DISALLOW_COPY_AND_ASSIGN(Surface); DISALLOW_COPY_AND_ASSIGN(Surface);
Display *const mDisplay; Display *const mDisplay;
...@@ -53,8 +53,9 @@ class Surface ...@@ -53,8 +53,9 @@ class Surface
IDirect3DSurface9 *mDepthStencil; IDirect3DSurface9 *mDepthStencil;
IDirect3DTexture9 *mFlipTexture; IDirect3DTexture9 *mFlipTexture;
bool checkForOutOfDateSwapChain(); void subclassWindow();
void unsubclassWindow();
void resetSwapChain(int backbufferWidth, int backbufferHeight);
static DWORD convertInterval(EGLint interval); static DWORD convertInterval(EGLint interval);
void applyFlipState(IDirect3DDevice9 *device); void applyFlipState(IDirect3DDevice9 *device);
...@@ -67,6 +68,7 @@ class Surface ...@@ -67,6 +68,7 @@ class Surface
IDirect3DSurface9 *mPreFlipDepthStencil; IDirect3DSurface9 *mPreFlipDepthStencil;
const HWND mWindow; // Window that the surface is created for. 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 const egl::Config *mConfig; // EGL config surface was created with
EGLint mHeight; // Height of surface EGLint mHeight; // Height of surface
EGLint mWidth; // Width of surface EGLint mWidth; // Width of surface
......
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