зеркало из https://github.com/AvaloniaUI/angle.git
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
This commit is contained in:
Родитель
3a053f261e
Коммит
a6e31e58bb
|
@ -40,6 +40,16 @@ LRESULT WINAPI ESWindowProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam
|
|||
case WM_CREATE:
|
||||
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:
|
||||
{
|
||||
ESContext *esContext = (ESContext*)(LONG_PTR) GetWindowLongPtr ( hWnd, GWL_USERDATA );
|
||||
|
@ -47,7 +57,8 @@ LRESULT WINAPI ESWindowProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam
|
|||
if ( esContext && esContext->drawFunc )
|
||||
esContext->drawFunc ( esContext );
|
||||
|
||||
ValidateRect( esContext->hWnd, NULL );
|
||||
if ( esContext )
|
||||
ValidateRect( esContext->hWnd, NULL );
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -103,7 +114,7 @@ GLboolean WinCreate ( ESContext *esContext, LPCTSTR title )
|
|||
if (!RegisterClass (&wndclass) )
|
||||
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
|
||||
// the correct number of pixels
|
||||
|
|
|
@ -34,11 +34,13 @@ Surface::Surface(Display *display, const Config *config, HWND window)
|
|||
mSwapInterval = -1;
|
||||
setSwapInterval(1);
|
||||
|
||||
subclassWindow();
|
||||
resetSwapChain();
|
||||
}
|
||||
|
||||
Surface::~Surface()
|
||||
{
|
||||
unsubclassWindow();
|
||||
release();
|
||||
}
|
||||
|
||||
|
@ -88,6 +90,18 @@ void Surface::release()
|
|||
}
|
||||
|
||||
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();
|
||||
|
||||
|
@ -109,16 +123,8 @@ void Surface::resetSwapChain()
|
|||
presentParameters.PresentationInterval = mPresentInterval;
|
||||
presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
||||
presentParameters.Windowed = TRUE;
|
||||
|
||||
RECT windowRect;
|
||||
if (!GetClientRect(getWindowHandle(), &windowRect))
|
||||
{
|
||||
ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
presentParameters.BackBufferWidth = windowRect.right - windowRect.left;
|
||||
presentParameters.BackBufferHeight = windowRect.bottom - windowRect.top;
|
||||
presentParameters.BackBufferWidth = backbufferWidth;
|
||||
presentParameters.BackBufferHeight = backbufferHeight;
|
||||
|
||||
IDirect3DSwapChain9 *swapChain = NULL;
|
||||
HRESULT result = device->CreateAdditionalSwapChain(&presentParameters, &swapChain);
|
||||
|
@ -199,6 +205,8 @@ void Surface::resetSwapChain()
|
|||
|
||||
mPresentIntervalDirty = false;
|
||||
|
||||
InvalidateRect(mWindow, NULL, FALSE);
|
||||
|
||||
// The flip state block recorded mFlipTexture so it is now invalid.
|
||||
releaseRecordedState(device);
|
||||
}
|
||||
|
@ -336,6 +344,52 @@ void Surface::releaseRecordedState(IDirect3DDevice9 *device)
|
|||
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()
|
||||
{
|
||||
|
@ -346,10 +400,14 @@ bool Surface::checkForOutOfDateSwapChain()
|
|||
return false;
|
||||
}
|
||||
|
||||
if (getWidth() != client.right - client.left || getHeight() != client.bottom - client.top || mPresentIntervalDirty)
|
||||
{
|
||||
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);
|
||||
|
@ -357,7 +415,6 @@ bool Surface::checkForOutOfDateSwapChain()
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -387,11 +444,6 @@ bool Surface::swap()
|
|||
IDirect3DSurface9 *renderTarget = mRenderTarget;
|
||||
renderTarget->AddRef();
|
||||
|
||||
EGLint oldWidth = mWidth;
|
||||
EGLint oldHeight = mHeight;
|
||||
|
||||
checkForOutOfDateSwapChain();
|
||||
|
||||
IDirect3DDevice9 *device = mDisplay->getDevice();
|
||||
|
||||
IDirect3DSurface9 *textureSurface;
|
||||
|
@ -404,25 +456,26 @@ bool Surface::swap()
|
|||
applyFlipState(device);
|
||||
device->SetTexture(0, flipTexture);
|
||||
|
||||
float xscale = (float)mWidth / oldWidth;
|
||||
float yscale = (float)mHeight / oldHeight;
|
||||
|
||||
// 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, 0);
|
||||
|
||||
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DRIVERINTERNALERROR)
|
||||
|
@ -437,6 +490,7 @@ bool Surface::swap()
|
|||
|
||||
ASSERT(SUCCEEDED(result));
|
||||
|
||||
checkForOutOfDateSwapChain();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -42,8 +42,8 @@ class Surface
|
|||
virtual IDirect3DSurface9 *getDepthStencil();
|
||||
|
||||
void setSwapInterval(EGLint interval);
|
||||
|
||||
private:
|
||||
bool checkForOutOfDateSwapChain(); // returns true if swapchain changed due to resize or interval update
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(Surface);
|
||||
|
||||
Display *const mDisplay;
|
||||
|
@ -53,8 +53,9 @@ class Surface
|
|||
IDirect3DSurface9 *mDepthStencil;
|
||||
IDirect3DTexture9 *mFlipTexture;
|
||||
|
||||
bool checkForOutOfDateSwapChain();
|
||||
|
||||
void subclassWindow();
|
||||
void unsubclassWindow();
|
||||
void resetSwapChain(int backbufferWidth, int backbufferHeight);
|
||||
static DWORD convertInterval(EGLint interval);
|
||||
|
||||
void applyFlipState(IDirect3DDevice9 *device);
|
||||
|
@ -67,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
|
||||
|
|
Загрузка…
Ссылка в новой задаче