blob: 4e6b6373b00eeb41552e9eb07894cc57277aea55 [file] [log] [blame]
daniel@transgaming.com3c720782012-10-31 18:42:34 +00001//
daniel@transgaming.comed36abd2013-01-11 21:15:58 +00002// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com3c720782012-10-31 18:42:34 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +00007// SwapChain9.cpp: Implements a back-end specific class for the D3D9 swap chain.
daniel@transgaming.com3c720782012-10-31 18:42:34 +00008
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +00009#include "libGLESv2/renderer/SwapChain9.h"
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +000010#include "libGLESv2/renderer/renderer9_utils.h"
11#include "libGLESv2/renderer/Renderer9.h"
daniel@transgaming.com3c720782012-10-31 18:42:34 +000012
daniel@transgaming.com76d3e6e2012-10-31 19:55:33 +000013namespace rx
daniel@transgaming.com3c720782012-10-31 18:42:34 +000014{
15
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +000016SwapChain9::SwapChain9(Renderer9 *renderer, HWND window, HANDLE shareHandle,
17 GLenum backBufferFormat, GLenum depthBufferFormat)
18 : mRenderer(renderer), SwapChain(window, shareHandle, backBufferFormat, depthBufferFormat)
daniel@transgaming.com3c720782012-10-31 18:42:34 +000019{
20 mSwapChain = NULL;
21 mBackBuffer = NULL;
22 mDepthStencil = NULL;
23 mRenderTarget = NULL;
24 mOffscreenTexture = NULL;
25 mWidth = -1;
26 mHeight = -1;
shannon.woods@transgaming.comc71ca752013-02-28 23:06:50 +000027 mSwapInterval = -1;
daniel@transgaming.com3c720782012-10-31 18:42:34 +000028}
29
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +000030SwapChain9::~SwapChain9()
daniel@transgaming.com3c720782012-10-31 18:42:34 +000031{
32 release();
33}
34
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +000035void SwapChain9::release()
daniel@transgaming.com3c720782012-10-31 18:42:34 +000036{
37 if (mSwapChain)
38 {
39 mSwapChain->Release();
40 mSwapChain = NULL;
41 }
42
43 if (mBackBuffer)
44 {
45 mBackBuffer->Release();
46 mBackBuffer = NULL;
47 }
48
49 if (mDepthStencil)
50 {
51 mDepthStencil->Release();
52 mDepthStencil = NULL;
53 }
54
55 if (mRenderTarget)
56 {
57 mRenderTarget->Release();
58 mRenderTarget = NULL;
59 }
60
61 if (mOffscreenTexture)
62 {
63 mOffscreenTexture->Release();
64 mOffscreenTexture = NULL;
65 }
66
daniel@transgaming.com21cfaef2012-10-31 18:42:43 +000067 if (mWindow)
68 mShareHandle = NULL;
daniel@transgaming.com3c720782012-10-31 18:42:34 +000069}
70
71static DWORD convertInterval(EGLint interval)
72{
73 switch(interval)
74 {
75 case 0: return D3DPRESENT_INTERVAL_IMMEDIATE;
76 case 1: return D3DPRESENT_INTERVAL_ONE;
77 case 2: return D3DPRESENT_INTERVAL_TWO;
78 case 3: return D3DPRESENT_INTERVAL_THREE;
79 case 4: return D3DPRESENT_INTERVAL_FOUR;
80 default: UNREACHABLE();
81 }
82
83 return D3DPRESENT_INTERVAL_DEFAULT;
84}
85
shannon.woods@transgaming.comc71ca752013-02-28 23:06:50 +000086EGLint SwapChain9::resize(int backbufferWidth, int backbufferHeight)
87{
88 // D3D9 does not support resizing swap chains without recreating them
89 return reset(backbufferWidth, backbufferHeight, mSwapInterval);
90}
91
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +000092EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapInterval)
daniel@transgaming.com3c720782012-10-31 18:42:34 +000093{
94 IDirect3DDevice9 *device = mRenderer->getDevice();
95
96 if (device == NULL)
97 {
98 return EGL_BAD_ACCESS;
99 }
100
101 // Evict all non-render target textures to system memory and release all resources
102 // before reallocating them to free up as much video memory as possible.
103 device->EvictManagedResources();
104
105 HRESULT result;
106
107 // Release specific resources to free up memory for the new render target, while the
108 // old render target still exists for the purpose of preserving its contents.
109 if (mSwapChain)
110 {
111 mSwapChain->Release();
112 mSwapChain = NULL;
113 }
114
115 if (mBackBuffer)
116 {
117 mBackBuffer->Release();
118 mBackBuffer = NULL;
119 }
120
121 if (mOffscreenTexture)
122 {
123 mOffscreenTexture->Release();
124 mOffscreenTexture = NULL;
125 }
126
127 if (mDepthStencil)
128 {
129 mDepthStencil->Release();
130 mDepthStencil = NULL;
131 }
132
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000133 HANDLE *pShareHandle = NULL;
134 if (!mWindow && mRenderer->getShareHandleSupport())
135 {
136 pShareHandle = &mShareHandle;
137 }
138
139 result = device->CreateTexture(backbufferWidth, backbufferHeight, 1, D3DUSAGE_RENDERTARGET,
daniel@transgaming.com682a37c2012-11-28 19:34:44 +0000140 gl_d3d9::ConvertRenderbufferFormat(mBackBufferFormat), D3DPOOL_DEFAULT,
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000141 &mOffscreenTexture, pShareHandle);
142 if (FAILED(result))
143 {
144 ERR("Could not create offscreen texture: %08lX", result);
145 release();
146
shannon.woods@transgaming.comf5f59492013-02-28 23:04:40 +0000147 if (d3d9::isDeviceLostError(result))
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000148 {
149 return EGL_CONTEXT_LOST;
150 }
151 else
152 {
153 return EGL_BAD_ALLOC;
154 }
155 }
156
157 IDirect3DSurface9 *oldRenderTarget = mRenderTarget;
158
159 result = mOffscreenTexture->GetSurfaceLevel(0, &mRenderTarget);
160 ASSERT(SUCCEEDED(result));
161
162 if (oldRenderTarget)
163 {
164 RECT rect =
165 {
166 0, 0,
167 mWidth, mHeight
168 };
169
170 if (rect.right > static_cast<LONG>(backbufferWidth))
171 {
172 rect.right = backbufferWidth;
173 }
174
175 if (rect.bottom > static_cast<LONG>(backbufferHeight))
176 {
177 rect.bottom = backbufferHeight;
178 }
179
180 mRenderer->endScene();
181
182 result = device->StretchRect(oldRenderTarget, &rect, mRenderTarget, &rect, D3DTEXF_NONE);
183 ASSERT(SUCCEEDED(result));
184
185 oldRenderTarget->Release();
186 }
187
188 if (mWindow)
189 {
190 D3DPRESENT_PARAMETERS presentParameters = {0};
daniel@transgaming.com682a37c2012-11-28 19:34:44 +0000191 presentParameters.AutoDepthStencilFormat = gl_d3d9::ConvertRenderbufferFormat(mDepthBufferFormat);
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000192 presentParameters.BackBufferCount = 1;
daniel@transgaming.com682a37c2012-11-28 19:34:44 +0000193 presentParameters.BackBufferFormat = gl_d3d9::ConvertRenderbufferFormat(mBackBufferFormat);
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000194 presentParameters.EnableAutoDepthStencil = FALSE;
195 presentParameters.Flags = 0;
196 presentParameters.hDeviceWindow = mWindow;
197 presentParameters.MultiSampleQuality = 0; // FIXME: Unimplemented
198 presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; // FIXME: Unimplemented
199 presentParameters.PresentationInterval = convertInterval(swapInterval);
200 presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
201 presentParameters.Windowed = TRUE;
202 presentParameters.BackBufferWidth = backbufferWidth;
203 presentParameters.BackBufferHeight = backbufferHeight;
204
205 // http://crbug.com/140239
206 // http://crbug.com/143434
207 //
208 // Some AMD/Intel switchable systems / drivers appear to round swap chain surfaces to a multiple of 64 pixels in width
209 // when using the integrated Intel. This rounds the width up rather than down.
210 //
211 // Some non-switchable AMD GPUs / drivers do not respect the source rectangle to Present. Therefore, when the vendor ID
212 // is not Intel, the back buffer width must be exactly the same width as the window or horizontal scaling will occur.
daniel@transgaming.comd8e36562012-10-31 19:52:19 +0000213 if (mRenderer->getAdapterVendor() == VENDOR_ID_INTEL)
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000214 {
215 presentParameters.BackBufferWidth = (presentParameters.BackBufferWidth + 63) / 64 * 64;
216 }
217
218 result = device->CreateAdditionalSwapChain(&presentParameters, &mSwapChain);
219
220 if (FAILED(result))
221 {
222 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL || result == D3DERR_DEVICELOST);
223
224 ERR("Could not create additional swap chains or offscreen surfaces: %08lX", result);
225 release();
226
shannon.woods@transgaming.comf5f59492013-02-28 23:04:40 +0000227 if (d3d9::isDeviceLostError(result))
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000228 {
229 return EGL_CONTEXT_LOST;
230 }
231 else
232 {
233 return EGL_BAD_ALLOC;
234 }
235 }
236
237 result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer);
238 ASSERT(SUCCEEDED(result));
daniel@transgaming.comb323df02012-11-28 19:41:36 +0000239 InvalidateRect(mWindow, NULL, FALSE);
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000240 }
241
daniel@transgaming.coma60160b2012-11-28 19:41:15 +0000242 if (mDepthBufferFormat != GL_NONE)
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000243 {
244 result = device->CreateDepthStencilSurface(backbufferWidth, backbufferHeight,
daniel@transgaming.com682a37c2012-11-28 19:34:44 +0000245 gl_d3d9::ConvertRenderbufferFormat(mDepthBufferFormat),
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000246 D3DMULTISAMPLE_NONE, 0, FALSE, &mDepthStencil, NULL);
247
248 if (FAILED(result))
249 {
250 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL);
251
252 ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result);
253 release();
254
shannon.woods@transgaming.comf5f59492013-02-28 23:04:40 +0000255 if (d3d9::isDeviceLostError(result))
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000256 {
257 return EGL_CONTEXT_LOST;
258 }
259 else
260 {
261 return EGL_BAD_ALLOC;
262 }
263 }
264 }
265
266 mWidth = backbufferWidth;
267 mHeight = backbufferHeight;
shannon.woods@transgaming.comc71ca752013-02-28 23:06:50 +0000268 mSwapInterval = swapInterval;
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000269
270 return EGL_SUCCESS;
271}
272
273// parameters should be validated/clamped by caller
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +0000274EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height)
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000275{
276 if (!mSwapChain)
277 {
278 return EGL_SUCCESS;
279 }
280
281 IDirect3DDevice9 *device = mRenderer->getDevice();
282
283 // Disable all pipeline operations
284 device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
285 device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
286 device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
287 device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
288 device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
289 device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
290 device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
291 device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED);
292 device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE);
293 device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
294 device->SetPixelShader(NULL);
295 device->SetVertexShader(NULL);
296
297 device->SetRenderTarget(0, mBackBuffer);
298 device->SetDepthStencilSurface(NULL);
299
300 device->SetTexture(0, mOffscreenTexture);
301 device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
302 device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
303 device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
304 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
305 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
306 device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
307 device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
308 device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
309
310 D3DVIEWPORT9 viewport = {0, 0, mWidth, mHeight, 0.0f, 1.0f};
311 device->SetViewport(&viewport);
312
313 float x1 = x - 0.5f;
314 float y1 = (mHeight - y - height) - 0.5f;
315 float x2 = (x + width) - 0.5f;
316 float y2 = (mHeight - y) - 0.5f;
317
318 float u1 = x / float(mWidth);
319 float v1 = y / float(mHeight);
320 float u2 = (x + width) / float(mWidth);
321 float v2 = (y + height) / float(mHeight);
322
323 float quad[4][6] = {{x1, y1, 0.0f, 1.0f, u1, v2},
324 {x2, y1, 0.0f, 1.0f, u2, v2},
325 {x2, y2, 0.0f, 1.0f, u2, v1},
326 {x1, y2, 0.0f, 1.0f, u1, v1}}; // x, y, z, rhw, u, v
327
328 mRenderer->startScene();
329 device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, 6 * sizeof(float));
330 mRenderer->endScene();
331
332 device->SetTexture(0, NULL);
333
334 RECT rect =
335 {
336 x, mHeight - y - height,
337 x + width, mHeight - y
338 };
339
340 HRESULT result = mSwapChain->Present(&rect, &rect, NULL, NULL, 0);
341
daniel@transgaming.comc43a6052012-11-28 19:41:51 +0000342 mRenderer->markAllStateDirty();
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000343
shannon.woods@transgaming.comf5f59492013-02-28 23:04:40 +0000344 if (d3d9::isDeviceLostError(result))
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000345 {
346 return EGL_CONTEXT_LOST;
347 }
348
349 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DRIVERINTERNALERROR)
350 {
351 return EGL_BAD_ALLOC;
352 }
353
354 ASSERT(SUCCEEDED(result));
355
356 return EGL_SUCCESS;
357}
358
359// Increments refcount on surface.
360// caller must Release() the returned surface
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +0000361IDirect3DSurface9 *SwapChain9::getRenderTarget()
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000362{
363 if (mRenderTarget)
364 {
365 mRenderTarget->AddRef();
366 }
367
368 return mRenderTarget;
369}
370
371// Increments refcount on surface.
372// caller must Release() the returned surface
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +0000373IDirect3DSurface9 *SwapChain9::getDepthStencil()
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000374{
375 if (mDepthStencil)
376 {
377 mDepthStencil->AddRef();
378 }
379
380 return mDepthStencil;
381}
382
383// Increments refcount on texture.
384// caller must Release() the returned texture
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +0000385IDirect3DTexture9 *SwapChain9::getOffscreenTexture()
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000386{
387 if (mOffscreenTexture)
388 {
389 mOffscreenTexture->AddRef();
390 }
391
392 return mOffscreenTexture;
393}
394
daniel@transgaming.comd733bb82012-11-28 20:53:40 +0000395SwapChain9 *SwapChain9::makeSwapChain9(SwapChain *swapChain)
396{
apatrick@chromium.org8b400b12013-01-30 21:53:40 +0000397 ASSERT(HAS_DYNAMIC_TYPE(rx::SwapChain9*, swapChain));
daniel@transgaming.comd733bb82012-11-28 20:53:40 +0000398 return static_cast<rx::SwapChain9*>(swapChain);
399}
400
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000401}