1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/angle/src/libGLESv2/renderer/SwapChain9.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,434 @@ 1.4 +#include "precompiled.h" 1.5 +// 1.6 +// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. 1.7 +// Use of this source code is governed by a BSD-style license that can be 1.8 +// found in the LICENSE file. 1.9 +// 1.10 + 1.11 +// SwapChain9.cpp: Implements a back-end specific class for the D3D9 swap chain. 1.12 + 1.13 +#include "libGLESv2/renderer/SwapChain9.h" 1.14 +#include "libGLESv2/renderer/renderer9_utils.h" 1.15 +#include "libGLESv2/renderer/Renderer9.h" 1.16 + 1.17 +namespace rx 1.18 +{ 1.19 + 1.20 +SwapChain9::SwapChain9(Renderer9 *renderer, HWND window, HANDLE shareHandle, 1.21 + GLenum backBufferFormat, GLenum depthBufferFormat) 1.22 + : mRenderer(renderer), SwapChain(window, shareHandle, backBufferFormat, depthBufferFormat) 1.23 +{ 1.24 + mSwapChain = NULL; 1.25 + mBackBuffer = NULL; 1.26 + mDepthStencil = NULL; 1.27 + mRenderTarget = NULL; 1.28 + mOffscreenTexture = NULL; 1.29 + mWidth = -1; 1.30 + mHeight = -1; 1.31 + mSwapInterval = -1; 1.32 +} 1.33 + 1.34 +SwapChain9::~SwapChain9() 1.35 +{ 1.36 + release(); 1.37 +} 1.38 + 1.39 +void SwapChain9::release() 1.40 +{ 1.41 + if (mSwapChain) 1.42 + { 1.43 + mSwapChain->Release(); 1.44 + mSwapChain = NULL; 1.45 + } 1.46 + 1.47 + if (mBackBuffer) 1.48 + { 1.49 + mBackBuffer->Release(); 1.50 + mBackBuffer = NULL; 1.51 + } 1.52 + 1.53 + if (mDepthStencil) 1.54 + { 1.55 + mDepthStencil->Release(); 1.56 + mDepthStencil = NULL; 1.57 + } 1.58 + 1.59 + if (mRenderTarget) 1.60 + { 1.61 + mRenderTarget->Release(); 1.62 + mRenderTarget = NULL; 1.63 + } 1.64 + 1.65 + if (mOffscreenTexture) 1.66 + { 1.67 + mOffscreenTexture->Release(); 1.68 + mOffscreenTexture = NULL; 1.69 + } 1.70 + 1.71 + if (mWindow) 1.72 + mShareHandle = NULL; 1.73 +} 1.74 + 1.75 +static DWORD convertInterval(EGLint interval) 1.76 +{ 1.77 + switch(interval) 1.78 + { 1.79 + case 0: return D3DPRESENT_INTERVAL_IMMEDIATE; 1.80 + case 1: return D3DPRESENT_INTERVAL_ONE; 1.81 + case 2: return D3DPRESENT_INTERVAL_TWO; 1.82 + case 3: return D3DPRESENT_INTERVAL_THREE; 1.83 + case 4: return D3DPRESENT_INTERVAL_FOUR; 1.84 + default: UNREACHABLE(); 1.85 + } 1.86 + 1.87 + return D3DPRESENT_INTERVAL_DEFAULT; 1.88 +} 1.89 + 1.90 +EGLint SwapChain9::resize(int backbufferWidth, int backbufferHeight) 1.91 +{ 1.92 + // D3D9 does not support resizing swap chains without recreating them 1.93 + return reset(backbufferWidth, backbufferHeight, mSwapInterval); 1.94 +} 1.95 + 1.96 +EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapInterval) 1.97 +{ 1.98 + IDirect3DDevice9 *device = mRenderer->getDevice(); 1.99 + 1.100 + if (device == NULL) 1.101 + { 1.102 + return EGL_BAD_ACCESS; 1.103 + } 1.104 + 1.105 + // Evict all non-render target textures to system memory and release all resources 1.106 + // before reallocating them to free up as much video memory as possible. 1.107 + device->EvictManagedResources(); 1.108 + 1.109 + HRESULT result; 1.110 + 1.111 + // Release specific resources to free up memory for the new render target, while the 1.112 + // old render target still exists for the purpose of preserving its contents. 1.113 + if (mSwapChain) 1.114 + { 1.115 + mSwapChain->Release(); 1.116 + mSwapChain = NULL; 1.117 + } 1.118 + 1.119 + if (mBackBuffer) 1.120 + { 1.121 + mBackBuffer->Release(); 1.122 + mBackBuffer = NULL; 1.123 + } 1.124 + 1.125 + if (mOffscreenTexture) 1.126 + { 1.127 + mOffscreenTexture->Release(); 1.128 + mOffscreenTexture = NULL; 1.129 + } 1.130 + 1.131 + if (mDepthStencil) 1.132 + { 1.133 + mDepthStencil->Release(); 1.134 + mDepthStencil = NULL; 1.135 + } 1.136 + 1.137 + HANDLE *pShareHandle = NULL; 1.138 + if (!mWindow && mRenderer->getShareHandleSupport()) 1.139 + { 1.140 + pShareHandle = &mShareHandle; 1.141 + } 1.142 + 1.143 + result = device->CreateTexture(backbufferWidth, backbufferHeight, 1, D3DUSAGE_RENDERTARGET, 1.144 + gl_d3d9::ConvertRenderbufferFormat(mBackBufferFormat), D3DPOOL_DEFAULT, 1.145 + &mOffscreenTexture, pShareHandle); 1.146 + if (FAILED(result)) 1.147 + { 1.148 + ERR("Could not create offscreen texture: %08lX", result); 1.149 + release(); 1.150 + 1.151 + if (d3d9::isDeviceLostError(result)) 1.152 + { 1.153 + return EGL_CONTEXT_LOST; 1.154 + } 1.155 + else 1.156 + { 1.157 + return EGL_BAD_ALLOC; 1.158 + } 1.159 + } 1.160 + 1.161 + IDirect3DSurface9 *oldRenderTarget = mRenderTarget; 1.162 + 1.163 + result = mOffscreenTexture->GetSurfaceLevel(0, &mRenderTarget); 1.164 + ASSERT(SUCCEEDED(result)); 1.165 + 1.166 + if (oldRenderTarget) 1.167 + { 1.168 + RECT rect = 1.169 + { 1.170 + 0, 0, 1.171 + mWidth, mHeight 1.172 + }; 1.173 + 1.174 + if (rect.right > static_cast<LONG>(backbufferWidth)) 1.175 + { 1.176 + rect.right = backbufferWidth; 1.177 + } 1.178 + 1.179 + if (rect.bottom > static_cast<LONG>(backbufferHeight)) 1.180 + { 1.181 + rect.bottom = backbufferHeight; 1.182 + } 1.183 + 1.184 + mRenderer->endScene(); 1.185 + 1.186 + result = device->StretchRect(oldRenderTarget, &rect, mRenderTarget, &rect, D3DTEXF_NONE); 1.187 + ASSERT(SUCCEEDED(result)); 1.188 + 1.189 + oldRenderTarget->Release(); 1.190 + } 1.191 + 1.192 + if (mWindow) 1.193 + { 1.194 + D3DPRESENT_PARAMETERS presentParameters = {0}; 1.195 + presentParameters.AutoDepthStencilFormat = gl_d3d9::ConvertRenderbufferFormat(mDepthBufferFormat); 1.196 + presentParameters.BackBufferCount = 1; 1.197 + presentParameters.BackBufferFormat = gl_d3d9::ConvertRenderbufferFormat(mBackBufferFormat); 1.198 + presentParameters.EnableAutoDepthStencil = FALSE; 1.199 + presentParameters.Flags = 0; 1.200 + presentParameters.hDeviceWindow = mWindow; 1.201 + presentParameters.MultiSampleQuality = 0; // FIXME: Unimplemented 1.202 + presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; // FIXME: Unimplemented 1.203 + presentParameters.PresentationInterval = convertInterval(swapInterval); 1.204 + presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD; 1.205 + presentParameters.Windowed = TRUE; 1.206 + presentParameters.BackBufferWidth = backbufferWidth; 1.207 + presentParameters.BackBufferHeight = backbufferHeight; 1.208 + 1.209 + // http://crbug.com/140239 1.210 + // http://crbug.com/143434 1.211 + // 1.212 + // Some AMD/Intel switchable systems / drivers appear to round swap chain surfaces to a multiple of 64 pixels in width 1.213 + // when using the integrated Intel. This rounds the width up rather than down. 1.214 + // 1.215 + // Some non-switchable AMD GPUs / drivers do not respect the source rectangle to Present. Therefore, when the vendor ID 1.216 + // is not Intel, the back buffer width must be exactly the same width as the window or horizontal scaling will occur. 1.217 + if (mRenderer->getAdapterVendor() == VENDOR_ID_INTEL) 1.218 + { 1.219 + presentParameters.BackBufferWidth = (presentParameters.BackBufferWidth + 63) / 64 * 64; 1.220 + } 1.221 + 1.222 + result = device->CreateAdditionalSwapChain(&presentParameters, &mSwapChain); 1.223 + 1.224 + if (FAILED(result)) 1.225 + { 1.226 + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL || result == D3DERR_DEVICELOST); 1.227 + 1.228 + ERR("Could not create additional swap chains or offscreen surfaces: %08lX", result); 1.229 + release(); 1.230 + 1.231 + if (d3d9::isDeviceLostError(result)) 1.232 + { 1.233 + return EGL_CONTEXT_LOST; 1.234 + } 1.235 + else 1.236 + { 1.237 + return EGL_BAD_ALLOC; 1.238 + } 1.239 + } 1.240 + 1.241 + result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer); 1.242 + ASSERT(SUCCEEDED(result)); 1.243 + InvalidateRect(mWindow, NULL, FALSE); 1.244 + } 1.245 + 1.246 + if (mDepthBufferFormat != GL_NONE) 1.247 + { 1.248 + result = device->CreateDepthStencilSurface(backbufferWidth, backbufferHeight, 1.249 + gl_d3d9::ConvertRenderbufferFormat(mDepthBufferFormat), 1.250 + D3DMULTISAMPLE_NONE, 0, FALSE, &mDepthStencil, NULL); 1.251 + 1.252 + if (FAILED(result)) 1.253 + { 1.254 + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL); 1.255 + 1.256 + ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result); 1.257 + release(); 1.258 + 1.259 + if (d3d9::isDeviceLostError(result)) 1.260 + { 1.261 + return EGL_CONTEXT_LOST; 1.262 + } 1.263 + else 1.264 + { 1.265 + return EGL_BAD_ALLOC; 1.266 + } 1.267 + } 1.268 + } 1.269 + 1.270 + mWidth = backbufferWidth; 1.271 + mHeight = backbufferHeight; 1.272 + mSwapInterval = swapInterval; 1.273 + 1.274 + return EGL_SUCCESS; 1.275 +} 1.276 + 1.277 +// parameters should be validated/clamped by caller 1.278 +EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) 1.279 +{ 1.280 + if (!mSwapChain) 1.281 + { 1.282 + return EGL_SUCCESS; 1.283 + } 1.284 + 1.285 + IDirect3DDevice9 *device = mRenderer->getDevice(); 1.286 + 1.287 + // Disable all pipeline operations 1.288 + device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); 1.289 + device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); 1.290 + device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); 1.291 + device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); 1.292 + device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); 1.293 + device->SetRenderState(D3DRS_STENCILENABLE, FALSE); 1.294 + device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); 1.295 + device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); 1.296 + device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE); 1.297 + device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); 1.298 + device->SetPixelShader(NULL); 1.299 + device->SetVertexShader(NULL); 1.300 + 1.301 + device->SetRenderTarget(0, mBackBuffer); 1.302 + device->SetDepthStencilSurface(NULL); 1.303 + 1.304 + device->SetTexture(0, mOffscreenTexture); 1.305 + device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); 1.306 + device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); 1.307 + device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); 1.308 + device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); 1.309 + device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); 1.310 + device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); 1.311 + device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); 1.312 + device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); 1.313 + 1.314 + D3DVIEWPORT9 viewport = {0, 0, mWidth, mHeight, 0.0f, 1.0f}; 1.315 + device->SetViewport(&viewport); 1.316 + 1.317 + float x1 = x - 0.5f; 1.318 + float y1 = (mHeight - y - height) - 0.5f; 1.319 + float x2 = (x + width) - 0.5f; 1.320 + float y2 = (mHeight - y) - 0.5f; 1.321 + 1.322 + float u1 = x / float(mWidth); 1.323 + float v1 = y / float(mHeight); 1.324 + float u2 = (x + width) / float(mWidth); 1.325 + float v2 = (y + height) / float(mHeight); 1.326 + 1.327 + float quad[4][6] = {{x1, y1, 0.0f, 1.0f, u1, v2}, 1.328 + {x2, y1, 0.0f, 1.0f, u2, v2}, 1.329 + {x2, y2, 0.0f, 1.0f, u2, v1}, 1.330 + {x1, y2, 0.0f, 1.0f, u1, v1}}; // x, y, z, rhw, u, v 1.331 + 1.332 + mRenderer->startScene(); 1.333 + device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, 6 * sizeof(float)); 1.334 + mRenderer->endScene(); 1.335 + 1.336 + device->SetTexture(0, NULL); 1.337 + 1.338 + RECT rect = 1.339 + { 1.340 + x, mHeight - y - height, 1.341 + x + width, mHeight - y 1.342 + }; 1.343 + 1.344 + HRESULT result = mSwapChain->Present(&rect, &rect, NULL, NULL, 0); 1.345 + 1.346 + mRenderer->markAllStateDirty(); 1.347 + 1.348 + if (d3d9::isDeviceLostError(result)) 1.349 + { 1.350 + return EGL_CONTEXT_LOST; 1.351 + } 1.352 + 1.353 + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DRIVERINTERNALERROR) 1.354 + { 1.355 + return EGL_BAD_ALLOC; 1.356 + } 1.357 + 1.358 + ASSERT(SUCCEEDED(result)); 1.359 + 1.360 + return EGL_SUCCESS; 1.361 +} 1.362 + 1.363 +// Increments refcount on surface. 1.364 +// caller must Release() the returned surface 1.365 +IDirect3DSurface9 *SwapChain9::getRenderTarget() 1.366 +{ 1.367 + if (mRenderTarget) 1.368 + { 1.369 + mRenderTarget->AddRef(); 1.370 + } 1.371 + 1.372 + return mRenderTarget; 1.373 +} 1.374 + 1.375 +// Increments refcount on surface. 1.376 +// caller must Release() the returned surface 1.377 +IDirect3DSurface9 *SwapChain9::getDepthStencil() 1.378 +{ 1.379 + if (mDepthStencil) 1.380 + { 1.381 + mDepthStencil->AddRef(); 1.382 + } 1.383 + 1.384 + return mDepthStencil; 1.385 +} 1.386 + 1.387 +// Increments refcount on texture. 1.388 +// caller must Release() the returned texture 1.389 +IDirect3DTexture9 *SwapChain9::getOffscreenTexture() 1.390 +{ 1.391 + if (mOffscreenTexture) 1.392 + { 1.393 + mOffscreenTexture->AddRef(); 1.394 + } 1.395 + 1.396 + return mOffscreenTexture; 1.397 +} 1.398 + 1.399 +SwapChain9 *SwapChain9::makeSwapChain9(SwapChain *swapChain) 1.400 +{ 1.401 + ASSERT(HAS_DYNAMIC_TYPE(rx::SwapChain9*, swapChain)); 1.402 + return static_cast<rx::SwapChain9*>(swapChain); 1.403 +} 1.404 + 1.405 +void SwapChain9::recreate() 1.406 +{ 1.407 + if (!mSwapChain) 1.408 + { 1.409 + return; 1.410 + } 1.411 + 1.412 + IDirect3DDevice9 *device = mRenderer->getDevice(); 1.413 + if (device == NULL) 1.414 + { 1.415 + return; 1.416 + } 1.417 + 1.418 + D3DPRESENT_PARAMETERS presentParameters; 1.419 + HRESULT result = mSwapChain->GetPresentParameters(&presentParameters); 1.420 + ASSERT(SUCCEEDED(result)); 1.421 + 1.422 + IDirect3DSwapChain9* newSwapChain = NULL; 1.423 + result = device->CreateAdditionalSwapChain(&presentParameters, &newSwapChain); 1.424 + if (FAILED(result)) 1.425 + { 1.426 + return; 1.427 + } 1.428 + 1.429 + mSwapChain->Release(); 1.430 + mSwapChain = newSwapChain; 1.431 + 1.432 + mBackBuffer->Release(); 1.433 + result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer); 1.434 + ASSERT(SUCCEEDED(result)); 1.435 +} 1.436 + 1.437 +}