michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozilla/layers/PLayerTransaction.h" michael@0: michael@0: // This must occur *after* layers/PLayerTransaction.h to avoid michael@0: // typedefs conflicts. michael@0: #include "mozilla/ArrayUtils.h" michael@0: michael@0: #include "ThebesLayerD3D9.h" michael@0: #include "gfxPlatform.h" michael@0: michael@0: #include "gfxWindowsPlatform.h" michael@0: #include "gfxTeeSurface.h" michael@0: #include "gfxUtils.h" michael@0: #include "ReadbackProcessor.h" michael@0: #include "ReadbackLayer.h" michael@0: #include "mozilla/gfx/2D.h" michael@0: michael@0: namespace mozilla { michael@0: namespace layers { michael@0: michael@0: using namespace gfx; michael@0: michael@0: ThebesLayerD3D9::ThebesLayerD3D9(LayerManagerD3D9 *aManager) michael@0: : ThebesLayer(aManager, nullptr) michael@0: , LayerD3D9(aManager) michael@0: { michael@0: mImplData = static_cast(this); michael@0: aManager->deviceManager()->mLayersWithResources.AppendElement(this); michael@0: } michael@0: michael@0: ThebesLayerD3D9::~ThebesLayerD3D9() michael@0: { michael@0: if (mD3DManager) { michael@0: mD3DManager->deviceManager()->mLayersWithResources.RemoveElement(this); michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Retention threshold - amount of pixels intersection required to enable michael@0: * layer content retention. This is a guesstimate. Profiling could be done to michael@0: * figure out the optimal threshold. michael@0: */ michael@0: #define RETENTION_THRESHOLD 16384 michael@0: michael@0: void michael@0: ThebesLayerD3D9::InvalidateRegion(const nsIntRegion &aRegion) michael@0: { michael@0: mInvalidRegion.Or(mInvalidRegion, aRegion); michael@0: mInvalidRegion.SimplifyOutward(20); michael@0: mValidRegion.Sub(mValidRegion, mInvalidRegion); michael@0: } michael@0: michael@0: void michael@0: ThebesLayerD3D9::CopyRegion(IDirect3DTexture9* aSrc, const nsIntPoint &aSrcOffset, michael@0: IDirect3DTexture9* aDest, const nsIntPoint &aDestOffset, michael@0: const nsIntRegion &aCopyRegion, nsIntRegion* aValidRegion) michael@0: { michael@0: nsRefPtr srcSurface, dstSurface; michael@0: aSrc->GetSurfaceLevel(0, getter_AddRefs(srcSurface)); michael@0: aDest->GetSurfaceLevel(0, getter_AddRefs(dstSurface)); michael@0: michael@0: nsIntRegion retainedRegion; michael@0: nsIntRegionRectIterator iter(aCopyRegion); michael@0: const nsIntRect *r; michael@0: while ((r = iter.Next())) { michael@0: if (r->width * r->height > RETENTION_THRESHOLD) { michael@0: RECT oldRect, newRect; michael@0: michael@0: // Calculate the retained rectangle's position on the old and the new michael@0: // surface. michael@0: oldRect.left = r->x - aSrcOffset.x; michael@0: oldRect.top = r->y - aSrcOffset.y; michael@0: oldRect.right = oldRect.left + r->width; michael@0: oldRect.bottom = oldRect.top + r->height; michael@0: michael@0: newRect.left = r->x - aDestOffset.x; michael@0: newRect.top = r->y - aDestOffset.y; michael@0: newRect.right = newRect.left + r->width; michael@0: newRect.bottom = newRect.top + r->height; michael@0: michael@0: // Copy data from our old texture to the new one michael@0: HRESULT hr = device()-> michael@0: StretchRect(srcSurface, &oldRect, dstSurface, &newRect, D3DTEXF_NONE); michael@0: michael@0: if (SUCCEEDED(hr)) { michael@0: retainedRegion.Or(retainedRegion, *r); michael@0: } michael@0: } michael@0: } michael@0: michael@0: // Areas which were valid and were retained are still valid michael@0: aValidRegion->And(*aValidRegion, retainedRegion); michael@0: } michael@0: michael@0: static uint64_t RectArea(const nsIntRect& aRect) michael@0: { michael@0: return aRect.width*uint64_t(aRect.height); michael@0: } michael@0: michael@0: void michael@0: ThebesLayerD3D9::UpdateTextures(SurfaceMode aMode) michael@0: { michael@0: nsIntRect visibleRect = mVisibleRegion.GetBounds(); michael@0: michael@0: if (HaveTextures(aMode)) { michael@0: if (!mTextureRect.IsEqualInterior(visibleRect)) { michael@0: nsRefPtr oldTexture = mTexture; michael@0: nsRefPtr oldTextureOnWhite = mTextureOnWhite; michael@0: michael@0: NS_ASSERTION(mTextureRect.Contains(mValidRegion.GetBounds()), michael@0: "How can we have valid data outside the texture?"); michael@0: nsIntRegion retainRegion; michael@0: // The region we want to retain is the valid data that is inside michael@0: // the new visible region michael@0: retainRegion.And(mValidRegion, mVisibleRegion); michael@0: michael@0: CreateNewTextures(gfx::IntSize(visibleRect.width, visibleRect.height), aMode); michael@0: michael@0: // If our texture creation failed this can mean a device reset is pending and we michael@0: // should silently ignore the failure. In the future when device failures michael@0: // are properly handled we should test for the type of failure and gracefully michael@0: // handle different failures. See bug 569081. michael@0: if (!HaveTextures(aMode)) { michael@0: mValidRegion.SetEmpty(); michael@0: } else { michael@0: CopyRegion(oldTexture, mTextureRect.TopLeft(), mTexture, visibleRect.TopLeft(), michael@0: retainRegion, &mValidRegion); michael@0: if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) { michael@0: CopyRegion(oldTextureOnWhite, mTextureRect.TopLeft(), mTextureOnWhite, visibleRect.TopLeft(), michael@0: retainRegion, &mValidRegion); michael@0: } michael@0: } michael@0: michael@0: mTextureRect = visibleRect; michael@0: } michael@0: } else { michael@0: CreateNewTextures(gfx::IntSize(visibleRect.width, visibleRect.height), aMode); michael@0: mTextureRect = visibleRect; michael@0: michael@0: NS_ASSERTION(mValidRegion.IsEmpty(), "Someone forgot to empty the region"); michael@0: } michael@0: } michael@0: michael@0: void michael@0: ThebesLayerD3D9::RenderRegion(const nsIntRegion& aRegion) michael@0: { michael@0: nsIntRegionRectIterator iter(aRegion); michael@0: michael@0: const nsIntRect *iterRect; michael@0: while ((iterRect = iter.Next())) { michael@0: device()->SetVertexShaderConstantF(CBvLayerQuad, michael@0: ShaderConstantRect(iterRect->x, michael@0: iterRect->y, michael@0: iterRect->width, michael@0: iterRect->height), michael@0: 1); michael@0: michael@0: device()->SetVertexShaderConstantF(CBvTextureCoords, michael@0: ShaderConstantRect( michael@0: (float)(iterRect->x - mTextureRect.x) / (float)mTextureRect.width, michael@0: (float)(iterRect->y - mTextureRect.y) / (float)mTextureRect.height, michael@0: (float)iterRect->width / (float)mTextureRect.width, michael@0: (float)iterRect->height / (float)mTextureRect.height), 1); michael@0: michael@0: device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); michael@0: } michael@0: } michael@0: michael@0: void michael@0: ThebesLayerD3D9::RenderThebesLayer(ReadbackProcessor* aReadback) michael@0: { michael@0: if (mVisibleRegion.IsEmpty()) { michael@0: return; michael@0: } michael@0: michael@0: nsIntRect newTextureRect = mVisibleRegion.GetBounds(); michael@0: michael@0: SurfaceMode mode = GetSurfaceMode(); michael@0: if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA && michael@0: (!mParent || !mParent->SupportsComponentAlphaChildren())) { michael@0: mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA; michael@0: } michael@0: // If we have a transform that requires resampling of our texture, then michael@0: // we need to make sure we don't sample pixels that haven't been drawn. michael@0: // We clamp sample coordinates to the texture rect, but when the visible region michael@0: // doesn't fill the entire texture rect we need to make sure we draw all the michael@0: // pixels in the texture rect anyway in case they get sampled. michael@0: nsIntRegion neededRegion = mVisibleRegion; michael@0: if (!neededRegion.GetBounds().IsEqualInterior(newTextureRect) || michael@0: neededRegion.GetNumRects() > 1) { michael@0: if (MayResample()) { michael@0: neededRegion = newTextureRect; michael@0: if (mode == SurfaceMode::SURFACE_OPAQUE) { michael@0: // We're going to paint outside the visible region, but layout hasn't michael@0: // promised that it will paint opaquely there, so we'll have to michael@0: // treat this layer as transparent. michael@0: mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA; michael@0: } michael@0: } michael@0: } michael@0: michael@0: VerifyContentType(mode); michael@0: UpdateTextures(mode); michael@0: if (!HaveTextures(mode)) { michael@0: NS_WARNING("Texture creation failed"); michael@0: return; michael@0: } michael@0: michael@0: nsTArray readbackUpdates; michael@0: nsIntRegion readbackRegion; michael@0: if (aReadback && UsedForReadback()) { michael@0: aReadback->GetThebesLayerUpdates(this, &readbackUpdates, &readbackRegion); michael@0: } michael@0: michael@0: // Because updates to D3D9 ThebesLayers are rendered with the CPU, we don't michael@0: // have to do readback from D3D9 surfaces. Instead we make sure that any area michael@0: // needed for readback is included in the drawRegion we ask layout to render. michael@0: // Then the readback areas we need can be copied out of the temporary michael@0: // destinationSurface in DrawRegion. michael@0: nsIntRegion drawRegion; michael@0: drawRegion.Sub(neededRegion, mValidRegion); michael@0: drawRegion.Or(drawRegion, readbackRegion); michael@0: // NS_ASSERTION(mVisibleRegion.Contains(region), "Bad readback region!"); michael@0: michael@0: if (!drawRegion.IsEmpty()) { michael@0: LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo(); michael@0: if (!cbInfo.Callback) { michael@0: NS_ERROR("D3D9 should never need to update ThebesLayers in an empty transaction"); michael@0: return; michael@0: } michael@0: michael@0: DrawRegion(drawRegion, mode, readbackUpdates); michael@0: michael@0: mValidRegion = neededRegion; michael@0: } michael@0: michael@0: if (mD3DManager->CompositingDisabled()) { michael@0: return; michael@0: } michael@0: michael@0: SetShaderTransformAndOpacity(); michael@0: michael@0: if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) { michael@0: mD3DManager->SetShaderMode(DeviceManagerD3D9::COMPONENTLAYERPASS1, michael@0: GetMaskLayer()); michael@0: device()->SetTexture(0, mTexture); michael@0: device()->SetTexture(1, mTextureOnWhite); michael@0: device()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO); michael@0: device()->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCCOLOR); michael@0: RenderRegion(neededRegion); michael@0: michael@0: mD3DManager->SetShaderMode(DeviceManagerD3D9::COMPONENTLAYERPASS2, michael@0: GetMaskLayer()); michael@0: device()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); michael@0: device()->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); michael@0: RenderRegion(neededRegion); michael@0: michael@0: // Restore defaults michael@0: device()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); michael@0: device()->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); michael@0: device()->SetTexture(1, nullptr); michael@0: } else { michael@0: mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBALAYER, michael@0: GetMaskLayer()); michael@0: device()->SetTexture(0, mTexture); michael@0: RenderRegion(neededRegion); michael@0: } michael@0: michael@0: // Set back to default. michael@0: device()->SetVertexShaderConstantF(CBvTextureCoords, michael@0: ShaderConstantRect(0, 0, 1.0f, 1.0f), michael@0: 1); michael@0: } michael@0: michael@0: void michael@0: ThebesLayerD3D9::CleanResources() michael@0: { michael@0: mTexture = nullptr; michael@0: mTextureOnWhite = nullptr; michael@0: mValidRegion.SetEmpty(); michael@0: } michael@0: michael@0: void michael@0: ThebesLayerD3D9::LayerManagerDestroyed() michael@0: { michael@0: mD3DManager->deviceManager()->mLayersWithResources.RemoveElement(this); michael@0: mD3DManager = nullptr; michael@0: } michael@0: michael@0: Layer* michael@0: ThebesLayerD3D9::GetLayer() michael@0: { michael@0: return this; michael@0: } michael@0: michael@0: bool michael@0: ThebesLayerD3D9::IsEmpty() michael@0: { michael@0: return !mTexture; michael@0: } michael@0: michael@0: void michael@0: ThebesLayerD3D9::VerifyContentType(SurfaceMode aMode) michael@0: { michael@0: if (!mTexture) michael@0: return; michael@0: michael@0: D3DSURFACE_DESC desc; michael@0: mTexture->GetLevelDesc(0, &desc); michael@0: michael@0: switch (aMode) { michael@0: case SurfaceMode::SURFACE_OPAQUE: michael@0: if (desc.Format == D3DFMT_X8R8G8B8 && !mTextureOnWhite) michael@0: return; michael@0: break; michael@0: michael@0: case SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA: michael@0: if (desc.Format == D3DFMT_A8R8G8B8 && !mTextureOnWhite) michael@0: return; michael@0: break; michael@0: michael@0: case SurfaceMode::SURFACE_COMPONENT_ALPHA: michael@0: if (mTextureOnWhite) { michael@0: NS_ASSERTION(desc.Format == D3DFMT_X8R8G8B8, "Wrong format for component alpha texture"); michael@0: return; michael@0: } michael@0: break; michael@0: } michael@0: michael@0: // The new format isn't compatible with the old texture(s), toss out the old michael@0: // texture(s). michael@0: mTexture = nullptr; michael@0: mTextureOnWhite = nullptr; michael@0: mValidRegion.SetEmpty(); michael@0: } michael@0: michael@0: class OpaqueRenderer { michael@0: public: michael@0: OpaqueRenderer(const nsIntRegion& aUpdateRegion) : michael@0: mUpdateRegion(aUpdateRegion) {} michael@0: ~OpaqueRenderer() { End(); } michael@0: already_AddRefed Begin(LayerD3D9* aLayer); michael@0: void End(); michael@0: IDirect3DTexture9* GetTexture() { return mTmpTexture; } michael@0: michael@0: private: michael@0: const nsIntRegion& mUpdateRegion; michael@0: nsRefPtr mTmpTexture; michael@0: nsRefPtr mSurface; michael@0: nsRefPtr mD3D9ThebesSurface; michael@0: }; michael@0: michael@0: already_AddRefed michael@0: OpaqueRenderer::Begin(LayerD3D9* aLayer) michael@0: { michael@0: nsIntRect bounds = mUpdateRegion.GetBounds(); michael@0: michael@0: HRESULT hr = aLayer->device()-> michael@0: CreateTexture(bounds.width, bounds.height, 1, 0, D3DFMT_X8R8G8B8, michael@0: D3DPOOL_SYSTEMMEM, getter_AddRefs(mTmpTexture), nullptr); michael@0: michael@0: if (FAILED(hr)) { michael@0: aLayer->ReportFailure(NS_LITERAL_CSTRING("Failed to create temporary texture in system memory."), hr); michael@0: return nullptr; michael@0: } michael@0: michael@0: hr = mTmpTexture->GetSurfaceLevel(0, getter_AddRefs(mSurface)); michael@0: michael@0: if (FAILED(hr)) { michael@0: // Uh-oh, bail. michael@0: NS_WARNING("Failed to get texture surface level."); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr result = new gfxWindowsSurface(mSurface); michael@0: if (!result || result->CairoStatus()) { michael@0: NS_WARNING("Failed to d3d9 cairo surface."); michael@0: return nullptr; michael@0: } michael@0: mD3D9ThebesSurface = result; michael@0: michael@0: return result.forget(); michael@0: } michael@0: michael@0: void michael@0: OpaqueRenderer::End() michael@0: { michael@0: mSurface = nullptr; michael@0: // gfxWindowsSurface returned from ::Begin() should be released before the michael@0: // texture is used. This will assert that this is the case michael@0: #if 1 michael@0: if (mD3D9ThebesSurface) { michael@0: mD3D9ThebesSurface->AddRef(); michael@0: nsrefcnt c = mD3D9ThebesSurface->Release(); michael@0: if (c != 1) michael@0: NS_RUNTIMEABORT("Reference mD3D9ThebesSurface must be released by caller of Begin() before calling End()"); michael@0: } michael@0: #endif michael@0: mD3D9ThebesSurface = nullptr; michael@0: michael@0: } michael@0: michael@0: static void michael@0: FillSurface(gfxASurface* aSurface, const nsIntRegion& aRegion, michael@0: const nsIntPoint& aOffset, const gfxRGBA& aColor) michael@0: { michael@0: nsRefPtr ctx = new gfxContext(aSurface); michael@0: ctx->Translate(-gfxPoint(aOffset.x, aOffset.y)); michael@0: gfxUtils::ClipToRegion(ctx, aRegion); michael@0: ctx->SetColor(aColor); michael@0: ctx->Paint(); michael@0: } michael@0: michael@0: void michael@0: ThebesLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode, michael@0: const nsTArray& aReadbackUpdates) michael@0: { michael@0: HRESULT hr; michael@0: nsIntRect visibleRect = mVisibleRegion.GetBounds(); michael@0: michael@0: nsRefPtr destinationSurface; michael@0: nsIntRect bounds = aRegion.GetBounds(); michael@0: nsRefPtr tmpTexture; michael@0: OpaqueRenderer opaqueRenderer(aRegion); michael@0: OpaqueRenderer opaqueRendererOnWhite(aRegion); michael@0: michael@0: switch (aMode) michael@0: { michael@0: case SurfaceMode::SURFACE_OPAQUE: michael@0: destinationSurface = opaqueRenderer.Begin(this); michael@0: break; michael@0: michael@0: case SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA: { michael@0: hr = device()->CreateTexture(bounds.width, bounds.height, 1, michael@0: 0, D3DFMT_A8R8G8B8, michael@0: D3DPOOL_SYSTEMMEM, getter_AddRefs(tmpTexture), nullptr); michael@0: michael@0: if (FAILED(hr)) { michael@0: ReportFailure(NS_LITERAL_CSTRING("Failed to create temporary texture in system memory."), hr); michael@0: return; michael@0: } michael@0: michael@0: // XXX - We may consider retaining a SYSTEMMEM texture texture the size michael@0: // of our DEFAULT texture and then use UpdateTexture and add dirty rects michael@0: // to update in a single call. michael@0: nsRefPtr dest = new gfxWindowsSurface( michael@0: gfxIntSize(bounds.width, bounds.height), gfxImageFormat::ARGB32); michael@0: // If the contents of this layer don't require component alpha in the michael@0: // end of rendering, it's safe to enable Cleartype since all the Cleartype michael@0: // glyphs must be over (or under) opaque pixels. michael@0: dest->SetSubpixelAntialiasingEnabled(!(mContentFlags & CONTENT_COMPONENT_ALPHA)); michael@0: destinationSurface = dest.forget(); michael@0: break; michael@0: } michael@0: michael@0: case SurfaceMode::SURFACE_COMPONENT_ALPHA: { michael@0: nsRefPtr onBlack = opaqueRenderer.Begin(this); michael@0: nsRefPtr onWhite = opaqueRendererOnWhite.Begin(this); michael@0: if (onBlack && onWhite) { michael@0: FillSurface(onBlack, aRegion, bounds.TopLeft(), gfxRGBA(0.0, 0.0, 0.0, 1.0)); michael@0: FillSurface(onWhite, aRegion, bounds.TopLeft(), gfxRGBA(1.0, 1.0, 1.0, 1.0)); michael@0: gfxASurface* surfaces[2] = { onBlack.get(), onWhite.get() }; michael@0: destinationSurface = new gfxTeeSurface(surfaces, ArrayLength(surfaces)); michael@0: // Using this surface as a source will likely go horribly wrong, since michael@0: // only the onBlack surface will really be used, so alpha information will michael@0: // be incorrect. michael@0: destinationSurface->SetAllowUseAsSource(false); michael@0: } michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (!destinationSurface) michael@0: return; michael@0: michael@0: nsRefPtr context; michael@0: if (gfxPlatform::GetPlatform()->SupportsAzureContentForType(BackendType::CAIRO)) { michael@0: RefPtr dt = michael@0: gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(destinationSurface, michael@0: IntSize(destinationSurface->GetSize().width, michael@0: destinationSurface->GetSize().height)); michael@0: michael@0: context = new gfxContext(dt); michael@0: } else { michael@0: context = new gfxContext(destinationSurface); michael@0: } michael@0: michael@0: context->Translate(gfxPoint(-bounds.x, -bounds.y)); michael@0: LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo(); michael@0: cbInfo.Callback(this, context, aRegion, DrawRegionClip::CLIP_NONE, nsIntRegion(), cbInfo.CallbackData); michael@0: michael@0: for (uint32_t i = 0; i < aReadbackUpdates.Length(); ++i) { michael@0: NS_ASSERTION(aMode == SurfaceMode::SURFACE_OPAQUE, michael@0: "Transparent surfaces should not be used for readback"); michael@0: const ReadbackProcessor::Update& update = aReadbackUpdates[i]; michael@0: nsIntPoint offset = update.mLayer->GetBackgroundLayerOffset(); michael@0: nsRefPtr ctx = michael@0: update.mLayer->GetSink()->BeginUpdate(update.mUpdateRect + offset, michael@0: update.mSequenceCounter); michael@0: if (ctx) { michael@0: ctx->Translate(gfxPoint(offset.x, offset.y)); michael@0: ctx->SetSource(destinationSurface, gfxPoint(bounds.x, bounds.y)); michael@0: ctx->Paint(); michael@0: update.mLayer->GetSink()->EndUpdate(ctx, update.mUpdateRect + offset); michael@0: } michael@0: } michael@0: michael@0: // Release the cairo d3d9 surface before we try to composite it michael@0: context = nullptr; michael@0: michael@0: nsAutoTArray srcTextures; michael@0: nsAutoTArray destTextures; michael@0: switch (aMode) michael@0: { michael@0: case SurfaceMode::SURFACE_OPAQUE: michael@0: // Must release reference to dest surface before ending drawing michael@0: destinationSurface = nullptr; michael@0: opaqueRenderer.End(); michael@0: srcTextures.AppendElement(opaqueRenderer.GetTexture()); michael@0: destTextures.AppendElement(mTexture); michael@0: break; michael@0: michael@0: case SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA: { michael@0: LockTextureRectD3D9 textureLock(tmpTexture); michael@0: if (!textureLock.HasLock()) { michael@0: NS_WARNING("Failed to lock ThebesLayer tmpTexture texture."); michael@0: return; michael@0: } michael@0: michael@0: D3DLOCKED_RECT r = textureLock.GetLockRect(); michael@0: michael@0: nsRefPtr imgSurface = michael@0: new gfxImageSurface((unsigned char *)r.pBits, michael@0: bounds.Size(), michael@0: r.Pitch, michael@0: gfxImageFormat::ARGB32); michael@0: michael@0: if (destinationSurface) { michael@0: nsRefPtr context = new gfxContext(imgSurface); michael@0: context->SetSource(destinationSurface); michael@0: context->SetOperator(gfxContext::OPERATOR_SOURCE); michael@0: context->Paint(); michael@0: } michael@0: michael@0: // Must release reference to dest surface before ending drawing michael@0: destinationSurface = nullptr; michael@0: imgSurface = nullptr; michael@0: michael@0: srcTextures.AppendElement(tmpTexture); michael@0: destTextures.AppendElement(mTexture); michael@0: break; michael@0: } michael@0: michael@0: case SurfaceMode::SURFACE_COMPONENT_ALPHA: { michael@0: // Must release reference to dest surface before ending drawing michael@0: destinationSurface = nullptr; michael@0: opaqueRenderer.End(); michael@0: opaqueRendererOnWhite.End(); michael@0: srcTextures.AppendElement(opaqueRenderer.GetTexture()); michael@0: destTextures.AppendElement(mTexture); michael@0: srcTextures.AppendElement(opaqueRendererOnWhite.GetTexture()); michael@0: destTextures.AppendElement(mTextureOnWhite); michael@0: break; michael@0: } michael@0: } michael@0: NS_ASSERTION(srcTextures.Length() == destTextures.Length(), "Mismatched lengths"); michael@0: michael@0: michael@0: // Copy to the texture. michael@0: for (uint32_t i = 0; i < srcTextures.Length(); ++i) { michael@0: nsRefPtr srcSurface; michael@0: nsRefPtr dstSurface; michael@0: michael@0: destTextures[i]->GetSurfaceLevel(0, getter_AddRefs(dstSurface)); michael@0: srcTextures[i]->GetSurfaceLevel(0, getter_AddRefs(srcSurface)); michael@0: michael@0: nsIntRegionRectIterator iter(aRegion); michael@0: const nsIntRect *iterRect; michael@0: while ((iterRect = iter.Next())) { michael@0: RECT rect; michael@0: rect.left = iterRect->x - bounds.x; michael@0: rect.top = iterRect->y - bounds.y; michael@0: rect.right = iterRect->XMost() - bounds.x; michael@0: rect.bottom = iterRect->YMost() - bounds.y; michael@0: michael@0: POINT point; michael@0: point.x = iterRect->x - visibleRect.x; michael@0: point.y = iterRect->y - visibleRect.y; michael@0: device()->UpdateSurface(srcSurface, &rect, dstSurface, &point); michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: ThebesLayerD3D9::CreateNewTextures(const gfx::IntSize &aSize, michael@0: SurfaceMode aMode) michael@0: { michael@0: if (aSize.width == 0 || aSize.height == 0) { michael@0: // Nothing to do. michael@0: return; michael@0: } michael@0: michael@0: mTexture = nullptr; michael@0: mTextureOnWhite = nullptr; michael@0: HRESULT hr = device()->CreateTexture(aSize.width, aSize.height, 1, michael@0: D3DUSAGE_RENDERTARGET, michael@0: aMode != SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8, michael@0: D3DPOOL_DEFAULT, getter_AddRefs(mTexture), nullptr); michael@0: if (FAILED(hr)) { michael@0: ReportFailure(NS_LITERAL_CSTRING("ThebesLayerD3D9::CreateNewTextures(): Failed to create texture"), michael@0: hr); michael@0: return; michael@0: } michael@0: michael@0: if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) { michael@0: hr = device()->CreateTexture(aSize.width, aSize.height, 1, michael@0: D3DUSAGE_RENDERTARGET, michael@0: D3DFMT_X8R8G8B8, michael@0: D3DPOOL_DEFAULT, getter_AddRefs(mTextureOnWhite), nullptr); michael@0: if (FAILED(hr)) { michael@0: ReportFailure(NS_LITERAL_CSTRING("ThebesLayerD3D9::CreateNewTextures(): Failed to create texture (2)"), michael@0: hr); michael@0: return; michael@0: } michael@0: } michael@0: } michael@0: michael@0: } /* namespace layers */ michael@0: } /* namespace mozilla */