blob: f5bdaa280b972c32cc18e4e22b8551955dc8538b [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{
Geoff Langea228632013-07-30 15:17:12 -040039 SafeRelease(mSwapChain);
40 SafeRelease(mBackBuffer);
41 SafeRelease(mDepthStencil);
42 SafeRelease(mRenderTarget);
43 SafeRelease(mOffscreenTexture);
daniel@transgaming.com3c720782012-10-31 18:42:34 +000044
daniel@transgaming.com21cfaef2012-10-31 18:42:43 +000045 if (mWindow)
Geoff Langea228632013-07-30 15:17:12 -040046 {
daniel@transgaming.com21cfaef2012-10-31 18:42:43 +000047 mShareHandle = NULL;
Geoff Langea228632013-07-30 15:17:12 -040048 }
daniel@transgaming.com3c720782012-10-31 18:42:34 +000049}
50
51static DWORD convertInterval(EGLint interval)
52{
53 switch(interval)
54 {
55 case 0: return D3DPRESENT_INTERVAL_IMMEDIATE;
56 case 1: return D3DPRESENT_INTERVAL_ONE;
57 case 2: return D3DPRESENT_INTERVAL_TWO;
58 case 3: return D3DPRESENT_INTERVAL_THREE;
59 case 4: return D3DPRESENT_INTERVAL_FOUR;
60 default: UNREACHABLE();
61 }
62
63 return D3DPRESENT_INTERVAL_DEFAULT;
64}
65
shannon.woods@transgaming.comc71ca752013-02-28 23:06:50 +000066EGLint SwapChain9::resize(int backbufferWidth, int backbufferHeight)
67{
68 // D3D9 does not support resizing swap chains without recreating them
69 return reset(backbufferWidth, backbufferHeight, mSwapInterval);
70}
71
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +000072EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapInterval)
daniel@transgaming.com3c720782012-10-31 18:42:34 +000073{
74 IDirect3DDevice9 *device = mRenderer->getDevice();
75
76 if (device == NULL)
77 {
78 return EGL_BAD_ACCESS;
79 }
80
81 // Evict all non-render target textures to system memory and release all resources
82 // before reallocating them to free up as much video memory as possible.
83 device->EvictManagedResources();
84
85 HRESULT result;
86
87 // Release specific resources to free up memory for the new render target, while the
88 // old render target still exists for the purpose of preserving its contents.
Geoff Langea228632013-07-30 15:17:12 -040089 SafeRelease(mSwapChain);
90 SafeRelease(mBackBuffer);
91 SafeRelease(mOffscreenTexture);
92 SafeRelease(mDepthStencil);
daniel@transgaming.com3c720782012-10-31 18:42:34 +000093
daniel@transgaming.com3c720782012-10-31 18:42:34 +000094 HANDLE *pShareHandle = NULL;
95 if (!mWindow && mRenderer->getShareHandleSupport())
96 {
97 pShareHandle = &mShareHandle;
98 }
99
100 result = device->CreateTexture(backbufferWidth, backbufferHeight, 1, D3DUSAGE_RENDERTARGET,
Shannon Woodsddb785c2013-07-08 10:32:13 -0400101 gl_d3d9::GetTextureFormat(mBackBufferFormat, mRenderer),
shannonwoods@chromium.org755012f2013-05-30 00:09:32 +0000102 D3DPOOL_DEFAULT, &mOffscreenTexture, pShareHandle);
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000103 if (FAILED(result))
104 {
105 ERR("Could not create offscreen texture: %08lX", result);
106 release();
107
shannon.woods@transgaming.comf5f59492013-02-28 23:04:40 +0000108 if (d3d9::isDeviceLostError(result))
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000109 {
110 return EGL_CONTEXT_LOST;
111 }
112 else
113 {
114 return EGL_BAD_ALLOC;
115 }
116 }
117
118 IDirect3DSurface9 *oldRenderTarget = mRenderTarget;
119
120 result = mOffscreenTexture->GetSurfaceLevel(0, &mRenderTarget);
121 ASSERT(SUCCEEDED(result));
122
123 if (oldRenderTarget)
124 {
125 RECT rect =
126 {
127 0, 0,
128 mWidth, mHeight
129 };
130
131 if (rect.right > static_cast<LONG>(backbufferWidth))
132 {
133 rect.right = backbufferWidth;
134 }
135
136 if (rect.bottom > static_cast<LONG>(backbufferHeight))
137 {
138 rect.bottom = backbufferHeight;
139 }
140
141 mRenderer->endScene();
142
143 result = device->StretchRect(oldRenderTarget, &rect, mRenderTarget, &rect, D3DTEXF_NONE);
144 ASSERT(SUCCEEDED(result));
145
Geoff Langea228632013-07-30 15:17:12 -0400146 SafeRelease(oldRenderTarget);
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000147 }
148
149 if (mWindow)
150 {
151 D3DPRESENT_PARAMETERS presentParameters = {0};
shannonwoods@chromium.org755012f2013-05-30 00:09:32 +0000152 presentParameters.AutoDepthStencilFormat = gl_d3d9::GetRenderFormat(mDepthBufferFormat, mRenderer);
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000153 presentParameters.BackBufferCount = 1;
shannonwoods@chromium.org755012f2013-05-30 00:09:32 +0000154 presentParameters.BackBufferFormat = gl_d3d9::GetRenderFormat(mBackBufferFormat, mRenderer);
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000155 presentParameters.EnableAutoDepthStencil = FALSE;
156 presentParameters.Flags = 0;
157 presentParameters.hDeviceWindow = mWindow;
158 presentParameters.MultiSampleQuality = 0; // FIXME: Unimplemented
159 presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; // FIXME: Unimplemented
160 presentParameters.PresentationInterval = convertInterval(swapInterval);
161 presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
162 presentParameters.Windowed = TRUE;
163 presentParameters.BackBufferWidth = backbufferWidth;
164 presentParameters.BackBufferHeight = backbufferHeight;
165
166 // http://crbug.com/140239
167 // http://crbug.com/143434
168 //
169 // Some AMD/Intel switchable systems / drivers appear to round swap chain surfaces to a multiple of 64 pixels in width
170 // when using the integrated Intel. This rounds the width up rather than down.
171 //
172 // Some non-switchable AMD GPUs / drivers do not respect the source rectangle to Present. Therefore, when the vendor ID
173 // 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 +0000174 if (mRenderer->getAdapterVendor() == VENDOR_ID_INTEL)
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000175 {
176 presentParameters.BackBufferWidth = (presentParameters.BackBufferWidth + 63) / 64 * 64;
177 }
178
179 result = device->CreateAdditionalSwapChain(&presentParameters, &mSwapChain);
180
181 if (FAILED(result))
182 {
183 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL || result == D3DERR_DEVICELOST);
184
185 ERR("Could not create additional swap chains or offscreen surfaces: %08lX", result);
186 release();
187
shannon.woods@transgaming.comf5f59492013-02-28 23:04:40 +0000188 if (d3d9::isDeviceLostError(result))
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000189 {
190 return EGL_CONTEXT_LOST;
191 }
192 else
193 {
194 return EGL_BAD_ALLOC;
195 }
196 }
197
198 result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer);
199 ASSERT(SUCCEEDED(result));
daniel@transgaming.comb323df02012-11-28 19:41:36 +0000200 InvalidateRect(mWindow, NULL, FALSE);
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000201 }
202
daniel@transgaming.coma60160b2012-11-28 19:41:15 +0000203 if (mDepthBufferFormat != GL_NONE)
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000204 {
205 result = device->CreateDepthStencilSurface(backbufferWidth, backbufferHeight,
shannonwoods@chromium.org755012f2013-05-30 00:09:32 +0000206 gl_d3d9::GetRenderFormat(mDepthBufferFormat, mRenderer),
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000207 D3DMULTISAMPLE_NONE, 0, FALSE, &mDepthStencil, NULL);
208
209 if (FAILED(result))
210 {
211 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL);
212
213 ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result);
214 release();
215
shannon.woods@transgaming.comf5f59492013-02-28 23:04:40 +0000216 if (d3d9::isDeviceLostError(result))
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000217 {
218 return EGL_CONTEXT_LOST;
219 }
220 else
221 {
222 return EGL_BAD_ALLOC;
223 }
224 }
225 }
226
227 mWidth = backbufferWidth;
228 mHeight = backbufferHeight;
shannon.woods@transgaming.comc71ca752013-02-28 23:06:50 +0000229 mSwapInterval = swapInterval;
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000230
231 return EGL_SUCCESS;
232}
233
234// parameters should be validated/clamped by caller
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +0000235EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height)
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000236{
237 if (!mSwapChain)
238 {
239 return EGL_SUCCESS;
240 }
241
242 IDirect3DDevice9 *device = mRenderer->getDevice();
243
244 // Disable all pipeline operations
245 device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
246 device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
247 device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
248 device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
249 device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
250 device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
251 device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
252 device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED);
253 device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE);
254 device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
255 device->SetPixelShader(NULL);
256 device->SetVertexShader(NULL);
257
258 device->SetRenderTarget(0, mBackBuffer);
259 device->SetDepthStencilSurface(NULL);
260
261 device->SetTexture(0, mOffscreenTexture);
262 device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
263 device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
264 device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
265 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
266 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
267 device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
268 device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
269 device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
270
271 D3DVIEWPORT9 viewport = {0, 0, mWidth, mHeight, 0.0f, 1.0f};
272 device->SetViewport(&viewport);
273
274 float x1 = x - 0.5f;
275 float y1 = (mHeight - y - height) - 0.5f;
276 float x2 = (x + width) - 0.5f;
277 float y2 = (mHeight - y) - 0.5f;
278
279 float u1 = x / float(mWidth);
280 float v1 = y / float(mHeight);
281 float u2 = (x + width) / float(mWidth);
282 float v2 = (y + height) / float(mHeight);
283
284 float quad[4][6] = {{x1, y1, 0.0f, 1.0f, u1, v2},
285 {x2, y1, 0.0f, 1.0f, u2, v2},
286 {x2, y2, 0.0f, 1.0f, u2, v1},
287 {x1, y2, 0.0f, 1.0f, u1, v1}}; // x, y, z, rhw, u, v
288
289 mRenderer->startScene();
290 device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, 6 * sizeof(float));
291 mRenderer->endScene();
292
293 device->SetTexture(0, NULL);
294
295 RECT rect =
296 {
297 x, mHeight - y - height,
298 x + width, mHeight - y
299 };
300
301 HRESULT result = mSwapChain->Present(&rect, &rect, NULL, NULL, 0);
302
daniel@transgaming.comc43a6052012-11-28 19:41:51 +0000303 mRenderer->markAllStateDirty();
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000304
shannon.woods@transgaming.comf5f59492013-02-28 23:04:40 +0000305 if (d3d9::isDeviceLostError(result))
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000306 {
307 return EGL_CONTEXT_LOST;
308 }
309
310 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DRIVERINTERNALERROR)
311 {
312 return EGL_BAD_ALLOC;
313 }
314
315 ASSERT(SUCCEEDED(result));
316
317 return EGL_SUCCESS;
318}
319
320// Increments refcount on surface.
321// caller must Release() the returned surface
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +0000322IDirect3DSurface9 *SwapChain9::getRenderTarget()
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000323{
324 if (mRenderTarget)
325 {
326 mRenderTarget->AddRef();
327 }
328
329 return mRenderTarget;
330}
331
332// Increments refcount on surface.
333// caller must Release() the returned surface
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +0000334IDirect3DSurface9 *SwapChain9::getDepthStencil()
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000335{
336 if (mDepthStencil)
337 {
338 mDepthStencil->AddRef();
339 }
340
341 return mDepthStencil;
342}
343
344// Increments refcount on texture.
345// caller must Release() the returned texture
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +0000346IDirect3DTexture9 *SwapChain9::getOffscreenTexture()
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000347{
348 if (mOffscreenTexture)
349 {
350 mOffscreenTexture->AddRef();
351 }
352
353 return mOffscreenTexture;
354}
355
daniel@transgaming.comd733bb82012-11-28 20:53:40 +0000356SwapChain9 *SwapChain9::makeSwapChain9(SwapChain *swapChain)
357{
apatrick@chromium.org8b400b12013-01-30 21:53:40 +0000358 ASSERT(HAS_DYNAMIC_TYPE(rx::SwapChain9*, swapChain));
daniel@transgaming.comd733bb82012-11-28 20:53:40 +0000359 return static_cast<rx::SwapChain9*>(swapChain);
360}
361
shannon.woods%transgaming.com@gtempaccount.com8bce3f52013-04-13 03:35:32 +0000362void SwapChain9::recreate()
363{
364 if (!mSwapChain)
365 {
366 return;
367 }
368
369 IDirect3DDevice9 *device = mRenderer->getDevice();
370 if (device == NULL)
371 {
372 return;
373 }
374
375 D3DPRESENT_PARAMETERS presentParameters;
376 HRESULT result = mSwapChain->GetPresentParameters(&presentParameters);
377 ASSERT(SUCCEEDED(result));
378
379 IDirect3DSwapChain9* newSwapChain = NULL;
380 result = device->CreateAdditionalSwapChain(&presentParameters, &newSwapChain);
381 if (FAILED(result))
382 {
383 return;
384 }
385
Geoff Langea228632013-07-30 15:17:12 -0400386 SafeRelease(mSwapChain);
shannon.woods%transgaming.com@gtempaccount.com8bce3f52013-04-13 03:35:32 +0000387 mSwapChain = newSwapChain;
388
Geoff Langea228632013-07-30 15:17:12 -0400389 SafeRelease(mBackBuffer);
shannon.woods%transgaming.com@gtempaccount.com8bce3f52013-04-13 03:35:32 +0000390 result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer);
391 ASSERT(SUCCEEDED(result));
392}
393
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000394}