already_AddRefed<SourceSurface> D3D11YCbCrImage::GetAsSourceSurface() { if (!mTextureClient) { gfxWarning() << "GetAsSourceSurface() called on uninitialized D3D11YCbCrImage."; return nullptr; } gfx::IntSize size(mPictureRect.Size()); gfx::SurfaceFormat format = gfx::ImageFormatToSurfaceFormat(gfxVars::OffscreenFormat()); HRESULT hr; PlanarYCbCrData data; DXGIYCbCrTextureData *dxgiData = static_cast<DXGIYCbCrTextureData*>(mTextureClient->GetInternalData()); if (!dxgiData) { gfxCriticalError() << "Failed to get texture client internal data."; return nullptr; } RefPtr<ID3D11Texture2D> texY = dxgiData->GetD3D11Texture(0); RefPtr<ID3D11Texture2D> texCb = dxgiData->GetD3D11Texture(1); RefPtr<ID3D11Texture2D> texCr = dxgiData->GetD3D11Texture(2); RefPtr<ID3D11Texture2D> softTexY, softTexCb, softTexCr; D3D11_TEXTURE2D_DESC desc; RefPtr<ID3D11Device> dev; texY->GetDevice(getter_AddRefs(dev)); RefPtr<ID3D10Multithread> mt; hr = dev->QueryInterface((ID3D10Multithread**)getter_AddRefs(mt)); if (FAILED(hr) || !mt) { gfxCriticalError() << "Multithread safety interface not supported."; return nullptr; } if (!mt->GetMultithreadProtected()) { gfxCriticalError() << "Device used not marked as multithread-safe."; return nullptr; } D3D11MTAutoEnter mtAutoEnter(mt.forget()); texY->GetDesc(&desc); desc.BindFlags = 0; desc.MiscFlags = 0; desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; desc.Usage = D3D11_USAGE_STAGING; dev->CreateTexture2D(&desc, nullptr, getter_AddRefs(softTexY)); texCb->GetDesc(&desc); desc.BindFlags = 0; desc.MiscFlags = 0; desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; desc.Usage = D3D11_USAGE_STAGING; dev->CreateTexture2D(&desc, nullptr, getter_AddRefs(softTexCb)); dev->CreateTexture2D(&desc, nullptr, getter_AddRefs(softTexCr)); RefPtr<ID3D11DeviceContext> ctx; dev->GetImmediateContext(getter_AddRefs(ctx)); { AutoLockD3D11Texture lockY(texY); AutoLockD3D11Texture lockCb(texCb); AutoLockD3D11Texture lockCr(texCr); ctx->CopyResource(softTexY, texY); ctx->CopyResource(softTexCb, texCb); ctx->CopyResource(softTexCr, texCr); } D3D11_MAPPED_SUBRESOURCE mapY, mapCb, mapCr; RefPtr<gfx::DataSourceSurface> surface; mapY.pData = mapCb.pData = mapCr.pData = nullptr; hr = ctx->Map(softTexY, 0, D3D11_MAP_READ, 0, &mapY); if (FAILED(hr)) { gfxCriticalError() << "Failed to map Y plane (" << hr << ")"; return nullptr; } hr = ctx->Map(softTexCb, 0, D3D11_MAP_READ, 0, &mapCb); if (FAILED(hr)) { gfxCriticalError() << "Failed to map Y plane (" << hr << ")"; return nullptr; } hr = ctx->Map(softTexCr, 0, D3D11_MAP_READ, 0, &mapCr); if (FAILED(hr)) { gfxCriticalError() << "Failed to map Y plane (" << hr << ")"; return nullptr; } MOZ_ASSERT(mapCb.RowPitch == mapCr.RowPitch); data.mPicX = mPictureRect.x; data.mPicY = mPictureRect.y; data.mPicSize = mPictureRect.Size(); data.mStereoMode = StereoMode::MONO; data.mYUVColorSpace = mColorSpace; data.mYSkip = data.mCbSkip = data.mCrSkip = 0; data.mYSize = mYSize; data.mCbCrSize = mCbCrSize; data.mYChannel = static_cast<uint8_t*>(mapY.pData); data.mYStride = mapY.RowPitch; data.mCbChannel = static_cast<uint8_t*>(mapCb.pData); data.mCrChannel = static_cast<uint8_t*>(mapCr.pData); data.mCbCrStride = mapCb.RowPitch; gfx::GetYCbCrToRGBDestFormatAndSize(data, format, size); if (size.width > PlanarYCbCrImage::MAX_DIMENSION || size.height > PlanarYCbCrImage::MAX_DIMENSION) { gfxCriticalError() << "Illegal image dest width or height"; return nullptr; } surface = gfx::Factory::CreateDataSourceSurface(size, format); if (!surface) { gfxCriticalError() << "Failed to create DataSourceSurface for image: " << size << " " << format; return nullptr; } DataSourceSurface::ScopedMap mapping(surface, DataSourceSurface::WRITE); if (!mapping.IsMapped()) { gfxCriticalError() << "Failed to map DataSourceSurface for D3D11YCbCrImage"; return nullptr; } gfx::ConvertYCbCrToRGB( data, format, size, mapping.GetData(), mapping.GetStride()); ctx->Unmap(softTexY, 0); ctx->Unmap(softTexCb, 0); ctx->Unmap(softTexCr, 0); return surface.forget(); }
ID2D1Bitmap* SourceSurfaceD2DTarget::GetBitmap(ID2D1RenderTarget *aRT) { if (mBitmap) { return mBitmap; } HRESULT hr; D3D10_TEXTURE2D_DESC desc; mTexture->GetDesc(&desc); IntSize size(desc.Width, desc.Height); RefPtr<IDXGISurface> surf; hr = mTexture->QueryInterface((IDXGISurface**)byRef(surf)); if (FAILED(hr)) { gfxWarning() << "Failed to query interface texture to DXGISurface. Code: " << hr; return nullptr; } D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties(D2DPixelFormat(mFormat)); hr = aRT->CreateSharedBitmap(IID_IDXGISurface, surf, &props, byRef(mBitmap)); if (FAILED(hr)) { // This seems to happen for SurfaceFormat::A8 sometimes... hr = aRT->CreateBitmap(D2D1::SizeU(desc.Width, desc.Height), D2D1::BitmapProperties(D2DPixelFormat(mFormat)), byRef(mBitmap)); if (FAILED(hr)) { gfxWarning() << "Failed in CreateBitmap. Code: " << hr; return nullptr; } RefPtr<ID2D1RenderTarget> rt; if (mDrawTarget) { rt = mDrawTarget->mRT; } if (!rt) { // Okay, we already separated from our drawtarget. And we're an A8 // surface the only way we can get to a bitmap is by creating a // a rendertarget and from there copying to a bitmap! Terrible! RefPtr<IDXGISurface> surface; hr = mTexture->QueryInterface((IDXGISurface**)byRef(surface)); if (FAILED(hr)) { gfxWarning() << "Failed to QI texture to surface."; return nullptr; } D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, D2DPixelFormat(mFormat)); hr = DrawTargetD2D::factory()->CreateDxgiSurfaceRenderTarget(surface, props, byRef(rt)); if (FAILED(hr)) { gfxWarning() << "Failed to create D2D render target for texture."; return nullptr; } } mBitmap->CopyFromRenderTarget(nullptr, rt, nullptr); return mBitmap; } return mBitmap; }
DataSourceSurfaceD2D::DataSourceSurfaceD2D(SourceSurfaceD2D* aSourceSurface) : mTexture(nullptr) , mFormat(aSourceSurface->mFormat) , mSize(aSourceSurface->mSize) , mMapped(false) { // We allocate ourselves a regular D3D surface (sourceTexture) and paint the // D2D bitmap into it via a DXGI render target. Then we need to copy // sourceTexture into a staging texture (mTexture), which we will lazily map // to get the data. CD3D10_TEXTURE2D_DESC desc(DXGIFormat(mFormat), mSize.width, mSize.height); desc.MipLevels = 1; desc.Usage = D3D10_USAGE_DEFAULT; desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE; RefPtr<ID3D10Texture2D> sourceTexture; HRESULT hr = aSourceSurface->mDevice->CreateTexture2D(&desc, nullptr, byRef(sourceTexture)); if (FAILED(hr)) { gfxWarning() << "Failed to create texture. Code: " << hr; return; } RefPtr<IDXGISurface> dxgiSurface; hr = sourceTexture->QueryInterface((IDXGISurface**)byRef(dxgiSurface)); if (FAILED(hr)) { gfxWarning() << "Failed to create DXGI surface. Code: " << hr; return; } D2D1_RENDER_TARGET_PROPERTIES rtProps = D2D1::RenderTargetProperties( D2D1_RENDER_TARGET_TYPE_DEFAULT, D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED)); RefPtr<ID2D1RenderTarget> renderTarget; hr = DrawTargetD2D::factory()->CreateDxgiSurfaceRenderTarget(dxgiSurface, &rtProps, byRef(renderTarget)); if (FAILED(hr)) { gfxWarning() << "Failed to create render target. Code: " << hr; return; } renderTarget->BeginDraw(); renderTarget->DrawBitmap(aSourceSurface->mBitmap, D2D1::RectF(0, 0, Float(mSize.width), Float(mSize.height))); renderTarget->EndDraw(); desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ; desc.Usage = D3D10_USAGE_STAGING; desc.BindFlags = 0; hr = aSourceSurface->mDevice->CreateTexture2D(&desc, nullptr, byRef(mTexture)); if (FAILED(hr)) { gfxWarning() << "Failed to create staging texture. Code: " << hr; mTexture = nullptr; return; } aSourceSurface->mDevice->CopyResource(mTexture, sourceTexture); }
void ClientSingleTiledLayerBuffer::PaintThebes( const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion, const nsIntRegion& aDirtyRegion, LayerManager::DrawPaintedLayerCallback aCallback, void* aCallbackData, TilePaintFlags aFlags) { mWasLastPaintProgressive = !!(aFlags & TilePaintFlags::Progressive); bool asyncPaint = !!(aFlags & TilePaintFlags::Async); // Compare layer valid region size to current backbuffer size, discard if not // matching. gfx::IntSize size = aNewValidRegion.GetBounds().Size(); gfx::IntPoint origin = aNewValidRegion.GetBounds().TopLeft(); nsIntRegion paintRegion = aPaintRegion; RefPtr<TextureClient> discardedFrontBuffer = nullptr; RefPtr<TextureClient> discardedFrontBufferOnWhite = nullptr; nsIntRegion discardedValidRegion; if (mSize != size || mTilingOrigin != origin) { discardedFrontBuffer = mTile.mFrontBuffer; discardedFrontBufferOnWhite = mTile.mFrontBufferOnWhite; discardedValidRegion = mValidRegion; TILING_LOG( "TILING %p: Single-tile valid region changed. Discarding buffers.\n", &mPaintedLayer); ResetPaintedAndValidState(); mSize = size; mTilingOrigin = origin; paintRegion = aNewValidRegion; } SurfaceMode mode; gfxContentType content = GetContentType(&mode); mFormat = gfxPlatform::GetPlatform()->OptimalFormatForContent(content); if (mTile.IsPlaceholderTile()) { mTile.SetTextureAllocator(this); } if (mManager->AsShadowForwarder()->SupportsTextureDirectMapping()) { AutoTArray<uint64_t, 2> syncTextureSerials; mTile.GetSyncTextureSerials(mode, syncTextureSerials); if (syncTextureSerials.Length() > 0) { mManager->AsShadowForwarder()->SyncTextures(syncTextureSerials); } } // The dirty region relative to the top-left of the tile. nsIntRegion tileVisibleRegion = aNewValidRegion.MovedBy(-mTilingOrigin); nsIntRegion tileDirtyRegion = paintRegion.MovedBy(-mTilingOrigin); Maybe<AcquiredBackBuffer> backBuffer = mTile.AcquireBackBuffer(mCompositableClient, tileDirtyRegion, tileVisibleRegion, content, mode, aFlags); if (!backBuffer) { return; } // Mark the area we need to paint in the back buffer as invalid in the // front buffer as they will become out of sync. mTile.mInvalidFront.OrWith(tileDirtyRegion); // Add backbuffer's invalid region to the dirty region to be painted. // This will be empty if we were able to copy from the front in to the back. nsIntRegion tileInvalidRegion = mTile.mInvalidBack; tileInvalidRegion.AndWith(tileVisibleRegion); paintRegion.OrWith(tileInvalidRegion.MovedBy(mTilingOrigin)); tileDirtyRegion.OrWith(tileInvalidRegion); // Mark the region we will be painting and the region we copied from the front // buffer as needing to be uploaded to the compositor mTile.mUpdateRect = tileDirtyRegion.GetBounds().Union(backBuffer->mUpdatedRect); // If the old frontbuffer was discarded then attempt to copy what we // can from it to the new backbuffer. if (discardedFrontBuffer) { nsIntRegion copyableRegion; copyableRegion.And(aNewValidRegion, discardedValidRegion); copyableRegion.SubOut(aDirtyRegion); OpenMode readMode = asyncPaint ? OpenMode::OPEN_READ_ASYNC : OpenMode::OPEN_READ; DualTextureClientAutoLock discardedBuffer( discardedFrontBuffer, discardedFrontBufferOnWhite, readMode); if (discardedBuffer.Succeeded()) { RefPtr<gfx::SourceSurface> discardedSurface = discardedBuffer->Snapshot(); for (auto iter = copyableRegion.RectIter(); !iter.Done(); iter.Next()) { const gfx::IntRect src = iter.Get() - discardedValidRegion.GetBounds().TopLeft(); const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin; backBuffer->mTarget->CopySurface(discardedSurface, src, dest); } TILING_LOG("TILING %p: Region copied from discarded frontbuffer %s\n", &mPaintedLayer, Stringify(copyableRegion).c_str()); // We don't need to repaint valid content that was just copied. paintRegion.SubOut(copyableRegion); copyableRegion.MoveBy(-mTilingOrigin); tileDirtyRegion.SubOut(copyableRegion); } else { gfxWarning() << "[Tiling:Client] Failed to aquire the discarded front " "buffer's draw target"; } } if (mode != SurfaceMode::SURFACE_OPAQUE) { for (auto iter = tileDirtyRegion.RectIter(); !iter.Done(); iter.Next()) { const gfx::Rect drawRect(iter.Get().X(), iter.Get().Y(), iter.Get().Width(), iter.Get().Height()); backBuffer->mTarget->ClearRect(drawRect); } } // Paint into the target { RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(backBuffer->mTarget); if (!ctx) { gfxDevCrash(gfx::LogReason::InvalidContext) << "SingleTiledContextClient context problem " << gfx::hexa(backBuffer->mTarget); return; } ctx->SetMatrix( ctx->CurrentMatrix().PreTranslate(-mTilingOrigin.x, -mTilingOrigin.y)); aCallback(&mPaintedLayer, ctx, paintRegion, paintRegion, DrawRegionClip::DRAW, nsIntRegion(), aCallbackData); } if (asyncPaint) { if (!backBuffer->mCapture->IsEmpty()) { UniquePtr<PaintTask> task(new PaintTask()); task->mCapture = backBuffer->mCapture; task->mTarget = backBuffer->mBackBuffer; task->mClients = std::move(backBuffer->mTextureClients); if (discardedFrontBuffer) { task->mClients.AppendElement(discardedFrontBuffer); } if (discardedFrontBufferOnWhite) { task->mClients.AppendElement(discardedFrontBufferOnWhite); } // The target is an alias for the capture, and the paint thread expects // to be the only one with a reference to the capture backBuffer->mTarget = nullptr; backBuffer->mCapture = nullptr; PaintThread::Get()->QueuePaintTask(std::move(task)); mManager->SetQueuedAsyncPaints(); } } else { MOZ_ASSERT(backBuffer->mTarget == backBuffer->mBackBuffer); MOZ_ASSERT(!backBuffer->mCapture); } // The new buffer is now validated, remove the dirty region from it. mTile.mInvalidBack.SubOut(tileDirtyRegion); backBuffer = Nothing(); mTile.Flip(); UnlockTile(mTile); mValidRegion = aNewValidRegion; mLastPaintSurfaceMode = mode; mLastPaintContentType = content; }
TemporaryRef<ID2D1ResourceTexture> RadialGradientEffectD2D1::CreateGradientTexture() { std::vector<D2D1_GRADIENT_STOP> rawStops; rawStops.resize(mStopCollection->GetGradientStopCount()); mStopCollection->GetGradientStops(&rawStops.front(), rawStops.size()); std::vector<unsigned char> textureData; textureData.resize(4096 * 4); unsigned char *texData = &textureData.front(); float prevColorPos = 0; float nextColorPos = 1.0f; D2D1_COLOR_F prevColor = rawStops[0].color; D2D1_COLOR_F nextColor = prevColor; if (rawStops.size() >= 2) { nextColor = rawStops[1].color; nextColorPos = rawStops[1].position; } uint32_t stopPosition = 2; // Not the most optimized way but this will do for now. for (int i = 0; i < 4096; i++) { // The 4095 seems a little counter intuitive, but we want the gradient // color at offset 0 at the first pixel, and at offset 1.0f at the last // pixel. float pos = float(i) / 4095; while (pos > nextColorPos) { prevColor = nextColor; prevColorPos = nextColorPos; if (rawStops.size() > stopPosition) { nextColor = rawStops[stopPosition].color; nextColorPos = rawStops[stopPosition++].position; } else { nextColorPos = 1.0f; } } float interp; if (nextColorPos != prevColorPos) { interp = (pos - prevColorPos) / (nextColorPos - prevColorPos); } else { interp = 0; } Color newColor(prevColor.r + (nextColor.r - prevColor.r) * interp, prevColor.g + (nextColor.g - prevColor.g) * interp, prevColor.b + (nextColor.b - prevColor.b) * interp, prevColor.a + (nextColor.a - prevColor.a) * interp); // Note D2D expects RGBA here!! texData[i * 4] = (char)(255.0f * newColor.r); texData[i * 4 + 1] = (char)(255.0f * newColor.g); texData[i * 4 + 2] = (char)(255.0f * newColor.b); texData[i * 4 + 3] = (char)(255.0f * newColor.a); } RefPtr<ID2D1ResourceTexture> tex; UINT32 width = 4096; UINT32 stride = 4096 * 4; D2D1_RESOURCE_TEXTURE_PROPERTIES props; // Older shader models do not support 1D textures. So just use a width x 1 texture. props.dimensions = 2; UINT32 dims[] = { width, 1 }; props.extents = dims; props.channelDepth = D2D1_CHANNEL_DEPTH_4; props.bufferPrecision = D2D1_BUFFER_PRECISION_8BPC_UNORM; props.filter = D2D1_FILTER_MIN_MAG_MIP_LINEAR; D2D1_EXTEND_MODE extendMode[] = { mStopCollection->GetExtendMode(), mStopCollection->GetExtendMode() }; props.extendModes = extendMode; HRESULT hr = mEffectContext->CreateResourceTexture(nullptr, &props, &textureData.front(), &stride, 4096 * 4, byRef(tex)); if (FAILED(hr)) { gfxWarning() << "Failed to create resource texture: " << hexa(hr); } return tex.forget(); }
void BasicCompositor::DrawQuad(const gfx::Rect& aRect, const gfx::Rect& aClipRect, const EffectChain &aEffectChain, gfx::Float aOpacity, const gfx::Matrix4x4& aTransform, const gfx::Rect& aVisibleRect) { RefPtr<DrawTarget> buffer = mRenderTarget->mDrawTarget; // For 2D drawing, |dest| and |buffer| are the same surface. For 3D drawing, // |dest| is a temporary surface. RefPtr<DrawTarget> dest = buffer; AutoRestoreTransform autoRestoreTransform(dest); Matrix newTransform; Rect transformBounds; Matrix4x4 new3DTransform; IntPoint offset = mRenderTarget->GetOrigin(); if (aTransform.Is2D()) { newTransform = aTransform.As2D(); } else { // Create a temporary surface for the transform. dest = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(RoundOut(aRect).Size(), SurfaceFormat::B8G8R8A8); if (!dest) { return; } dest->SetTransform(Matrix::Translation(-aRect.x, -aRect.y)); // Get the bounds post-transform. transformBounds = aTransform.TransformAndClipBounds(aRect, Rect(offset.x, offset.y, buffer->GetSize().width, buffer->GetSize().height)); transformBounds.RoundOut(); if (transformBounds.IsEmpty()) { return; } // Propagate the coordinate offset to our 2D draw target. newTransform = Matrix::Translation(transformBounds.x, transformBounds.y); // When we apply the 3D transformation, we do it against a temporary // surface, so undo the coordinate offset. new3DTransform = Matrix4x4::Translation(aRect.x, aRect.y, 0) * aTransform; } buffer->PushClipRect(aClipRect); newTransform.PostTranslate(-offset.x, -offset.y); buffer->SetTransform(newTransform); RefPtr<SourceSurface> sourceMask; Matrix maskTransform; if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) { EffectMask *effectMask = static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EffectTypes::MASK].get()); sourceMask = effectMask->mMaskTexture->AsSourceBasic()->GetSurface(dest); if (!sourceMask) { gfxWarning() << "Invalid sourceMask effect"; } MOZ_ASSERT(effectMask->mMaskTransform.Is2D(), "How did we end up with a 3D transform here?!"); MOZ_ASSERT(!effectMask->mIs3D); maskTransform = effectMask->mMaskTransform.As2D(); maskTransform.PreTranslate(-offset.x, -offset.y); } CompositionOp blendMode = CompositionOp::OP_OVER; if (Effect* effect = aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE].get()) { blendMode = static_cast<EffectBlendMode*>(effect)->mBlendMode; } switch (aEffectChain.mPrimaryEffect->mType) { case EffectTypes::SOLID_COLOR: { EffectSolidColor* effectSolidColor = static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get()); bool unboundedOp = !IsOperatorBoundByMask(blendMode); if (unboundedOp) { dest->PushClipRect(aRect); } FillRectWithMask(dest, aRect, effectSolidColor->mColor, DrawOptions(aOpacity, blendMode), sourceMask, &maskTransform); if (unboundedOp) { dest->PopClip(); } break; } case EffectTypes::RGB: { TexturedEffect* texturedEffect = static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get()); TextureSourceBasic* source = texturedEffect->mTexture->AsSourceBasic(); if (source && texturedEffect->mPremultiplied) { DrawSurfaceWithTextureCoords(dest, aRect, source->GetSurface(dest), texturedEffect->mTextureCoords, texturedEffect->mFilter, DrawOptions(aOpacity, blendMode), sourceMask, &maskTransform); } else if (source) { SourceSurface* srcSurf = source->GetSurface(dest); if (srcSurf) { RefPtr<DataSourceSurface> srcData = srcSurf->GetDataSurface(); // Yes, we re-create the premultiplied data every time. // This might be better with a cache, eventually. RefPtr<DataSourceSurface> premultData = gfxUtils::CreatePremultipliedDataSurface(srcData); DrawSurfaceWithTextureCoords(dest, aRect, premultData, texturedEffect->mTextureCoords, texturedEffect->mFilter, DrawOptions(aOpacity, blendMode), sourceMask, &maskTransform); } } else { gfxDevCrash(LogReason::IncompatibleBasicTexturedEffect) << "Bad for basic with " << texturedEffect->mTexture->Name() << " and " << gfx::hexa(sourceMask); } break; } case EffectTypes::YCBCR: { NS_RUNTIMEABORT("Can't (easily) support component alpha with BasicCompositor!"); break; } case EffectTypes::RENDER_TARGET: { EffectRenderTarget* effectRenderTarget = static_cast<EffectRenderTarget*>(aEffectChain.mPrimaryEffect.get()); RefPtr<BasicCompositingRenderTarget> surface = static_cast<BasicCompositingRenderTarget*>(effectRenderTarget->mRenderTarget.get()); RefPtr<SourceSurface> sourceSurf = surface->mDrawTarget->Snapshot(); DrawSurfaceWithTextureCoords(dest, aRect, sourceSurf, effectRenderTarget->mTextureCoords, effectRenderTarget->mFilter, DrawOptions(aOpacity, blendMode), sourceMask, &maskTransform); break; } case EffectTypes::COMPONENT_ALPHA: { NS_RUNTIMEABORT("Can't (easily) support component alpha with BasicCompositor!"); break; } default: { NS_RUNTIMEABORT("Invalid effect type!"); break; } } if (!aTransform.Is2D()) { dest->Flush(); RefPtr<SourceSurface> snapshot = dest->Snapshot(); RefPtr<DataSourceSurface> source = snapshot->GetDataSurface(); RefPtr<DataSourceSurface> temp = Factory::CreateDataSourceSurface(RoundOut(transformBounds).Size(), SurfaceFormat::B8G8R8A8 #ifdef MOZ_ENABLE_SKIA , true #endif ); if (NS_WARN_IF(!temp)) { buffer->PopClip(); return; } Transform(temp, source, new3DTransform, transformBounds.TopLeft()); transformBounds.MoveTo(0, 0); buffer->DrawSurface(temp, transformBounds, transformBounds); } buffer->PopClip(); }