1a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block//
2a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block// Use of this source code is governed by a BSD-style license that can be
4a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block// found in the LICENSE file.
5a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block//
6a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
7a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block// Surface.cpp: Implements the egl::Surface class, representing a drawing surface
8a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block// such as the client area of a window, including any back buffers.
9a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block// Implements EGLSurface and related functionality. [EGL 1.4] section 2.2 page 3.
10a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
11ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch#include <tchar.h>
12ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch
13a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block#include "libEGL/Surface.h"
14a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
15a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block#include "common/debug.h"
16a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
17a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block#include "libEGL/main.h"
18a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block#include "libEGL/Display.h"
19a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
20a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Blocknamespace egl
21a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block{
225abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain MerrickSurface::Surface(Display *display, const Config *config, HWND window)
235abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    : mDisplay(display), mConfig(config), mWindow(window)
24a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block{
255abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    mSwapChain = NULL;
265abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    mDepthStencil = NULL;
27a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    mBackBuffer = NULL;
28a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    mFlipTexture = NULL;
29a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    mFlipState = NULL;
30a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    mPreFlipState = NULL;
31a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
32a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    mPixelAspectRatio = (EGLint)(1.0 * EGL_DISPLAY_SCALING);   // FIXME: Determine actual pixel aspect ratio
33a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    mRenderBuffer = EGL_BACK_BUFFER;
34a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    mSwapBehavior = EGL_BUFFER_PRESERVED;
35ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    mSwapInterval = -1;
36ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    setSwapInterval(1);
37a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
38ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    subclassWindow();
395abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    resetSwapChain();
40a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block}
41a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
42a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve BlockSurface::~Surface()
43a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block{
44ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    unsubclassWindow();
45ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    release();
46ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch}
47ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch
48ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdochvoid Surface::release()
49ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch{
50a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    if (mSwapChain)
51a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    {
52a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        mSwapChain->Release();
53ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        mSwapChain = NULL;
54a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    }
55a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
56a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    if (mBackBuffer)
57a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    {
58a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        mBackBuffer->Release();
59ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        mBackBuffer = NULL;
60a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    }
61a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
62a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    if (mDepthStencil)
63a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    {
64a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        mDepthStencil->Release();
65ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        mDepthStencil = NULL;
66a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    }
67a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
68a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    if (mFlipTexture)
69a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    {
70a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        mFlipTexture->Release();
71ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        mFlipTexture = NULL;
72a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    }
73a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
74a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    if (mFlipState)
75a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    {
76a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        mFlipState->Release();
77ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        mFlipState = NULL;
78a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    }
79a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
80a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    if (mPreFlipState)
81a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    {
82a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        mPreFlipState->Release();
83ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        mPreFlipState = NULL;
84a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    }
85a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block}
86a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
875abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrickvoid Surface::resetSwapChain()
88a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block{
89ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    RECT windowRect;
90ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    if (!GetClientRect(getWindowHandle(), &windowRect))
91ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    {
92ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        ASSERT(false);
93ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch
94ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        ERR("Could not retrieve the window dimensions");
95ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        return;
96ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    }
97ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch
98ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    resetSwapChain(windowRect.right - windowRect.left, windowRect.bottom - windowRect.top);
99ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch}
100ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch
101ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdochvoid Surface::resetSwapChain(int backbufferWidth, int backbufferHeight)
102ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch{
1035abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    IDirect3DDevice9 *device = mDisplay->getDevice();
1045abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
105ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    if (device == NULL)
106ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    {
107ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        return;
108ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    }
109ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch
110ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    // Evict all non-render target textures to system memory and release all resources
111ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    // before reallocating them to free up as much video memory as possible.
112ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    device->EvictManagedResources();
113ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    release();
114ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch
1155abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    D3DPRESENT_PARAMETERS presentParameters = {0};
1165abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
1175abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    presentParameters.AutoDepthStencilFormat = mConfig->mDepthStencilFormat;
1185abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    presentParameters.BackBufferCount = 1;
1195abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    presentParameters.BackBufferFormat = mConfig->mRenderTargetFormat;
1205abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    presentParameters.EnableAutoDepthStencil = FALSE;
1215abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    presentParameters.Flags = 0;
1225abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    presentParameters.hDeviceWindow = getWindowHandle();
1235abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    presentParameters.MultiSampleQuality = 0;                  // FIXME: Unimplemented
1245abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;   // FIXME: Unimplemented
125ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    presentParameters.PresentationInterval = mPresentInterval;
1265abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
1275abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    presentParameters.Windowed = TRUE;
128ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    presentParameters.BackBufferWidth = backbufferWidth;
129ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    presentParameters.BackBufferHeight = backbufferHeight;
1305abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
131ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    HRESULT result = device->CreateAdditionalSwapChain(&presentParameters, &mSwapChain);
1325abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
1335abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    if (FAILED(result))
1345abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    {
1355abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1365abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
1375abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        ERR("Could not create additional swap chains: %08lX", result);
138ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        release();
1395abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        return error(EGL_BAD_ALLOC);
1405abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    }
1415abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
1425abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    result = device->CreateDepthStencilSurface(presentParameters.BackBufferWidth, presentParameters.BackBufferHeight,
1435abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick                                               presentParameters.AutoDepthStencilFormat, presentParameters.MultiSampleType,
144ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch                                               presentParameters.MultiSampleQuality, FALSE, &mDepthStencil, NULL);
1455abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
1465abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    if (FAILED(result))
1475abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    {
1485abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1495abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
1505abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        ERR("Could not create depthstencil surface for new swap chain: %08lX", result);
151ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        release();
1525abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        return error(EGL_BAD_ALLOC);
1535abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    }
1545abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
1555abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    ASSERT(SUCCEEDED(result));
1565abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
1575abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    result = device->CreateTexture(presentParameters.BackBufferWidth, presentParameters.BackBufferHeight, 1, D3DUSAGE_RENDERTARGET,
158ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch                                   presentParameters.BackBufferFormat, D3DPOOL_DEFAULT, &mFlipTexture, NULL);
1595abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
1605abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    if (FAILED(result))
161a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    {
1625abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1635abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
1645abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        ERR("Could not create flip texture for new swap chain: %08lX", result);
165ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        release();
1665abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        return error(EGL_BAD_ALLOC);
167a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    }
168a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
169ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer);
1705abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    mWidth = presentParameters.BackBufferWidth;
1715abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    mHeight = presentParameters.BackBufferHeight;
1725abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
173ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    mPresentIntervalDirty = false;
174ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch
175ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    InvalidateRect(mWindow, NULL, FALSE);
1765abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
1775abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    // The flip state block recorded mFlipTexture so it is now invalid.
1785abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    releaseRecordedState(device);
1795abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick}
1805abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
1815abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain MerrickHWND Surface::getWindowHandle()
1825abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick{
1835abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    return mWindow;
184a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block}
185a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
1865abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrickvoid Surface::writeRecordableFlipState(IDirect3DDevice9 *device)
187a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block{
188a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    // Disable all pipeline operations
189a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
190a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
191a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
192a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
193a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
194a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
195a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
196a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED);
197a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE);
198ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
199a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    device->SetPixelShader(NULL);
200a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    device->SetVertexShader(NULL);
201a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
202a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    // Just sample the texture
203a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
204a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
205a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
206ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    device->SetTexture(0, NULL);   // The actual texture will change after resizing. But the pre-flip state block must save/restore the texture.
207a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
208a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
209a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    device->SetSamplerState(0, D3DSAMP_SRGBTEXTURE, FALSE);
2105abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
2115abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
212a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
213a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
214ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    RECT scissorRect = {0};   // Scissoring is disabled for flipping, but we need this to capture and restore the old rectangle
215ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    device->SetScissorRect(&scissorRect);
216ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    D3DVIEWPORT9 viewport = {0, 0, mWidth, mHeight, 0.0f, 1.0f};
217ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    device->SetViewport(&viewport);
218a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block}
219a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
2205abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrickvoid Surface::applyFlipState(IDirect3DDevice9 *device)
221a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block{
222a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    HRESULT hr;
223a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
224a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    if (mFlipState == NULL)
225a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    {
226a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        // Create two state blocks both recording the states that are changed when swapping.
227a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
228a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        // mPreFlipState will record the original state each entry.
229a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        hr = device->BeginStateBlock();
230a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        ASSERT(SUCCEEDED(hr));
2315abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        writeRecordableFlipState(device);
232a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        hr = device->EndStateBlock(&mPreFlipState);
233a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
234a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
235a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        if (SUCCEEDED(hr))
236a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        {
237a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block            mPreFlipState->Capture();
238a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        }
239a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
240a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        // mFlipState will record the state for the swap operation.
241a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        hr = device->BeginStateBlock();
242a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        ASSERT(SUCCEEDED(hr));
243a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
2445abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        writeRecordableFlipState(device);
245a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
246a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        hr = device->EndStateBlock(&mFlipState);
247a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
248a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
249a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        if (FAILED(hr))
250a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        {
251a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block            mFlipState = NULL;
252a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block            mPreFlipState->Release();
253a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block            mPreFlipState = NULL;
254a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        }
255a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        else
256a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        {
257a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block            hr = mFlipState->Apply();
258a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block            ASSERT(SUCCEEDED(hr));
259a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        }
260a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    }
261a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    else
262a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    {
263a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        hr = mPreFlipState->Capture();
264a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        ASSERT(SUCCEEDED(hr));
265a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        hr = mFlipState->Apply();
266a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        ASSERT(SUCCEEDED(hr));
267a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    }
268a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
269a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    device->GetRenderTarget(0, &mPreFlipBackBuffer);
270a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    device->GetDepthStencilSurface(&mPreFlipDepthStencil);
271a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
272a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    device->SetRenderTarget(0, mBackBuffer);
273a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    device->SetDepthStencilSurface(NULL);
274a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block}
275a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
276a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Blockvoid Surface::restoreState(IDirect3DDevice9 *device)
277a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block{
278a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    device->SetRenderTarget(0, mPreFlipBackBuffer);
279a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    device->SetDepthStencilSurface(mPreFlipDepthStencil);
280a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
281a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    if (mPreFlipBackBuffer)
282a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    {
283a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        mPreFlipBackBuffer->Release();
284a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        mPreFlipBackBuffer = NULL;
285a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    }
286a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
287a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    if (mPreFlipDepthStencil)
288a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    {
289a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        mPreFlipDepthStencil->Release();
290a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        mPreFlipDepthStencil = NULL;
291a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    }
292ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch
293ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    mPreFlipState->Apply();
294a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block}
295a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
2965abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick// On the next flip, this will cause the state to be recorded from scratch.
2975abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick// In particular we need to do this if the flip texture changes.
2985abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrickvoid Surface::releaseRecordedState(IDirect3DDevice9 *device)
2995abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick{
3005abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    if (mFlipState)
3015abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    {
3025abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        mFlipState->Release();
3035abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        mFlipState = NULL;
3045abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    }
3055abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
3065abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    if (mPreFlipState)
3075abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    {
3085abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        mPreFlipState->Release();
3095abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        mPreFlipState = NULL;
3105abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    }
3115abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick}
312ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch#define kSurfaceProperty _TEXT("Egl::SurfaceOwner")
313ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch#define kParentWndProc _TEXT("Egl::SurfaceParentWndProc")
314ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch
315ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdochstatic LRESULT CALLBACK SurfaceWindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
316ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch  if (message == WM_SIZE) {
317ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch      Surface* surf = reinterpret_cast<Surface*>(GetProp(hwnd, kSurfaceProperty));
318ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch      if(surf) {
319ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        surf->checkForOutOfDateSwapChain();
320ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch      }
321ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch  }
322ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch  WNDPROC prevWndFunc = reinterpret_cast<WNDPROC >(GetProp(hwnd, kParentWndProc));
323ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch  return CallWindowProc(prevWndFunc, hwnd, message, wparam, lparam);
324ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch}
3255abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
326ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdochvoid Surface::subclassWindow()
327ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch{
328ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch  SetLastError(0);
329ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch  LONG oldWndProc = SetWindowLong(mWindow, GWL_WNDPROC, reinterpret_cast<LONG>(SurfaceWindowProc));
330ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch  if(oldWndProc == 0 && GetLastError() != ERROR_SUCCESS) {
331ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    mWindowSubclassed = false;
332ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    return;
333ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch  }
334ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch
335ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch  SetProp(mWindow, kSurfaceProperty, reinterpret_cast<HANDLE>(this));
336ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch  SetProp(mWindow, kParentWndProc, reinterpret_cast<HANDLE>(oldWndProc));
337ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch  mWindowSubclassed = true;
338ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch}
339ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch
340ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdochvoid Surface::unsubclassWindow()
341ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch{
342ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch  if(!mWindowSubclassed)
343ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    return;
344ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch
345ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch  // un-subclass
346ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch  LONG parentWndFunc = reinterpret_cast<LONG>(GetProp(mWindow, kParentWndProc));
347ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch
348ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch  // Check the windowproc is still SurfaceWindowProc.
349ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch  // If this assert fails, then it is likely the application has subclassed the
350ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch  // hwnd as well and did not unsubclass before destroying its EGL context. The
351ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch  // application should be modified to either subclass before initializing the
352ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch  // EGL context, or to unsubclass before destroying the EGL context.
353ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch  if(parentWndFunc) {
354ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    LONG prevWndFunc = SetWindowLong(mWindow, GWL_WNDPROC, parentWndFunc);
355ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    ASSERT(prevWndFunc == reinterpret_cast<LONG>(SurfaceWindowProc));
356ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch  }
357ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch
358ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch  RemoveProp(mWindow, kSurfaceProperty);
359ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch  RemoveProp(mWindow, kParentWndProc);
360ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch  mWindowSubclassed = false;
361ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch}
362ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch
363ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdochbool Surface::checkForOutOfDateSwapChain()
3645abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick{
3655abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    RECT client;
3665abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    if (!GetClientRect(getWindowHandle(), &client))
3675abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    {
3685abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        ASSERT(false);
3695abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        return false;
3705abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    }
3715abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
372ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    // Grow the buffer now, if the window has grown. We need to grow now to avoid losing information.
373ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    int clientWidth = client.right - client.left;
374ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    int clientHeight = client.bottom - client.top;
375ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    bool sizeDirty = clientWidth != getWidth() || clientHeight != getHeight();
3765abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
377ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    if (sizeDirty || mPresentIntervalDirty)
378ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    {
379ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        resetSwapChain(clientWidth, clientHeight);
3805abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        if (static_cast<egl::Surface*>(getCurrentDrawSurface()) == this)
3815abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        {
3825abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick            glMakeCurrent(glGetCurrentContext(), static_cast<egl::Display*>(getCurrentDisplay()), this);
3835abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        }
3845abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
3855abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        return true;
3865abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    }
3875abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    return false;
3885abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick}
3895abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
390ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen MurdochDWORD Surface::convertInterval(EGLint interval)
391a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block{
392ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    switch(interval)
393a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    {
394ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch      case 0: return D3DPRESENT_INTERVAL_IMMEDIATE;
395ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch      case 1: return D3DPRESENT_INTERVAL_ONE;
396ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch      case 2: return D3DPRESENT_INTERVAL_TWO;
397ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch      case 3: return D3DPRESENT_INTERVAL_THREE;
398ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch      case 4: return D3DPRESENT_INTERVAL_FOUR;
399ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch      default: UNREACHABLE();
400ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    }
4015abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
402ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    return D3DPRESENT_INTERVAL_DEFAULT;
403ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch}
4045abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
4055abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
406ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdochbool Surface::swap()
407ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch{
408ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    if (mSwapChain)
409ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    {
410a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        IDirect3DDevice9 *device = mDisplay->getDevice();
411a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
4125abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        applyFlipState(device);
413ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        device->SetTexture(0, mFlipTexture);
414a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
415a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        // Render the texture upside down into the back buffer
416ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        // Texcoords are chosen to flip the renderTarget about its Y axis.
417ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        float w = static_cast<float>(getWidth());
418ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        float h = static_cast<float>(getHeight());
419ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        float quad[4][6] = {{0 - 0.5f, 0 - 0.5f, 0.0f, 1.0f, 0.0f, 1.0f},
420ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch                            {w - 0.5f, 0 - 0.5f, 0.0f, 1.0f, 1.0f, 1.0f},
421ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch                            {w - 0.5f, h - 0.5f, 0.0f, 1.0f, 1.0f, 0.0f},
422ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch                            {0 - 0.5f, h - 0.5f, 0.0f, 1.0f, 0.0f, 0.0f}};   // x, y, z, rhw, u, v
423a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
424a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        mDisplay->startScene();
425a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, 6 * sizeof(float));
426a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
427a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        restoreState(device);
428a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
429a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        mDisplay->endScene();
430ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch
431ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        HRESULT result = mSwapChain->Present(NULL, NULL, NULL, NULL, 0);
432a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
433a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DRIVERINTERNALERROR)
434a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        {
435a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block            return error(EGL_BAD_ALLOC, false);
436a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        }
437a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
438a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        if (result == D3DERR_DEVICELOST)
439a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        {
440a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block            return error(EGL_CONTEXT_LOST, false);
441a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        }
442a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
443a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        ASSERT(SUCCEEDED(result));
4445abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
445ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        checkForOutOfDateSwapChain();
446a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    }
447a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
448a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    return true;
449a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block}
450a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
451a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve BlockEGLint Surface::getWidth() const
452a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block{
453a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    return mWidth;
454a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block}
455a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
456a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve BlockEGLint Surface::getHeight() const
457a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block{
458a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    return mHeight;
459a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block}
460a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
461a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve BlockIDirect3DSurface9 *Surface::getRenderTarget()
462a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block{
463ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    IDirect3DSurface9 *textureSurface = NULL;
464ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch
465ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    if (mFlipTexture)
466a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    {
467ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        mFlipTexture->GetSurfaceLevel(0, &textureSurface);
468a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    }
469a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
470ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    return textureSurface;
471a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block}
472a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
473a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve BlockIDirect3DSurface9 *Surface::getDepthStencil()
474a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block{
475a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    if (mDepthStencil)
476a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    {
477a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block        mDepthStencil->AddRef();
478a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    }
479a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block
480a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block    return mDepthStencil;
481a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block}
482ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch
483ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdochvoid Surface::setSwapInterval(EGLint interval)
484ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch{
485ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    if (mSwapInterval == interval)
486ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    {
487ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        return;
488ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    }
489ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch
490ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    mSwapInterval = interval;
491ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    mSwapInterval = std::max(mSwapInterval, mDisplay->getMinSwapInterval());
492ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    mSwapInterval = std::min(mSwapInterval, mDisplay->getMaxSwapInterval());
493ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch
494ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    mPresentInterval = convertInterval(mSwapInterval);
495ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    mPresentIntervalDirty = true;
496ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch}
497a9bfd6c4a32dfd9cc032cb67c6ccb8d09c16f579Steve Block}
498