1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/layers/d3d10/ThebesLayerD3D10.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,499 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "mozilla/layers/PLayerTransaction.h" 1.10 + 1.11 +// This must occur *after* layers/PLayerTransaction.h to avoid 1.12 +// typedefs conflicts. 1.13 +#include "mozilla/ArrayUtils.h" 1.14 + 1.15 +#include "ThebesLayerD3D10.h" 1.16 +#include "gfxPlatform.h" 1.17 + 1.18 +#include "gfxWindowsPlatform.h" 1.19 +#ifdef CAIRO_HAS_D2D_SURFACE 1.20 +#include "gfxD2DSurface.h" 1.21 +#endif 1.22 + 1.23 +#include "../d3d9/Nv3DVUtils.h" 1.24 +#include "gfxTeeSurface.h" 1.25 +#include "gfxUtils.h" 1.26 +#include "ReadbackLayer.h" 1.27 +#include "ReadbackProcessor.h" 1.28 + 1.29 +#include "mozilla/Preferences.h" 1.30 +#include "mozilla/gfx/2D.h" 1.31 + 1.32 +using namespace mozilla::gfx; 1.33 + 1.34 +namespace mozilla { 1.35 +namespace layers { 1.36 + 1.37 +ThebesLayerD3D10::ThebesLayerD3D10(LayerManagerD3D10 *aManager) 1.38 + : ThebesLayer(aManager, nullptr) 1.39 + , LayerD3D10(aManager) 1.40 + , mCurrentSurfaceMode(SurfaceMode::SURFACE_OPAQUE) 1.41 +{ 1.42 + mImplData = static_cast<LayerD3D10*>(this); 1.43 +} 1.44 + 1.45 +ThebesLayerD3D10::~ThebesLayerD3D10() 1.46 +{ 1.47 +} 1.48 + 1.49 +void 1.50 +ThebesLayerD3D10::InvalidateRegion(const nsIntRegion &aRegion) 1.51 +{ 1.52 + mInvalidRegion.Or(mInvalidRegion, aRegion); 1.53 + mInvalidRegion.SimplifyOutward(20); 1.54 + mValidRegion.Sub(mValidRegion, mInvalidRegion); 1.55 +} 1.56 + 1.57 +void ThebesLayerD3D10::CopyRegion(ID3D10Texture2D* aSrc, const nsIntPoint &aSrcOffset, 1.58 + ID3D10Texture2D* aDest, const nsIntPoint &aDestOffset, 1.59 + const nsIntRegion &aCopyRegion, nsIntRegion* aValidRegion) 1.60 +{ 1.61 + nsIntRegion retainedRegion; 1.62 + nsIntRegionRectIterator iter(aCopyRegion); 1.63 + const nsIntRect *r; 1.64 + while ((r = iter.Next())) { 1.65 + // Calculate the retained rectangle's position on the old and the new 1.66 + // surface. 1.67 + D3D10_BOX box; 1.68 + box.left = r->x - aSrcOffset.x; 1.69 + box.top = r->y - aSrcOffset.y; 1.70 + box.right = box.left + r->width; 1.71 + box.bottom = box.top + r->height; 1.72 + box.back = 1; 1.73 + box.front = 0; 1.74 + 1.75 + device()->CopySubresourceRegion(aDest, 0, 1.76 + r->x - aDestOffset.x, 1.77 + r->y - aDestOffset.y, 1.78 + 0, 1.79 + aSrc, 0, 1.80 + &box); 1.81 + 1.82 + retainedRegion.Or(retainedRegion, *r); 1.83 + } 1.84 + 1.85 + // Areas which were valid and were retained are still valid 1.86 + aValidRegion->And(*aValidRegion, retainedRegion); 1.87 +} 1.88 + 1.89 +void 1.90 +ThebesLayerD3D10::RenderLayer() 1.91 +{ 1.92 + if (!mTexture) { 1.93 + return; 1.94 + } 1.95 + 1.96 + SetEffectTransformAndOpacity(); 1.97 + 1.98 + ID3D10EffectTechnique *technique; 1.99 + switch (mCurrentSurfaceMode) { 1.100 + case SurfaceMode::SURFACE_COMPONENT_ALPHA: 1.101 + technique = SelectShader(SHADER_COMPONENT_ALPHA | LoadMaskTexture()); 1.102 + break; 1.103 + case SurfaceMode::SURFACE_OPAQUE: 1.104 + technique = SelectShader(SHADER_RGB | SHADER_PREMUL | LoadMaskTexture()); 1.105 + break; 1.106 + case SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA: 1.107 + technique = SelectShader(SHADER_RGBA | SHADER_PREMUL | LoadMaskTexture()); 1.108 + break; 1.109 + default: 1.110 + NS_ERROR("Unknown mode"); 1.111 + return; 1.112 + } 1.113 + 1.114 + nsIntRegionRectIterator iter(mVisibleRegion); 1.115 + 1.116 + const nsIntRect *iterRect; 1.117 + if (mSRView) { 1.118 + effect()->GetVariableByName("tRGB")->AsShaderResource()->SetResource(mSRView); 1.119 + } 1.120 + if (mSRViewOnWhite) { 1.121 + effect()->GetVariableByName("tRGBWhite")->AsShaderResource()->SetResource(mSRViewOnWhite); 1.122 + } 1.123 + 1.124 + while ((iterRect = iter.Next())) { 1.125 + effect()->GetVariableByName("vLayerQuad")->AsVector()->SetFloatVector( 1.126 + ShaderConstantRectD3D10( 1.127 + (float)iterRect->x, 1.128 + (float)iterRect->y, 1.129 + (float)iterRect->width, 1.130 + (float)iterRect->height) 1.131 + ); 1.132 + 1.133 + effect()->GetVariableByName("vTextureCoords")->AsVector()->SetFloatVector( 1.134 + ShaderConstantRectD3D10( 1.135 + (float)(iterRect->x - mTextureRect.x) / (float)mTextureRect.width, 1.136 + (float)(iterRect->y - mTextureRect.y) / (float)mTextureRect.height, 1.137 + (float)iterRect->width / (float)mTextureRect.width, 1.138 + (float)iterRect->height / (float)mTextureRect.height) 1.139 + ); 1.140 + 1.141 + technique->GetPassByIndex(0)->Apply(0); 1.142 + device()->Draw(4, 0); 1.143 + } 1.144 + 1.145 + // Set back to default. 1.146 + effect()->GetVariableByName("vTextureCoords")->AsVector()-> 1.147 + SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f)); 1.148 +} 1.149 + 1.150 +void 1.151 +ThebesLayerD3D10::Validate(ReadbackProcessor *aReadback) 1.152 +{ 1.153 + if (mVisibleRegion.IsEmpty()) { 1.154 + return; 1.155 + } 1.156 + 1.157 + if (FAILED(gfxWindowsPlatform::GetPlatform()->GetD3D10Device()->GetDeviceRemovedReason())) { 1.158 + // Device removed, this will be discovered on the next rendering pass. 1.159 + // Do no validate. 1.160 + return; 1.161 + } 1.162 + 1.163 + nsIntRect newTextureRect = mVisibleRegion.GetBounds(); 1.164 + 1.165 + SurfaceMode mode = GetSurfaceMode(); 1.166 + if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA && 1.167 + (!mParent || !mParent->SupportsComponentAlphaChildren())) { 1.168 + mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA; 1.169 + } 1.170 + // If we have a transform that requires resampling of our texture, then 1.171 + // we need to make sure we don't sample pixels that haven't been drawn. 1.172 + // We clamp sample coordinates to the texture rect, but when the visible region 1.173 + // doesn't fill the entire texture rect we need to make sure we draw all the 1.174 + // pixels in the texture rect anyway in case they get sampled. 1.175 + nsIntRegion neededRegion = mVisibleRegion; 1.176 + if (!neededRegion.GetBounds().IsEqualInterior(newTextureRect) || 1.177 + neededRegion.GetNumRects() > 1) { 1.178 + if (MayResample()) { 1.179 + neededRegion = newTextureRect; 1.180 + if (mode == SurfaceMode::SURFACE_OPAQUE) { 1.181 + // We're going to paint outside the visible region, but layout hasn't 1.182 + // promised that it will paint opaquely there, so we'll have to 1.183 + // treat this layer as transparent. 1.184 + mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA; 1.185 + } 1.186 + } 1.187 + } 1.188 + mCurrentSurfaceMode = mode; 1.189 + 1.190 + VerifyContentType(mode); 1.191 + 1.192 + nsTArray<ReadbackProcessor::Update> readbackUpdates; 1.193 + nsIntRegion readbackRegion; 1.194 + if (aReadback && UsedForReadback()) { 1.195 + aReadback->GetThebesLayerUpdates(this, &readbackUpdates, &readbackRegion); 1.196 + } 1.197 + 1.198 + if (mTexture) { 1.199 + if (!mTextureRect.IsEqualInterior(newTextureRect)) { 1.200 + nsRefPtr<ID3D10Texture2D> oldTexture = mTexture; 1.201 + mTexture = nullptr; 1.202 + nsRefPtr<ID3D10Texture2D> oldTextureOnWhite = mTextureOnWhite; 1.203 + mTextureOnWhite = nullptr; 1.204 + 1.205 + nsIntRegion retainRegion = mTextureRect; 1.206 + // Old visible region will become the region that is covered by both the 1.207 + // old and the new visible region. 1.208 + retainRegion.And(retainRegion, mVisibleRegion); 1.209 + // No point in retaining parts which were not valid. 1.210 + retainRegion.And(retainRegion, mValidRegion); 1.211 + 1.212 + CreateNewTextures(gfx::IntSize(newTextureRect.width, newTextureRect.height), mode); 1.213 + 1.214 + nsIntRect largeRect = retainRegion.GetLargestRectangle(); 1.215 + 1.216 + // If we had no hardware texture before, or have no retained area larger than 1.217 + // the retention threshold, we're not retaining and are done here. 1.218 + // If our texture creation failed this can mean a device reset is pending 1.219 + // and we should silently ignore the failure. In the future when device 1.220 + // failures are properly handled we should test for the type of failure 1.221 + // and gracefully handle different failures. See bug 569081. 1.222 + if (!oldTexture || !mTexture) { 1.223 + mValidRegion.SetEmpty(); 1.224 + } else { 1.225 + CopyRegion(oldTexture, mTextureRect.TopLeft(), 1.226 + mTexture, newTextureRect.TopLeft(), 1.227 + retainRegion, &mValidRegion); 1.228 + if (oldTextureOnWhite) { 1.229 + CopyRegion(oldTextureOnWhite, mTextureRect.TopLeft(), 1.230 + mTextureOnWhite, newTextureRect.TopLeft(), 1.231 + retainRegion, &mValidRegion); 1.232 + } 1.233 + } 1.234 + } 1.235 + } 1.236 + mTextureRect = newTextureRect; 1.237 + 1.238 + if (!mTexture || (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA && !mTextureOnWhite)) { 1.239 + CreateNewTextures(gfx::IntSize(newTextureRect.width, newTextureRect.height), mode); 1.240 + mValidRegion.SetEmpty(); 1.241 + } 1.242 + 1.243 + nsIntRegion drawRegion; 1.244 + drawRegion.Sub(neededRegion, mValidRegion); 1.245 + 1.246 + if (!drawRegion.IsEmpty()) { 1.247 + LayerManagerD3D10::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo(); 1.248 + if (!cbInfo.Callback) { 1.249 + NS_ERROR("D3D10 should never need to update ThebesLayers in an empty transaction"); 1.250 + return; 1.251 + } 1.252 + 1.253 + DrawRegion(drawRegion, mode); 1.254 + 1.255 + if (readbackUpdates.Length() > 0) { 1.256 + CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, 1.257 + newTextureRect.width, newTextureRect.height, 1.258 + 1, 1, 0, D3D10_USAGE_STAGING, 1.259 + D3D10_CPU_ACCESS_READ); 1.260 + 1.261 + nsRefPtr<ID3D10Texture2D> readbackTexture; 1.262 + HRESULT hr = device()->CreateTexture2D(&desc, nullptr, getter_AddRefs(readbackTexture)); 1.263 + if (FAILED(hr)) { 1.264 + LayerManagerD3D10::ReportFailure(NS_LITERAL_CSTRING("ThebesLayerD3D10::Validate(): Failed to create texture"), 1.265 + hr); 1.266 + return; 1.267 + } 1.268 + 1.269 + device()->CopyResource(readbackTexture, mTexture); 1.270 + 1.271 + for (uint32_t i = 0; i < readbackUpdates.Length(); i++) { 1.272 + mD3DManager->readbackManager()->PostTask(readbackTexture, 1.273 + &readbackUpdates[i], 1.274 + gfxPoint(newTextureRect.x, newTextureRect.y)); 1.275 + } 1.276 + } 1.277 + 1.278 + mValidRegion = neededRegion; 1.279 + } 1.280 +} 1.281 + 1.282 +void 1.283 +ThebesLayerD3D10::LayerManagerDestroyed() 1.284 +{ 1.285 + mD3DManager = nullptr; 1.286 +} 1.287 + 1.288 +Layer* 1.289 +ThebesLayerD3D10::GetLayer() 1.290 +{ 1.291 + return this; 1.292 +} 1.293 + 1.294 +void 1.295 +ThebesLayerD3D10::VerifyContentType(SurfaceMode aMode) 1.296 +{ 1.297 + if (mD2DSurface) { 1.298 + gfxContentType type = aMode != SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA ? 1.299 + gfxContentType::COLOR : gfxContentType::COLOR_ALPHA; 1.300 + 1.301 + if (type != mD2DSurface->GetContentType()) { 1.302 + mD2DSurface = new gfxD2DSurface(mTexture, type); 1.303 + 1.304 + if (!mD2DSurface || mD2DSurface->CairoStatus()) { 1.305 + NS_WARNING("Failed to create surface for ThebesLayerD3D10."); 1.306 + mD2DSurface = nullptr; 1.307 + return; 1.308 + } 1.309 + 1.310 + mValidRegion.SetEmpty(); 1.311 + } 1.312 + } else if (mDrawTarget) { 1.313 + SurfaceFormat format = aMode != SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA ? 1.314 + SurfaceFormat::B8G8R8X8 : SurfaceFormat::B8G8R8A8; 1.315 + 1.316 + if (format != mDrawTarget->GetFormat()) { 1.317 + mDrawTarget = Factory::CreateDrawTargetForD3D10Texture(mTexture, format); 1.318 + 1.319 + if (!mDrawTarget) { 1.320 + NS_WARNING("Failed to create drawtarget for ThebesLayerD3D10."); 1.321 + return; 1.322 + } 1.323 + 1.324 + mValidRegion.SetEmpty(); 1.325 + } 1.326 + } 1.327 + 1.328 + if (aMode != SurfaceMode::SURFACE_COMPONENT_ALPHA && mTextureOnWhite) { 1.329 + // If we've transitioned away from component alpha, we can delete those resources. 1.330 + mD2DSurfaceOnWhite = nullptr; 1.331 + mSRViewOnWhite = nullptr; 1.332 + mTextureOnWhite = nullptr; 1.333 + mValidRegion.SetEmpty(); 1.334 + } 1.335 +} 1.336 + 1.337 +void 1.338 +ThebesLayerD3D10::FillTexturesBlackWhite(const nsIntRegion& aRegion, const nsIntPoint& aOffset) 1.339 +{ 1.340 + if (mTexture && mTextureOnWhite) { 1.341 + // It would be more optimal to draw the actual geometry, but more code 1.342 + // and probably not worth the win here as this will often be a single 1.343 + // rect. 1.344 + nsRefPtr<ID3D10RenderTargetView> oldRT; 1.345 + device()->OMGetRenderTargets(1, getter_AddRefs(oldRT), nullptr); 1.346 + 1.347 + nsRefPtr<ID3D10RenderTargetView> viewBlack; 1.348 + nsRefPtr<ID3D10RenderTargetView> viewWhite; 1.349 + device()->CreateRenderTargetView(mTexture, nullptr, getter_AddRefs(viewBlack)); 1.350 + device()->CreateRenderTargetView(mTextureOnWhite, nullptr, getter_AddRefs(viewWhite)); 1.351 + 1.352 + D3D10_RECT oldScissor; 1.353 + UINT numRects = 1; 1.354 + device()->RSGetScissorRects(&numRects, &oldScissor); 1.355 + 1.356 + D3D10_TEXTURE2D_DESC desc; 1.357 + mTexture->GetDesc(&desc); 1.358 + 1.359 + D3D10_RECT scissor = { 0, 0, desc.Width, desc.Height }; 1.360 + device()->RSSetScissorRects(1, &scissor); 1.361 + 1.362 + mD3DManager->SetupInputAssembler(); 1.363 + nsIntSize oldVP = mD3DManager->GetViewport(); 1.364 + 1.365 + mD3DManager->SetViewport(nsIntSize(desc.Width, desc.Height)); 1.366 + 1.367 + ID3D10RenderTargetView *views[2] = { viewBlack, viewWhite }; 1.368 + device()->OMSetRenderTargets(2, views, nullptr); 1.369 + 1.370 + gfx3DMatrix transform; 1.371 + transform.Translate(gfxPoint3D(-aOffset.x, -aOffset.y, 0)); 1.372 + void* raw = &const_cast<gfx3DMatrix&>(transform)._11; 1.373 + effect()->GetVariableByName("mLayerTransform")->SetRawValue(raw, 0, 64); 1.374 + 1.375 + ID3D10EffectTechnique *technique = 1.376 + effect()->GetTechniqueByName("PrepareAlphaExtractionTextures"); 1.377 + 1.378 + nsIntRegionRectIterator iter(aRegion); 1.379 + 1.380 + const nsIntRect *iterRect; 1.381 + while ((iterRect = iter.Next())) { 1.382 + effect()->GetVariableByName("vLayerQuad")->AsVector()->SetFloatVector( 1.383 + ShaderConstantRectD3D10( 1.384 + (float)iterRect->x, 1.385 + (float)iterRect->y, 1.386 + (float)iterRect->width, 1.387 + (float)iterRect->height) 1.388 + ); 1.389 + 1.390 + technique->GetPassByIndex(0)->Apply(0); 1.391 + device()->Draw(4, 0); 1.392 + } 1.393 + 1.394 + views[0] = oldRT; 1.395 + device()->OMSetRenderTargets(1, views, nullptr); 1.396 + mD3DManager->SetViewport(oldVP); 1.397 + device()->RSSetScissorRects(1, &oldScissor); 1.398 + } 1.399 +} 1.400 + 1.401 +void 1.402 +ThebesLayerD3D10::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode) 1.403 +{ 1.404 + nsIntRect visibleRect = mVisibleRegion.GetBounds(); 1.405 + 1.406 + if (!mD2DSurface && !mDrawTarget) { 1.407 + return; 1.408 + } 1.409 + 1.410 + aRegion.SimplifyOutwardByArea(100 * 100); 1.411 + 1.412 + nsRefPtr<gfxASurface> destinationSurface; 1.413 + 1.414 + if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) { 1.415 + FillTexturesBlackWhite(aRegion, visibleRect.TopLeft()); 1.416 + } else { 1.417 + destinationSurface = mD2DSurface; 1.418 + } 1.419 + 1.420 + MOZ_ASSERT(mDrawTarget); 1.421 + nsRefPtr<gfxContext> context = new gfxContext(mDrawTarget); 1.422 + 1.423 + context->Translate(gfxPoint(-visibleRect.x, -visibleRect.y)); 1.424 + if (aMode == SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA) { 1.425 + nsIntRegionRectIterator iter(aRegion); 1.426 + const nsIntRect *iterRect; 1.427 + while ((iterRect = iter.Next())) { 1.428 + mDrawTarget->ClearRect(Rect(iterRect->x, iterRect->y, iterRect->width, iterRect->height)); 1.429 + } 1.430 + } 1.431 + 1.432 + mDrawTarget->SetPermitSubpixelAA(!(mContentFlags & CONTENT_COMPONENT_ALPHA)); 1.433 + 1.434 + LayerManagerD3D10::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo(); 1.435 + cbInfo.Callback(this, context, aRegion, DrawRegionClip::DRAW, nsIntRegion(), cbInfo.CallbackData); 1.436 +} 1.437 + 1.438 +void 1.439 +ThebesLayerD3D10::CreateNewTextures(const gfx::IntSize &aSize, SurfaceMode aMode) 1.440 +{ 1.441 + if (aSize.width == 0 || aSize.height == 0) { 1.442 + // Nothing to do. 1.443 + return; 1.444 + } 1.445 + 1.446 + CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, aSize.width, aSize.height, 1, 1); 1.447 + desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE; 1.448 + desc.MiscFlags = D3D10_RESOURCE_MISC_GDI_COMPATIBLE; 1.449 + HRESULT hr; 1.450 + 1.451 + if (!mTexture) { 1.452 + hr = device()->CreateTexture2D(&desc, nullptr, getter_AddRefs(mTexture)); 1.453 + 1.454 + if (FAILED(hr)) { 1.455 + NS_WARNING("Failed to create new texture for ThebesLayerD3D10!"); 1.456 + return; 1.457 + } 1.458 + 1.459 + hr = device()->CreateShaderResourceView(mTexture, nullptr, getter_AddRefs(mSRView)); 1.460 + 1.461 + if (FAILED(hr)) { 1.462 + NS_WARNING("Failed to create shader resource view for ThebesLayerD3D10."); 1.463 + } 1.464 + 1.465 + mDrawTarget = nullptr; 1.466 + } 1.467 + 1.468 + if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA && !mTextureOnWhite) { 1.469 + hr = device()->CreateTexture2D(&desc, nullptr, getter_AddRefs(mTextureOnWhite)); 1.470 + 1.471 + if (FAILED(hr)) { 1.472 + NS_WARNING("Failed to create new texture for ThebesLayerD3D10!"); 1.473 + return; 1.474 + } 1.475 + 1.476 + hr = device()->CreateShaderResourceView(mTextureOnWhite, nullptr, getter_AddRefs(mSRViewOnWhite)); 1.477 + 1.478 + if (FAILED(hr)) { 1.479 + NS_WARNING("Failed to create shader resource view for ThebesLayerD3D10."); 1.480 + } 1.481 + 1.482 + mDrawTarget = nullptr; 1.483 + } 1.484 + 1.485 + if (!mDrawTarget) { 1.486 + if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) { 1.487 + mDrawTarget = Factory::CreateDualDrawTargetForD3D10Textures(mTexture, mTextureOnWhite, SurfaceFormat::B8G8R8X8); 1.488 + } else { 1.489 + mDrawTarget = Factory::CreateDrawTargetForD3D10Texture(mTexture, aMode != SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA ? 1.490 + SurfaceFormat::B8G8R8X8 : SurfaceFormat::B8G8R8A8); 1.491 + } 1.492 + 1.493 + if (!mDrawTarget) { 1.494 + NS_WARNING("Failed to create DrawTarget for ThebesLayerD3D10."); 1.495 + mDrawTarget = nullptr; 1.496 + return; 1.497 + } 1.498 + } 1.499 +} 1.500 + 1.501 +} /* namespace layers */ 1.502 +} /* namespace mozilla */