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