blob: ee6abf232e2913a73bf13f23dd80caca95ca13eb [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
daniel@transgaming.com3c720782012-10-31 18:42:34 +00002//
daniel@transgaming.comed36abd2013-01-11 21:15:58 +00003// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com3c720782012-10-31 18:42:34 +00004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +00008// SwapChain9.cpp: Implements a back-end specific class for the D3D9 swap chain.
daniel@transgaming.com3c720782012-10-31 18:42:34 +00009
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +000010#include "libGLESv2/renderer/SwapChain9.h"
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +000011#include "libGLESv2/renderer/renderer9_utils.h"
shannonwoods@chromium.org755012f2013-05-30 00:09:32 +000012#include "libGLESv2/renderer/formatutils9.h"
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +000013#include "libGLESv2/renderer/Renderer9.h"
daniel@transgaming.com3c720782012-10-31 18:42:34 +000014
daniel@transgaming.com76d3e6e2012-10-31 19:55:33 +000015namespace rx
daniel@transgaming.com3c720782012-10-31 18:42:34 +000016{
17
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +000018SwapChain9::SwapChain9(Renderer9 *renderer, HWND window, HANDLE shareHandle,
19 GLenum backBufferFormat, GLenum depthBufferFormat)
20 : mRenderer(renderer), SwapChain(window, shareHandle, backBufferFormat, depthBufferFormat)
daniel@transgaming.com3c720782012-10-31 18:42:34 +000021{
22 mSwapChain = NULL;
23 mBackBuffer = NULL;
24 mDepthStencil = NULL;
25 mRenderTarget = NULL;
26 mOffscreenTexture = NULL;
27 mWidth = -1;
28 mHeight = -1;
shannon.woods@transgaming.comc71ca752013-02-28 23:06:50 +000029 mSwapInterval = -1;
daniel@transgaming.com3c720782012-10-31 18:42:34 +000030}
31
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +000032SwapChain9::~SwapChain9()
daniel@transgaming.com3c720782012-10-31 18:42:34 +000033{
34 release();
35}
36
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +000037void SwapChain9::release()
daniel@transgaming.com3c720782012-10-31 18:42:34 +000038{
39 if (mSwapChain)
40 {
41 mSwapChain->Release();
42 mSwapChain = NULL;
43 }
44
45 if (mBackBuffer)
46 {
47 mBackBuffer->Release();
48 mBackBuffer = NULL;
49 }
50
51 if (mDepthStencil)
52 {
53 mDepthStencil->Release();
54 mDepthStencil = NULL;
55 }
56
57 if (mRenderTarget)
58 {
59 mRenderTarget->Release();
60 mRenderTarget = NULL;
61 }
62
63 if (mOffscreenTexture)
64 {
65 mOffscreenTexture->Release();
66 mOffscreenTexture = NULL;
67 }
68
daniel@transgaming.com21cfaef2012-10-31 18:42:43 +000069 if (mWindow)
70 mShareHandle = NULL;
daniel@transgaming.com3c720782012-10-31 18:42:34 +000071}
72
73static DWORD convertInterval(EGLint interval)
74{
75 switch(interval)
76 {
77 case 0: return D3DPRESENT_INTERVAL_IMMEDIATE;
78 case 1: return D3DPRESENT_INTERVAL_ONE;
79 case 2: return D3DPRESENT_INTERVAL_TWO;
80 case 3: return D3DPRESENT_INTERVAL_THREE;
81 case 4: return D3DPRESENT_INTERVAL_FOUR;
82 default: UNREACHABLE();
83 }
84
85 return D3DPRESENT_INTERVAL_DEFAULT;
86}
87
shannon.woods@transgaming.comc71ca752013-02-28 23:06:50 +000088EGLint SwapChain9::resize(int backbufferWidth, int backbufferHeight)
89{
90 // D3D9 does not support resizing swap chains without recreating them
91 return reset(backbufferWidth, backbufferHeight, mSwapInterval);
92}
93
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +000094EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapInterval)
daniel@transgaming.com3c720782012-10-31 18:42:34 +000095{
96 IDirect3DDevice9 *device = mRenderer->getDevice();
97
98 if (device == NULL)
99 {
100 return EGL_BAD_ACCESS;
101 }
102
103 // Evict all non-render target textures to system memory and release all resources
104 // before reallocating them to free up as much video memory as possible.
105 device->EvictManagedResources();
106
107 HRESULT result;
108
109 // Release specific resources to free up memory for the new render target, while the
110 // old render target still exists for the purpose of preserving its contents.
111 if (mSwapChain)
112 {
113 mSwapChain->Release();
114 mSwapChain = NULL;
115 }
116
117 if (mBackBuffer)
118 {
119 mBackBuffer->Release();
120 mBackBuffer = NULL;
121 }
122
123 if (mOffscreenTexture)
124 {
125 mOffscreenTexture->Release();
126 mOffscreenTexture = NULL;
127 }
128
129 if (mDepthStencil)
130 {
131 mDepthStencil->Release();
132 mDepthStencil = NULL;
133 }
134
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000135 HANDLE *pShareHandle = NULL;
136 if (!mWindow && mRenderer->getShareHandleSupport())
137 {
138 pShareHandle = &mShareHandle;
139 }
140
141 result = device->CreateTexture(backbufferWidth, backbufferHeight, 1, D3DUSAGE_RENDERTARGET,
shannonwoods@chromium.org755012f2013-05-30 00:09:32 +0000142 gl_d3d9::GetTexureFormat(mBackBufferFormat, mRenderer),
143 D3DPOOL_DEFAULT, &mOffscreenTexture, pShareHandle);
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000144 if (FAILED(result))
145 {
146 ERR("Could not create offscreen texture: %08lX", result);
147 release();
148
shannon.woods@transgaming.comf5f59492013-02-28 23:04:40 +0000149 if (d3d9::isDeviceLostError(result))
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000150 {
151 return EGL_CONTEXT_LOST;
152 }
153 else
154 {
155 return EGL_BAD_ALLOC;
156 }
157 }
158
159 IDirect3DSurface9 *oldRenderTarget = mRenderTarget;
160
161 result = mOffscreenTexture->GetSurfaceLevel(0, &mRenderTarget);
162 ASSERT(SUCCEEDED(result));
163
164 if (oldRenderTarget)
165 {
166 RECT rect =
167 {
168 0, 0,
169 mWidth, mHeight
170 };
171
172 if (rect.right > static_cast<LONG>(backbufferWidth))
173 {
174 rect.right = backbufferWidth;
175 }
176
177 if (rect.bottom > static_cast<LONG>(backbufferHeight))
178 {
179 rect.bottom = backbufferHeight;
180 }
181
182 mRenderer->endScene();
183
184 result = device->StretchRect(oldRenderTarget, &rect, mRenderTarget, &rect, D3DTEXF_NONE);
185 ASSERT(SUCCEEDED(result));
186
187 oldRenderTarget->Release();
188 }
189
190 if (mWindow)
191 {
192 D3DPRESENT_PARAMETERS presentParameters = {0};
shannonwoods@chromium.org755012f2013-05-30 00:09:32 +0000193 presentParameters.AutoDepthStencilFormat = gl_d3d9::GetRenderFormat(mDepthBufferFormat, mRenderer);
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000194 presentParameters.BackBufferCount = 1;
shannonwoods@chromium.org755012f2013-05-30 00:09:32 +0000195 presentParameters.BackBufferFormat = gl_d3d9::GetRenderFormat(mBackBufferFormat, mRenderer);
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000196 presentParameters.EnableAutoDepthStencil = FALSE;
197 presentParameters.Flags = 0;
198 presentParameters.hDeviceWindow = mWindow;
199 presentParameters.MultiSampleQuality = 0; // FIXME: Unimplemented
200 presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; // FIXME: Unimplemented
201 presentParameters.PresentationInterval = convertInterval(swapInterval);
202 presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
203 presentParameters.Windowed = TRUE;
204 presentParameters.BackBufferWidth = backbufferWidth;
205 presentParameters.BackBufferHeight = backbufferHeight;
206
207 // http://crbug.com/140239
208 // http://crbug.com/143434
209 //
210 // Some AMD/Intel switchable systems / drivers appear to round swap chain surfaces to a multiple of 64 pixels in width
211 // when using the integrated Intel. This rounds the width up rather than down.
212 //
213 // Some non-switchable AMD GPUs / drivers do not respect the source rectangle to Present. Therefore, when the vendor ID
214 // 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 +0000215 if (mRenderer->getAdapterVendor() == VENDOR_ID_INTEL)
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000216 {
217 presentParameters.BackBufferWidth = (presentParameters.BackBufferWidth + 63) / 64 * 64;
218 }
219
220 result = device->CreateAdditionalSwapChain(&presentParameters, &mSwapChain);
221
222 if (FAILED(result))
223 {
224 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL || result == D3DERR_DEVICELOST);
225
226 ERR("Could not create additional swap chains or offscreen surfaces: %08lX", result);
227 release();
228
shannon.woods@transgaming.comf5f59492013-02-28 23:04:40 +0000229 if (d3d9::isDeviceLostError(result))
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000230 {
231 return EGL_CONTEXT_LOST;
232 }
233 else
234 {
235 return EGL_BAD_ALLOC;
236 }
237 }
238
239 result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer);
240 ASSERT(SUCCEEDED(result));
daniel@transgaming.comb323df02012-11-28 19:41:36 +0000241 InvalidateRect(mWindow, NULL, FALSE);
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000242 }
243
daniel@transgaming.coma60160b2012-11-28 19:41:15 +0000244 if (mDepthBufferFormat != GL_NONE)
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000245 {
246 result = device->CreateDepthStencilSurface(backbufferWidth, backbufferHeight,
shannonwoods@chromium.org755012f2013-05-30 00:09:32 +0000247 gl_d3d9::GetRenderFormat(mDepthBufferFormat, mRenderer),
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000248 D3DMULTISAMPLE_NONE, 0, FALSE, &mDepthStencil, NULL);
249
250 if (FAILED(result))
251 {
252 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL);
253
254 ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result);
255 release();
256
shannon.woods@transgaming.comf5f59492013-02-28 23:04:40 +0000257 if (d3d9::isDeviceLostError(result))
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000258 {
259 return EGL_CONTEXT_LOST;
260 }
261 else
262 {
263 return EGL_BAD_ALLOC;
264 }
265 }
266 }
267
268 mWidth = backbufferWidth;
269 mHeight = backbufferHeight;
shannon.woods@transgaming.comc71ca752013-02-28 23:06:50 +0000270 mSwapInterval = swapInterval;
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000271
272 return EGL_SUCCESS;
273}
274
275// parameters should be validated/clamped by caller
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +0000276EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height)
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000277{
278 if (!mSwapChain)
279 {
280 return EGL_SUCCESS;
281 }
282
283 IDirect3DDevice9 *device = mRenderer->getDevice();
284
285 // Disable all pipeline operations
286 device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
287 device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
288 device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
289 device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
290 device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
291 device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
292 device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
293 device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED);
294 device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE);
295 device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
296 device->SetPixelShader(NULL);
297 device->SetVertexShader(NULL);
298
299 device->SetRenderTarget(0, mBackBuffer);
300 device->SetDepthStencilSurface(NULL);
301
302 device->SetTexture(0, mOffscreenTexture);
303 device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
304 device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
305 device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
306 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
307 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
308 device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
309 device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
310 device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
311
312 D3DVIEWPORT9 viewport = {0, 0, mWidth, mHeight, 0.0f, 1.0f};
313 device->SetViewport(&viewport);
314
315 float x1 = x - 0.5f;
316 float y1 = (mHeight - y - height) - 0.5f;
317 float x2 = (x + width) - 0.5f;
318 float y2 = (mHeight - y) - 0.5f;
319
320 float u1 = x / float(mWidth);
321 float v1 = y / float(mHeight);
322 float u2 = (x + width) / float(mWidth);
323 float v2 = (y + height) / float(mHeight);
324
325 float quad[4][6] = {{x1, y1, 0.0f, 1.0f, u1, v2},
326 {x2, y1, 0.0f, 1.0f, u2, v2},
327 {x2, y2, 0.0f, 1.0f, u2, v1},
328 {x1, y2, 0.0f, 1.0f, u1, v1}}; // x, y, z, rhw, u, v
329
330 mRenderer->startScene();
331 device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, 6 * sizeof(float));
332 mRenderer->endScene();
333
334 device->SetTexture(0, NULL);
335
336 RECT rect =
337 {
338 x, mHeight - y - height,
339 x + width, mHeight - y
340 };
341
342 HRESULT result = mSwapChain->Present(&rect, &rect, NULL, NULL, 0);
343
daniel@transgaming.comc43a6052012-11-28 19:41:51 +0000344 mRenderer->markAllStateDirty();
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000345
shannon.woods@transgaming.comf5f59492013-02-28 23:04:40 +0000346 if (d3d9::isDeviceLostError(result))
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000347 {
348 return EGL_CONTEXT_LOST;
349 }
350
351 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DRIVERINTERNALERROR)
352 {
353 return EGL_BAD_ALLOC;
354 }
355
356 ASSERT(SUCCEEDED(result));
357
358 return EGL_SUCCESS;
359}
360
361// Increments refcount on surface.
362// caller must Release() the returned surface
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +0000363IDirect3DSurface9 *SwapChain9::getRenderTarget()
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000364{
365 if (mRenderTarget)
366 {
367 mRenderTarget->AddRef();
368 }
369
370 return mRenderTarget;
371}
372
373// Increments refcount on surface.
374// caller must Release() the returned surface
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +0000375IDirect3DSurface9 *SwapChain9::getDepthStencil()
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000376{
377 if (mDepthStencil)
378 {
379 mDepthStencil->AddRef();
380 }
381
382 return mDepthStencil;
383}
384
385// Increments refcount on texture.
386// caller must Release() the returned texture
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +0000387IDirect3DTexture9 *SwapChain9::getOffscreenTexture()
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000388{
389 if (mOffscreenTexture)
390 {
391 mOffscreenTexture->AddRef();
392 }
393
394 return mOffscreenTexture;
395}
396
daniel@transgaming.comd733bb82012-11-28 20:53:40 +0000397SwapChain9 *SwapChain9::makeSwapChain9(SwapChain *swapChain)
398{
apatrick@chromium.org8b400b12013-01-30 21:53:40 +0000399 ASSERT(HAS_DYNAMIC_TYPE(rx::SwapChain9*, swapChain));
daniel@transgaming.comd733bb82012-11-28 20:53:40 +0000400 return static_cast<rx::SwapChain9*>(swapChain);
401}
402
shannon.woods%transgaming.com@gtempaccount.com8bce3f52013-04-13 03:35:32 +0000403void SwapChain9::recreate()
404{
405 if (!mSwapChain)
406 {
407 return;
408 }
409
410 IDirect3DDevice9 *device = mRenderer->getDevice();
411 if (device == NULL)
412 {
413 return;
414 }
415
416 D3DPRESENT_PARAMETERS presentParameters;
417 HRESULT result = mSwapChain->GetPresentParameters(&presentParameters);
418 ASSERT(SUCCEEDED(result));
419
420 IDirect3DSwapChain9* newSwapChain = NULL;
421 result = device->CreateAdditionalSwapChain(&presentParameters, &newSwapChain);
422 if (FAILED(result))
423 {
424 return;
425 }
426
427 mSwapChain->Release();
428 mSwapChain = newSwapChain;
429
430 mBackBuffer->Release();
431 result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer);
432 ASSERT(SUCCEEDED(result));
433}
434
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000435}