1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/layers/d3d9/ThebesLayerD3D9.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,633 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- 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 "ThebesLayerD3D9.h" 1.16 +#include "gfxPlatform.h" 1.17 + 1.18 +#include "gfxWindowsPlatform.h" 1.19 +#include "gfxTeeSurface.h" 1.20 +#include "gfxUtils.h" 1.21 +#include "ReadbackProcessor.h" 1.22 +#include "ReadbackLayer.h" 1.23 +#include "mozilla/gfx/2D.h" 1.24 + 1.25 +namespace mozilla { 1.26 +namespace layers { 1.27 + 1.28 +using namespace gfx; 1.29 + 1.30 +ThebesLayerD3D9::ThebesLayerD3D9(LayerManagerD3D9 *aManager) 1.31 + : ThebesLayer(aManager, nullptr) 1.32 + , LayerD3D9(aManager) 1.33 +{ 1.34 + mImplData = static_cast<LayerD3D9*>(this); 1.35 + aManager->deviceManager()->mLayersWithResources.AppendElement(this); 1.36 +} 1.37 + 1.38 +ThebesLayerD3D9::~ThebesLayerD3D9() 1.39 +{ 1.40 + if (mD3DManager) { 1.41 + mD3DManager->deviceManager()->mLayersWithResources.RemoveElement(this); 1.42 + } 1.43 +} 1.44 + 1.45 +/** 1.46 + * Retention threshold - amount of pixels intersection required to enable 1.47 + * layer content retention. This is a guesstimate. Profiling could be done to 1.48 + * figure out the optimal threshold. 1.49 + */ 1.50 +#define RETENTION_THRESHOLD 16384 1.51 + 1.52 +void 1.53 +ThebesLayerD3D9::InvalidateRegion(const nsIntRegion &aRegion) 1.54 +{ 1.55 + mInvalidRegion.Or(mInvalidRegion, aRegion); 1.56 + mInvalidRegion.SimplifyOutward(20); 1.57 + mValidRegion.Sub(mValidRegion, mInvalidRegion); 1.58 +} 1.59 + 1.60 +void 1.61 +ThebesLayerD3D9::CopyRegion(IDirect3DTexture9* aSrc, const nsIntPoint &aSrcOffset, 1.62 + IDirect3DTexture9* aDest, const nsIntPoint &aDestOffset, 1.63 + const nsIntRegion &aCopyRegion, nsIntRegion* aValidRegion) 1.64 +{ 1.65 + nsRefPtr<IDirect3DSurface9> srcSurface, dstSurface; 1.66 + aSrc->GetSurfaceLevel(0, getter_AddRefs(srcSurface)); 1.67 + aDest->GetSurfaceLevel(0, getter_AddRefs(dstSurface)); 1.68 + 1.69 + nsIntRegion retainedRegion; 1.70 + nsIntRegionRectIterator iter(aCopyRegion); 1.71 + const nsIntRect *r; 1.72 + while ((r = iter.Next())) { 1.73 + if (r->width * r->height > RETENTION_THRESHOLD) { 1.74 + RECT oldRect, newRect; 1.75 + 1.76 + // Calculate the retained rectangle's position on the old and the new 1.77 + // surface. 1.78 + oldRect.left = r->x - aSrcOffset.x; 1.79 + oldRect.top = r->y - aSrcOffset.y; 1.80 + oldRect.right = oldRect.left + r->width; 1.81 + oldRect.bottom = oldRect.top + r->height; 1.82 + 1.83 + newRect.left = r->x - aDestOffset.x; 1.84 + newRect.top = r->y - aDestOffset.y; 1.85 + newRect.right = newRect.left + r->width; 1.86 + newRect.bottom = newRect.top + r->height; 1.87 + 1.88 + // Copy data from our old texture to the new one 1.89 + HRESULT hr = device()-> 1.90 + StretchRect(srcSurface, &oldRect, dstSurface, &newRect, D3DTEXF_NONE); 1.91 + 1.92 + if (SUCCEEDED(hr)) { 1.93 + retainedRegion.Or(retainedRegion, *r); 1.94 + } 1.95 + } 1.96 + } 1.97 + 1.98 + // Areas which were valid and were retained are still valid 1.99 + aValidRegion->And(*aValidRegion, retainedRegion); 1.100 +} 1.101 + 1.102 +static uint64_t RectArea(const nsIntRect& aRect) 1.103 +{ 1.104 + return aRect.width*uint64_t(aRect.height); 1.105 +} 1.106 + 1.107 +void 1.108 +ThebesLayerD3D9::UpdateTextures(SurfaceMode aMode) 1.109 +{ 1.110 + nsIntRect visibleRect = mVisibleRegion.GetBounds(); 1.111 + 1.112 + if (HaveTextures(aMode)) { 1.113 + if (!mTextureRect.IsEqualInterior(visibleRect)) { 1.114 + nsRefPtr<IDirect3DTexture9> oldTexture = mTexture; 1.115 + nsRefPtr<IDirect3DTexture9> oldTextureOnWhite = mTextureOnWhite; 1.116 + 1.117 + NS_ASSERTION(mTextureRect.Contains(mValidRegion.GetBounds()), 1.118 + "How can we have valid data outside the texture?"); 1.119 + nsIntRegion retainRegion; 1.120 + // The region we want to retain is the valid data that is inside 1.121 + // the new visible region 1.122 + retainRegion.And(mValidRegion, mVisibleRegion); 1.123 + 1.124 + CreateNewTextures(gfx::IntSize(visibleRect.width, visibleRect.height), aMode); 1.125 + 1.126 + // If our texture creation failed this can mean a device reset is pending and we 1.127 + // should silently ignore the failure. In the future when device failures 1.128 + // are properly handled we should test for the type of failure and gracefully 1.129 + // handle different failures. See bug 569081. 1.130 + if (!HaveTextures(aMode)) { 1.131 + mValidRegion.SetEmpty(); 1.132 + } else { 1.133 + CopyRegion(oldTexture, mTextureRect.TopLeft(), mTexture, visibleRect.TopLeft(), 1.134 + retainRegion, &mValidRegion); 1.135 + if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) { 1.136 + CopyRegion(oldTextureOnWhite, mTextureRect.TopLeft(), mTextureOnWhite, visibleRect.TopLeft(), 1.137 + retainRegion, &mValidRegion); 1.138 + } 1.139 + } 1.140 + 1.141 + mTextureRect = visibleRect; 1.142 + } 1.143 + } else { 1.144 + CreateNewTextures(gfx::IntSize(visibleRect.width, visibleRect.height), aMode); 1.145 + mTextureRect = visibleRect; 1.146 + 1.147 + NS_ASSERTION(mValidRegion.IsEmpty(), "Someone forgot to empty the region"); 1.148 + } 1.149 +} 1.150 + 1.151 +void 1.152 +ThebesLayerD3D9::RenderRegion(const nsIntRegion& aRegion) 1.153 +{ 1.154 + nsIntRegionRectIterator iter(aRegion); 1.155 + 1.156 + const nsIntRect *iterRect; 1.157 + while ((iterRect = iter.Next())) { 1.158 + device()->SetVertexShaderConstantF(CBvLayerQuad, 1.159 + ShaderConstantRect(iterRect->x, 1.160 + iterRect->y, 1.161 + iterRect->width, 1.162 + iterRect->height), 1.163 + 1); 1.164 + 1.165 + device()->SetVertexShaderConstantF(CBvTextureCoords, 1.166 + ShaderConstantRect( 1.167 + (float)(iterRect->x - mTextureRect.x) / (float)mTextureRect.width, 1.168 + (float)(iterRect->y - mTextureRect.y) / (float)mTextureRect.height, 1.169 + (float)iterRect->width / (float)mTextureRect.width, 1.170 + (float)iterRect->height / (float)mTextureRect.height), 1); 1.171 + 1.172 + device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); 1.173 + } 1.174 +} 1.175 + 1.176 +void 1.177 +ThebesLayerD3D9::RenderThebesLayer(ReadbackProcessor* aReadback) 1.178 +{ 1.179 + if (mVisibleRegion.IsEmpty()) { 1.180 + return; 1.181 + } 1.182 + 1.183 + nsIntRect newTextureRect = mVisibleRegion.GetBounds(); 1.184 + 1.185 + SurfaceMode mode = GetSurfaceMode(); 1.186 + if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA && 1.187 + (!mParent || !mParent->SupportsComponentAlphaChildren())) { 1.188 + mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA; 1.189 + } 1.190 + // If we have a transform that requires resampling of our texture, then 1.191 + // we need to make sure we don't sample pixels that haven't been drawn. 1.192 + // We clamp sample coordinates to the texture rect, but when the visible region 1.193 + // doesn't fill the entire texture rect we need to make sure we draw all the 1.194 + // pixels in the texture rect anyway in case they get sampled. 1.195 + nsIntRegion neededRegion = mVisibleRegion; 1.196 + if (!neededRegion.GetBounds().IsEqualInterior(newTextureRect) || 1.197 + neededRegion.GetNumRects() > 1) { 1.198 + if (MayResample()) { 1.199 + neededRegion = newTextureRect; 1.200 + if (mode == SurfaceMode::SURFACE_OPAQUE) { 1.201 + // We're going to paint outside the visible region, but layout hasn't 1.202 + // promised that it will paint opaquely there, so we'll have to 1.203 + // treat this layer as transparent. 1.204 + mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA; 1.205 + } 1.206 + } 1.207 + } 1.208 + 1.209 + VerifyContentType(mode); 1.210 + UpdateTextures(mode); 1.211 + if (!HaveTextures(mode)) { 1.212 + NS_WARNING("Texture creation failed"); 1.213 + return; 1.214 + } 1.215 + 1.216 + nsTArray<ReadbackProcessor::Update> readbackUpdates; 1.217 + nsIntRegion readbackRegion; 1.218 + if (aReadback && UsedForReadback()) { 1.219 + aReadback->GetThebesLayerUpdates(this, &readbackUpdates, &readbackRegion); 1.220 + } 1.221 + 1.222 + // Because updates to D3D9 ThebesLayers are rendered with the CPU, we don't 1.223 + // have to do readback from D3D9 surfaces. Instead we make sure that any area 1.224 + // needed for readback is included in the drawRegion we ask layout to render. 1.225 + // Then the readback areas we need can be copied out of the temporary 1.226 + // destinationSurface in DrawRegion. 1.227 + nsIntRegion drawRegion; 1.228 + drawRegion.Sub(neededRegion, mValidRegion); 1.229 + drawRegion.Or(drawRegion, readbackRegion); 1.230 + // NS_ASSERTION(mVisibleRegion.Contains(region), "Bad readback region!"); 1.231 + 1.232 + if (!drawRegion.IsEmpty()) { 1.233 + LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo(); 1.234 + if (!cbInfo.Callback) { 1.235 + NS_ERROR("D3D9 should never need to update ThebesLayers in an empty transaction"); 1.236 + return; 1.237 + } 1.238 + 1.239 + DrawRegion(drawRegion, mode, readbackUpdates); 1.240 + 1.241 + mValidRegion = neededRegion; 1.242 + } 1.243 + 1.244 + if (mD3DManager->CompositingDisabled()) { 1.245 + return; 1.246 + } 1.247 + 1.248 + SetShaderTransformAndOpacity(); 1.249 + 1.250 + if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) { 1.251 + mD3DManager->SetShaderMode(DeviceManagerD3D9::COMPONENTLAYERPASS1, 1.252 + GetMaskLayer()); 1.253 + device()->SetTexture(0, mTexture); 1.254 + device()->SetTexture(1, mTextureOnWhite); 1.255 + device()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO); 1.256 + device()->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCCOLOR); 1.257 + RenderRegion(neededRegion); 1.258 + 1.259 + mD3DManager->SetShaderMode(DeviceManagerD3D9::COMPONENTLAYERPASS2, 1.260 + GetMaskLayer()); 1.261 + device()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); 1.262 + device()->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); 1.263 + RenderRegion(neededRegion); 1.264 + 1.265 + // Restore defaults 1.266 + device()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); 1.267 + device()->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); 1.268 + device()->SetTexture(1, nullptr); 1.269 + } else { 1.270 + mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBALAYER, 1.271 + GetMaskLayer()); 1.272 + device()->SetTexture(0, mTexture); 1.273 + RenderRegion(neededRegion); 1.274 + } 1.275 + 1.276 + // Set back to default. 1.277 + device()->SetVertexShaderConstantF(CBvTextureCoords, 1.278 + ShaderConstantRect(0, 0, 1.0f, 1.0f), 1.279 + 1); 1.280 +} 1.281 + 1.282 +void 1.283 +ThebesLayerD3D9::CleanResources() 1.284 +{ 1.285 + mTexture = nullptr; 1.286 + mTextureOnWhite = nullptr; 1.287 + mValidRegion.SetEmpty(); 1.288 +} 1.289 + 1.290 +void 1.291 +ThebesLayerD3D9::LayerManagerDestroyed() 1.292 +{ 1.293 + mD3DManager->deviceManager()->mLayersWithResources.RemoveElement(this); 1.294 + mD3DManager = nullptr; 1.295 +} 1.296 + 1.297 +Layer* 1.298 +ThebesLayerD3D9::GetLayer() 1.299 +{ 1.300 + return this; 1.301 +} 1.302 + 1.303 +bool 1.304 +ThebesLayerD3D9::IsEmpty() 1.305 +{ 1.306 + return !mTexture; 1.307 +} 1.308 + 1.309 +void 1.310 +ThebesLayerD3D9::VerifyContentType(SurfaceMode aMode) 1.311 +{ 1.312 + if (!mTexture) 1.313 + return; 1.314 + 1.315 + D3DSURFACE_DESC desc; 1.316 + mTexture->GetLevelDesc(0, &desc); 1.317 + 1.318 + switch (aMode) { 1.319 + case SurfaceMode::SURFACE_OPAQUE: 1.320 + if (desc.Format == D3DFMT_X8R8G8B8 && !mTextureOnWhite) 1.321 + return; 1.322 + break; 1.323 + 1.324 + case SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA: 1.325 + if (desc.Format == D3DFMT_A8R8G8B8 && !mTextureOnWhite) 1.326 + return; 1.327 + break; 1.328 + 1.329 + case SurfaceMode::SURFACE_COMPONENT_ALPHA: 1.330 + if (mTextureOnWhite) { 1.331 + NS_ASSERTION(desc.Format == D3DFMT_X8R8G8B8, "Wrong format for component alpha texture"); 1.332 + return; 1.333 + } 1.334 + break; 1.335 + } 1.336 + 1.337 + // The new format isn't compatible with the old texture(s), toss out the old 1.338 + // texture(s). 1.339 + mTexture = nullptr; 1.340 + mTextureOnWhite = nullptr; 1.341 + mValidRegion.SetEmpty(); 1.342 +} 1.343 + 1.344 +class OpaqueRenderer { 1.345 +public: 1.346 + OpaqueRenderer(const nsIntRegion& aUpdateRegion) : 1.347 + mUpdateRegion(aUpdateRegion) {} 1.348 + ~OpaqueRenderer() { End(); } 1.349 + already_AddRefed<gfxWindowsSurface> Begin(LayerD3D9* aLayer); 1.350 + void End(); 1.351 + IDirect3DTexture9* GetTexture() { return mTmpTexture; } 1.352 + 1.353 +private: 1.354 + const nsIntRegion& mUpdateRegion; 1.355 + nsRefPtr<IDirect3DTexture9> mTmpTexture; 1.356 + nsRefPtr<IDirect3DSurface9> mSurface; 1.357 + nsRefPtr<gfxWindowsSurface> mD3D9ThebesSurface; 1.358 +}; 1.359 + 1.360 +already_AddRefed<gfxWindowsSurface> 1.361 +OpaqueRenderer::Begin(LayerD3D9* aLayer) 1.362 +{ 1.363 + nsIntRect bounds = mUpdateRegion.GetBounds(); 1.364 + 1.365 + HRESULT hr = aLayer->device()-> 1.366 + CreateTexture(bounds.width, bounds.height, 1, 0, D3DFMT_X8R8G8B8, 1.367 + D3DPOOL_SYSTEMMEM, getter_AddRefs(mTmpTexture), nullptr); 1.368 + 1.369 + if (FAILED(hr)) { 1.370 + aLayer->ReportFailure(NS_LITERAL_CSTRING("Failed to create temporary texture in system memory."), hr); 1.371 + return nullptr; 1.372 + } 1.373 + 1.374 + hr = mTmpTexture->GetSurfaceLevel(0, getter_AddRefs(mSurface)); 1.375 + 1.376 + if (FAILED(hr)) { 1.377 + // Uh-oh, bail. 1.378 + NS_WARNING("Failed to get texture surface level."); 1.379 + return nullptr; 1.380 + } 1.381 + 1.382 + nsRefPtr<gfxWindowsSurface> result = new gfxWindowsSurface(mSurface); 1.383 + if (!result || result->CairoStatus()) { 1.384 + NS_WARNING("Failed to d3d9 cairo surface."); 1.385 + return nullptr; 1.386 + } 1.387 + mD3D9ThebesSurface = result; 1.388 + 1.389 + return result.forget(); 1.390 +} 1.391 + 1.392 +void 1.393 +OpaqueRenderer::End() 1.394 +{ 1.395 + mSurface = nullptr; 1.396 + // gfxWindowsSurface returned from ::Begin() should be released before the 1.397 + // texture is used. This will assert that this is the case 1.398 +#if 1 1.399 + if (mD3D9ThebesSurface) { 1.400 + mD3D9ThebesSurface->AddRef(); 1.401 + nsrefcnt c = mD3D9ThebesSurface->Release(); 1.402 + if (c != 1) 1.403 + NS_RUNTIMEABORT("Reference mD3D9ThebesSurface must be released by caller of Begin() before calling End()"); 1.404 + } 1.405 +#endif 1.406 + mD3D9ThebesSurface = nullptr; 1.407 + 1.408 +} 1.409 + 1.410 +static void 1.411 +FillSurface(gfxASurface* aSurface, const nsIntRegion& aRegion, 1.412 + const nsIntPoint& aOffset, const gfxRGBA& aColor) 1.413 +{ 1.414 + nsRefPtr<gfxContext> ctx = new gfxContext(aSurface); 1.415 + ctx->Translate(-gfxPoint(aOffset.x, aOffset.y)); 1.416 + gfxUtils::ClipToRegion(ctx, aRegion); 1.417 + ctx->SetColor(aColor); 1.418 + ctx->Paint(); 1.419 +} 1.420 + 1.421 +void 1.422 +ThebesLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode, 1.423 + const nsTArray<ReadbackProcessor::Update>& aReadbackUpdates) 1.424 +{ 1.425 + HRESULT hr; 1.426 + nsIntRect visibleRect = mVisibleRegion.GetBounds(); 1.427 + 1.428 + nsRefPtr<gfxASurface> destinationSurface; 1.429 + nsIntRect bounds = aRegion.GetBounds(); 1.430 + nsRefPtr<IDirect3DTexture9> tmpTexture; 1.431 + OpaqueRenderer opaqueRenderer(aRegion); 1.432 + OpaqueRenderer opaqueRendererOnWhite(aRegion); 1.433 + 1.434 + switch (aMode) 1.435 + { 1.436 + case SurfaceMode::SURFACE_OPAQUE: 1.437 + destinationSurface = opaqueRenderer.Begin(this); 1.438 + break; 1.439 + 1.440 + case SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA: { 1.441 + hr = device()->CreateTexture(bounds.width, bounds.height, 1, 1.442 + 0, D3DFMT_A8R8G8B8, 1.443 + D3DPOOL_SYSTEMMEM, getter_AddRefs(tmpTexture), nullptr); 1.444 + 1.445 + if (FAILED(hr)) { 1.446 + ReportFailure(NS_LITERAL_CSTRING("Failed to create temporary texture in system memory."), hr); 1.447 + return; 1.448 + } 1.449 + 1.450 + // XXX - We may consider retaining a SYSTEMMEM texture texture the size 1.451 + // of our DEFAULT texture and then use UpdateTexture and add dirty rects 1.452 + // to update in a single call. 1.453 + nsRefPtr<gfxWindowsSurface> dest = new gfxWindowsSurface( 1.454 + gfxIntSize(bounds.width, bounds.height), gfxImageFormat::ARGB32); 1.455 + // If the contents of this layer don't require component alpha in the 1.456 + // end of rendering, it's safe to enable Cleartype since all the Cleartype 1.457 + // glyphs must be over (or under) opaque pixels. 1.458 + dest->SetSubpixelAntialiasingEnabled(!(mContentFlags & CONTENT_COMPONENT_ALPHA)); 1.459 + destinationSurface = dest.forget(); 1.460 + break; 1.461 + } 1.462 + 1.463 + case SurfaceMode::SURFACE_COMPONENT_ALPHA: { 1.464 + nsRefPtr<gfxWindowsSurface> onBlack = opaqueRenderer.Begin(this); 1.465 + nsRefPtr<gfxWindowsSurface> onWhite = opaqueRendererOnWhite.Begin(this); 1.466 + if (onBlack && onWhite) { 1.467 + FillSurface(onBlack, aRegion, bounds.TopLeft(), gfxRGBA(0.0, 0.0, 0.0, 1.0)); 1.468 + FillSurface(onWhite, aRegion, bounds.TopLeft(), gfxRGBA(1.0, 1.0, 1.0, 1.0)); 1.469 + gfxASurface* surfaces[2] = { onBlack.get(), onWhite.get() }; 1.470 + destinationSurface = new gfxTeeSurface(surfaces, ArrayLength(surfaces)); 1.471 + // Using this surface as a source will likely go horribly wrong, since 1.472 + // only the onBlack surface will really be used, so alpha information will 1.473 + // be incorrect. 1.474 + destinationSurface->SetAllowUseAsSource(false); 1.475 + } 1.476 + break; 1.477 + } 1.478 + } 1.479 + 1.480 + if (!destinationSurface) 1.481 + return; 1.482 + 1.483 + nsRefPtr<gfxContext> context; 1.484 + if (gfxPlatform::GetPlatform()->SupportsAzureContentForType(BackendType::CAIRO)) { 1.485 + RefPtr<DrawTarget> dt = 1.486 + gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(destinationSurface, 1.487 + IntSize(destinationSurface->GetSize().width, 1.488 + destinationSurface->GetSize().height)); 1.489 + 1.490 + context = new gfxContext(dt); 1.491 + } else { 1.492 + context = new gfxContext(destinationSurface); 1.493 + } 1.494 + 1.495 + context->Translate(gfxPoint(-bounds.x, -bounds.y)); 1.496 + LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo(); 1.497 + cbInfo.Callback(this, context, aRegion, DrawRegionClip::CLIP_NONE, nsIntRegion(), cbInfo.CallbackData); 1.498 + 1.499 + for (uint32_t i = 0; i < aReadbackUpdates.Length(); ++i) { 1.500 + NS_ASSERTION(aMode == SurfaceMode::SURFACE_OPAQUE, 1.501 + "Transparent surfaces should not be used for readback"); 1.502 + const ReadbackProcessor::Update& update = aReadbackUpdates[i]; 1.503 + nsIntPoint offset = update.mLayer->GetBackgroundLayerOffset(); 1.504 + nsRefPtr<gfxContext> ctx = 1.505 + update.mLayer->GetSink()->BeginUpdate(update.mUpdateRect + offset, 1.506 + update.mSequenceCounter); 1.507 + if (ctx) { 1.508 + ctx->Translate(gfxPoint(offset.x, offset.y)); 1.509 + ctx->SetSource(destinationSurface, gfxPoint(bounds.x, bounds.y)); 1.510 + ctx->Paint(); 1.511 + update.mLayer->GetSink()->EndUpdate(ctx, update.mUpdateRect + offset); 1.512 + } 1.513 + } 1.514 + 1.515 + // Release the cairo d3d9 surface before we try to composite it 1.516 + context = nullptr; 1.517 + 1.518 + nsAutoTArray<IDirect3DTexture9*,2> srcTextures; 1.519 + nsAutoTArray<IDirect3DTexture9*,2> destTextures; 1.520 + switch (aMode) 1.521 + { 1.522 + case SurfaceMode::SURFACE_OPAQUE: 1.523 + // Must release reference to dest surface before ending drawing 1.524 + destinationSurface = nullptr; 1.525 + opaqueRenderer.End(); 1.526 + srcTextures.AppendElement(opaqueRenderer.GetTexture()); 1.527 + destTextures.AppendElement(mTexture); 1.528 + break; 1.529 + 1.530 + case SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA: { 1.531 + LockTextureRectD3D9 textureLock(tmpTexture); 1.532 + if (!textureLock.HasLock()) { 1.533 + NS_WARNING("Failed to lock ThebesLayer tmpTexture texture."); 1.534 + return; 1.535 + } 1.536 + 1.537 + D3DLOCKED_RECT r = textureLock.GetLockRect(); 1.538 + 1.539 + nsRefPtr<gfxImageSurface> imgSurface = 1.540 + new gfxImageSurface((unsigned char *)r.pBits, 1.541 + bounds.Size(), 1.542 + r.Pitch, 1.543 + gfxImageFormat::ARGB32); 1.544 + 1.545 + if (destinationSurface) { 1.546 + nsRefPtr<gfxContext> context = new gfxContext(imgSurface); 1.547 + context->SetSource(destinationSurface); 1.548 + context->SetOperator(gfxContext::OPERATOR_SOURCE); 1.549 + context->Paint(); 1.550 + } 1.551 + 1.552 + // Must release reference to dest surface before ending drawing 1.553 + destinationSurface = nullptr; 1.554 + imgSurface = nullptr; 1.555 + 1.556 + srcTextures.AppendElement(tmpTexture); 1.557 + destTextures.AppendElement(mTexture); 1.558 + break; 1.559 + } 1.560 + 1.561 + case SurfaceMode::SURFACE_COMPONENT_ALPHA: { 1.562 + // Must release reference to dest surface before ending drawing 1.563 + destinationSurface = nullptr; 1.564 + opaqueRenderer.End(); 1.565 + opaqueRendererOnWhite.End(); 1.566 + srcTextures.AppendElement(opaqueRenderer.GetTexture()); 1.567 + destTextures.AppendElement(mTexture); 1.568 + srcTextures.AppendElement(opaqueRendererOnWhite.GetTexture()); 1.569 + destTextures.AppendElement(mTextureOnWhite); 1.570 + break; 1.571 + } 1.572 + } 1.573 + NS_ASSERTION(srcTextures.Length() == destTextures.Length(), "Mismatched lengths"); 1.574 + 1.575 + 1.576 + // Copy to the texture. 1.577 + for (uint32_t i = 0; i < srcTextures.Length(); ++i) { 1.578 + nsRefPtr<IDirect3DSurface9> srcSurface; 1.579 + nsRefPtr<IDirect3DSurface9> dstSurface; 1.580 + 1.581 + destTextures[i]->GetSurfaceLevel(0, getter_AddRefs(dstSurface)); 1.582 + srcTextures[i]->GetSurfaceLevel(0, getter_AddRefs(srcSurface)); 1.583 + 1.584 + nsIntRegionRectIterator iter(aRegion); 1.585 + const nsIntRect *iterRect; 1.586 + while ((iterRect = iter.Next())) { 1.587 + RECT rect; 1.588 + rect.left = iterRect->x - bounds.x; 1.589 + rect.top = iterRect->y - bounds.y; 1.590 + rect.right = iterRect->XMost() - bounds.x; 1.591 + rect.bottom = iterRect->YMost() - bounds.y; 1.592 + 1.593 + POINT point; 1.594 + point.x = iterRect->x - visibleRect.x; 1.595 + point.y = iterRect->y - visibleRect.y; 1.596 + device()->UpdateSurface(srcSurface, &rect, dstSurface, &point); 1.597 + } 1.598 + } 1.599 +} 1.600 + 1.601 +void 1.602 +ThebesLayerD3D9::CreateNewTextures(const gfx::IntSize &aSize, 1.603 + SurfaceMode aMode) 1.604 +{ 1.605 + if (aSize.width == 0 || aSize.height == 0) { 1.606 + // Nothing to do. 1.607 + return; 1.608 + } 1.609 + 1.610 + mTexture = nullptr; 1.611 + mTextureOnWhite = nullptr; 1.612 + HRESULT hr = device()->CreateTexture(aSize.width, aSize.height, 1, 1.613 + D3DUSAGE_RENDERTARGET, 1.614 + aMode != SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8, 1.615 + D3DPOOL_DEFAULT, getter_AddRefs(mTexture), nullptr); 1.616 + if (FAILED(hr)) { 1.617 + ReportFailure(NS_LITERAL_CSTRING("ThebesLayerD3D9::CreateNewTextures(): Failed to create texture"), 1.618 + hr); 1.619 + return; 1.620 + } 1.621 + 1.622 + if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) { 1.623 + hr = device()->CreateTexture(aSize.width, aSize.height, 1, 1.624 + D3DUSAGE_RENDERTARGET, 1.625 + D3DFMT_X8R8G8B8, 1.626 + D3DPOOL_DEFAULT, getter_AddRefs(mTextureOnWhite), nullptr); 1.627 + if (FAILED(hr)) { 1.628 + ReportFailure(NS_LITERAL_CSTRING("ThebesLayerD3D9::CreateNewTextures(): Failed to create texture (2)"), 1.629 + hr); 1.630 + return; 1.631 + } 1.632 + } 1.633 +} 1.634 + 1.635 +} /* namespace layers */ 1.636 +} /* namespace mozilla */