Support window resizing

TRAC #12660 Automatically resize the D3D swap chain when the eglSwapBuffers is called and the presentation window has changed size. Also change D3D device init to be performed once when the Display is created using a hidden 1x1 window. Signed-off-by: Nicolas Capens Signed-off-by: Daniel Koch Author: Andrew Lewycky git-svn-id: https://angleproject.googlecode.com/svn/trunk@365 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent 9ecb9f9d
...@@ -25,6 +25,7 @@ Display::Display(HDC deviceContext) : mDc(deviceContext) ...@@ -25,6 +25,7 @@ Display::Display(HDC deviceContext) : mDc(deviceContext)
{ {
mD3d9 = NULL; mD3d9 = NULL;
mDevice = NULL; mDevice = NULL;
mDeviceWindow = NULL;
mAdapter = D3DADAPTER_DEFAULT; mAdapter = D3DADAPTER_DEFAULT;
...@@ -150,6 +151,13 @@ bool Display::initialize() ...@@ -150,6 +151,13 @@ bool Display::initialize()
mConfigSet.mSet.insert(configuration); mConfigSet.mSet.insert(configuration);
} }
} }
if (!createDevice())
{
terminate();
return false;
}
} }
if (!isInitialized()) if (!isInitialized())
...@@ -185,6 +193,12 @@ void Display::terminate() ...@@ -185,6 +193,12 @@ void Display::terminate()
mD3d9->Release(); mD3d9->Release();
mD3d9 = NULL; mD3d9 = NULL;
} }
if (mDeviceWindow)
{
DestroyWindow(mDeviceWindow);
mDeviceWindow = NULL;
}
} }
void Display::startScene() void Display::startScene()
...@@ -254,126 +268,65 @@ bool Display::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value) ...@@ -254,126 +268,65 @@ bool Display::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value)
return true; return true;
} }
bool Display::createDevice()
{
static const TCHAR windowName[] = TEXT("AngleHiddenWindow");
static const TCHAR className[] = TEXT("STATIC");
mDeviceWindow = CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);
D3DPRESENT_PARAMETERS presentParameters = {0};
// The default swap chain is never actually used. Surface will create a new swap chain with the proper parameters.
presentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
presentParameters.BackBufferCount = 1;
presentParameters.BackBufferFormat = D3DFMT_UNKNOWN;
presentParameters.BackBufferWidth = 1;
presentParameters.BackBufferHeight = 1;
presentParameters.EnableAutoDepthStencil = FALSE;
presentParameters.Flags = 0;
presentParameters.hDeviceWindow = mDeviceWindow;
presentParameters.MultiSampleQuality = 0;
presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
presentParameters.PresentationInterval = convertInterval(mMinSwapInterval);
presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
presentParameters.Windowed = TRUE;
DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES;
HRESULT result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice);
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
{
return error(EGL_BAD_ALLOC, false);
}
if (FAILED(result))
{
result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParameters, &mDevice);
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
{
return error(EGL_BAD_ALLOC, false);
}
}
ASSERT(SUCCEEDED(result));
// Permanent non-default states
mDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE);
mSceneStarted = false;
return true;
}
Surface *Display::createWindowSurface(HWND window, EGLConfig config) Surface *Display::createWindowSurface(HWND window, EGLConfig config)
{ {
const Config *configuration = mConfigSet.get(config); const Config *configuration = mConfigSet.get(config);
D3DPRESENT_PARAMETERS presentParameters = {0}; Surface *surface = new Surface(this, configuration, window);
mSurfaceSet.insert(surface);
presentParameters.AutoDepthStencilFormat = configuration->mDepthStencilFormat;
presentParameters.BackBufferCount = 1;
presentParameters.BackBufferFormat = configuration->mRenderTargetFormat;
presentParameters.BackBufferWidth = 0;
presentParameters.BackBufferHeight = 0;
presentParameters.EnableAutoDepthStencil = configuration->mDepthSize ? TRUE : FALSE;
presentParameters.Flags = 0;
presentParameters.hDeviceWindow = window;
presentParameters.MultiSampleQuality = 0; // FIXME: Unimplemented
presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; // FIXME: Unimplemented
presentParameters.PresentationInterval = convertInterval(mMinSwapInterval);
presentParameters.SwapEffect = D3DSWAPEFFECT_COPY;
presentParameters.Windowed = TRUE; // FIXME
IDirect3DSwapChain9 *swapChain = NULL;
IDirect3DSurface9 *depthStencilSurface = NULL;
if (!mDevice)
{
DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES;
HRESULT result = mD3d9->CreateDevice(mAdapter, mDeviceType, window, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice);
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
{
return error(EGL_BAD_ALLOC, (egl::Surface*)NULL);
}
if (FAILED(result))
{
result = mD3d9->CreateDevice(mAdapter, mDeviceType, window, behaviorFlags | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParameters, &mDevice);
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
{
return error(EGL_BAD_ALLOC, (egl::Surface*)NULL);
}
}
ASSERT(SUCCEEDED(result));
if (mDevice)
{
mSceneStarted = false;
mDevice->GetSwapChain(0, &swapChain);
mDevice->GetDepthStencilSurface(&depthStencilSurface);
}
}
else
{
if (!mSurfaceSet.empty())
{
// if the device already exists, and there are other surfaces/windows currently in use, we need to create
// a separate swap chain for the new draw surface.
HRESULT result = mDevice->CreateAdditionalSwapChain(&presentParameters, &swapChain);
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
{
ERR("Could not create additional swap chains. Out of memory.");
return error(EGL_BAD_ALLOC, (egl::Surface*)NULL);
}
ASSERT(SUCCEEDED(result));
// CreateAdditionalSwapChain does not automatically generate a depthstencil surface, unlike
// CreateDevice, so we must do so explicitly.
result = mDevice->CreateDepthStencilSurface(presentParameters.BackBufferWidth, presentParameters.BackBufferHeight,
presentParameters.AutoDepthStencilFormat, presentParameters.MultiSampleType,
presentParameters.MultiSampleQuality, FALSE, &depthStencilSurface, NULL);
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
{
swapChain->Release();
ERR("Could not create depthstencil surface for new swap chain. Out of memory.");
return error(EGL_BAD_ALLOC, (egl::Surface*)NULL);
}
ASSERT(SUCCEEDED(result));
}
else
{
// if the device already exists, but there are no surfaces in use, then all the surfaces/windows
// have been destroyed, and we should repurpose the originally created depthstencil surface for
// use with the new surface we are creating.
HRESULT result = mDevice->Reset(&presentParameters);
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
{
ERR("Could not reset presentation parameters for device. Out of memory.");
return error(EGL_BAD_ALLOC, (egl::Surface*)NULL);
}
ASSERT(SUCCEEDED(result));
if (mDevice)
{
mSceneStarted = false;
mDevice->GetSwapChain(0, &swapChain);
mDevice->GetDepthStencilSurface(&depthStencilSurface);
}
}
}
// Permanent non-default states
mDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE);
Surface *surface = NULL;
if (swapChain)
{
surface = new Surface(this, swapChain, depthStencilSurface, configuration);
mSurfaceSet.insert(surface);
swapChain->Release();
}
return surface; return surface;
} }
......
...@@ -70,6 +70,7 @@ class Display ...@@ -70,6 +70,7 @@ class Display
IDirect3D9 *mD3d9; IDirect3D9 *mD3d9;
IDirect3DDevice9 *mDevice; IDirect3DDevice9 *mDevice;
D3DCAPS9 mDeviceCaps; D3DCAPS9 mDeviceCaps;
HWND mDeviceWindow;
bool mSceneStarted; bool mSceneStarted;
GLint mSwapInterval; GLint mSwapInterval;
...@@ -84,6 +85,8 @@ class Display ...@@ -84,6 +85,8 @@ class Display
typedef std::set<gl::Context*> ContextSet; typedef std::set<gl::Context*> ContextSet;
ContextSet mContextSet; ContextSet mContextSet;
bool createDevice();
}; };
} }
......
...@@ -25,7 +25,7 @@ class Config; ...@@ -25,7 +25,7 @@ class Config;
class Surface class Surface
{ {
public: public:
Surface(Display *display, IDirect3DSwapChain9 *swapChain, IDirect3DSurface9* depthStencil, const egl::Config *config); Surface(Display *display, const egl::Config *config, HWND window);
~Surface(); ~Surface();
...@@ -42,20 +42,25 @@ class Surface ...@@ -42,20 +42,25 @@ class Surface
DISALLOW_COPY_AND_ASSIGN(Surface); DISALLOW_COPY_AND_ASSIGN(Surface);
Display *const mDisplay; Display *const mDisplay;
IDirect3DSwapChain9 *const mSwapChain; IDirect3DSwapChain9 *mSwapChain;
IDirect3DSurface9 *mBackBuffer; IDirect3DSurface9 *mBackBuffer;
IDirect3DSurface9 *mRenderTarget; IDirect3DSurface9 *mRenderTarget;
IDirect3DSurface9 *mDepthStencil; IDirect3DSurface9 *mDepthStencil;
IDirect3DTexture9 *mFlipTexture; IDirect3DTexture9 *mFlipTexture;
void applyFlipState(IDirect3DDevice9 *device, IDirect3DTexture9 *source); void resetSwapChain();
bool checkForWindowResize();
void applyFlipState(IDirect3DDevice9 *device);
void restoreState(IDirect3DDevice9 *device); void restoreState(IDirect3DDevice9 *device);
void writeRecordableFlipState(IDirect3DDevice9 *device, IDirect3DTexture9 *source); void writeRecordableFlipState(IDirect3DDevice9 *device);
void releaseRecordedState(IDirect3DDevice9 *device);
IDirect3DStateBlock9 *mFlipState; IDirect3DStateBlock9 *mFlipState;
IDirect3DStateBlock9 *mPreFlipState; IDirect3DStateBlock9 *mPreFlipState;
IDirect3DSurface9 *mPreFlipBackBuffer; IDirect3DSurface9 *mPreFlipBackBuffer;
IDirect3DSurface9 *mPreFlipDepthStencil; IDirect3DSurface9 *mPreFlipDepthStencil;
const HWND mWindow; // Window that the surface is created for.
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