virtual void Paint(gfxContext* aContext, Layer* aMaskLayer) { if (IsHidden()) return; AutoSetOperator setOperator(aContext, GetOperator()); PaintColorTo(mColor, GetEffectiveOpacity(), aContext, aMaskLayer); }
void ColorLayerComposite::RenderLayer(const nsIntPoint& aOffset, const nsIntRect& aClipRect) { EffectChain effects; gfxRGBA color(GetColor()); effects.mPrimaryEffect = new EffectSolidColor(gfx::Color(color.r, color.g, color.b, color.a)); nsIntRect visibleRect = GetEffectiveVisibleRegion().GetBounds(); LayerManagerComposite::AddMaskEffect(GetMaskLayer(), effects); gfx::Rect rect(visibleRect.x, visibleRect.y, visibleRect.width, visibleRect.height); gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height); float opacity = GetEffectiveOpacity(); gfx::Matrix4x4 transform; ToMatrix4x4(GetEffectiveTransform(), transform); mCompositor->DrawQuad(rect, clipRect, effects, opacity, transform, gfx::Point(aOffset.x, aOffset.y)); mCompositor->DrawDiagnostics(gfx::Color(0.0, 1.0, 1.0, 1.0), rect, clipRect, transform, gfx::Point(aOffset.x, aOffset.y)); }
void ThebesLayerComposite::RenderLayer(const nsIntPoint& aOffset, const nsIntRect& aClipRect) { if (!mBuffer || !mBuffer->IsAttached()) { return; } MOZ_ASSERT(mBuffer->GetCompositor() == mCompositeManager->GetCompositor() && mBuffer->GetLayer() == this, "buffer is corrupted"); gfx::Matrix4x4 transform; ToMatrix4x4(GetEffectiveTransform(), transform); gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height); #ifdef MOZ_DUMP_PAINTING if (gfxUtils::sDumpPainting) { nsRefPtr<gfxImageSurface> surf = mBuffer->GetAsSurface(); WriteSnapshotToDumpFile(this, surf); } #endif EffectChain effectChain; LayerManagerComposite::AddMaskEffect(mMaskLayer, effectChain); nsIntRegion visibleRegion = GetEffectiveVisibleRegion(); TiledLayerProperties tiledLayerProps; if (mRequiresTiledProperties) { // calculating these things can be a little expensive, so don't // do them if we don't have to tiledLayerProps.mVisibleRegion = visibleRegion; tiledLayerProps.mDisplayPort = GetDisplayPort(); tiledLayerProps.mEffectiveResolution = GetEffectiveResolution(); tiledLayerProps.mCompositionBounds = GetCompositionBounds(); tiledLayerProps.mRetainTiles = !mIsFixedPosition; tiledLayerProps.mValidRegion = mValidRegion; } mBuffer->SetPaintWillResample(MayResample()); mBuffer->Composite(effectChain, GetEffectiveOpacity(), transform, gfx::Point(aOffset.x, aOffset.y), gfx::FILTER_LINEAR, clipRect, &visibleRegion, mRequiresTiledProperties ? &tiledLayerProps : nullptr); if (mRequiresTiledProperties) { mValidRegion = tiledLayerProps.mValidRegion; } LayerManagerComposite::RemoveMaskEffect(mMaskLayer); mCompositeManager->GetCompositor()->MakeCurrent(); }
void BasicImageLayer::Paint(DrawTarget* aDT, const gfx::Point& aDeviceOffset, Layer* aMaskLayer) { if (IsHidden() || !mContainer) { return; } RefPtr<ImageFactory> originalIF = mContainer->GetImageFactory(); mContainer->SetImageFactory(mManager->IsCompositingCheap() ? nullptr : BasicManager()->GetImageFactory()); AutoLockImage autoLock(mContainer); Image *image = autoLock.GetImage(BasicManager()->GetCompositionTime()); if (!image) { mContainer->SetImageFactory(originalIF); return; } RefPtr<gfx::SourceSurface> surface = image->GetAsSourceSurface(); if (!surface || !surface->IsValid()) { mContainer->SetImageFactory(originalIF); return; } gfx::IntSize size = mSize = surface->GetSize(); FillRectWithMask(aDT, aDeviceOffset, Rect(0, 0, size.width, size.height), surface, mSamplingFilter, DrawOptions(GetEffectiveOpacity(), GetEffectiveOperator(this)), aMaskLayer); mContainer->SetImageFactory(originalIF); }
void ImageLayerComposite::RenderLayer(const nsIntRect& aClipRect) { if (!mImageHost || !mImageHost->IsAttached()) { return; } #ifdef MOZ_DUMP_PAINTING if (gfxUtils::sDumpPainting) { nsRefPtr<gfxImageSurface> surf = mImageHost->GetAsSurface(); WriteSnapshotToDumpFile(this, surf); } #endif mCompositor->MakeCurrent(); EffectChain effectChain; LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(mMaskLayer, effectChain); gfx::Matrix4x4 transform; ToMatrix4x4(GetEffectiveTransform(), transform); gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height); mImageHost->SetCompositor(mCompositor); mImageHost->Composite(effectChain, GetEffectiveOpacity(), transform, gfx::ToFilter(mFilter), clipRect); }
void ImageLayerComposite::RenderLayer(const nsIntRect& aClipRect) { if (!mImageHost || !mImageHost->IsAttached()) { return; } #ifdef MOZ_DUMP_PAINTING if (gfxUtils::sDumpPainting) { RefPtr<gfx::DataSourceSurface> dSurf = mImageHost->GetAsSurface(); gfxPlatform *platform = gfxPlatform::GetPlatform(); RefPtr<gfx::DrawTarget> dt = platform->CreateDrawTargetForData(dSurf->GetData(), dSurf->GetSize(), dSurf->Stride(), dSurf->GetFormat()); nsRefPtr<gfxASurface> surf = platform->GetThebesSurfaceForDrawTarget(dt); WriteSnapshotToDumpFile(this, surf); } #endif mCompositor->MakeCurrent(); EffectChain effectChain; LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(mMaskLayer, effectChain); gfx::Matrix4x4 transform; ToMatrix4x4(GetEffectiveTransform(), transform); gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height); mImageHost->SetCompositor(mCompositor); mImageHost->Composite(effectChain, GetEffectiveOpacity(), transform, gfx::ToFilter(mFilter), clipRect); }
void BasicContainerLayer::ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface) { // We push groups for container layers if we need to, which always // are aligned in device space, so it doesn't really matter how we snap // containers. gfxMatrix residual; gfx3DMatrix idealTransform = GetLocalTransform()*aTransformToSurface; idealTransform.ProjectTo2D(); if (!idealTransform.CanDraw2D()) { mEffectiveTransform = idealTransform; ComputeEffectiveTransformsForChildren(gfx3DMatrix()); ComputeEffectiveTransformForMaskLayer(gfx3DMatrix()); mUseIntermediateSurface = true; return; } mEffectiveTransform = SnapTransformTranslation(idealTransform, &residual); // We always pass the ideal matrix down to our children, so there is no // need to apply any compensation using the residual from SnapTransformTranslation. ComputeEffectiveTransformsForChildren(idealTransform); ComputeEffectiveTransformForMaskLayer(aTransformToSurface); /* If we have a single child, it can just inherit our opacity, * otherwise we need a PushGroup and we need to mark ourselves as using * an intermediate surface so our children don't inherit our opacity * via GetEffectiveOpacity. * Having a mask layer always forces our own push group */ mUseIntermediateSurface = GetMaskLayer() || (GetEffectiveOpacity() != 1.0 && HasMultipleChildren()); }
void ColorLayerComposite::RenderLayer(const nsIntRect& aClipRect) { EffectChain effects(this); gfxRGBA color(GetColor()); effects.mPrimaryEffect = new EffectSolidColor(gfx::Color(color.r, color.g, color.b, color.a)); nsIntRect boundRect = GetBounds(); LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(GetMaskLayer(), effects); gfx::Rect rect(boundRect.x, boundRect.y, boundRect.width, boundRect.height); gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height); float opacity = GetEffectiveOpacity(); const gfx::Matrix4x4& transform = GetEffectiveTransform(); mCompositor->DrawQuad(rect, clipRect, effects, opacity, transform); mCompositor->DrawDiagnostics(DIAGNOSTIC_COLOR, rect, clipRect, transform); }
void ContainerLayer::DefaultComputeEffectiveTransforms(const Matrix4x4& aTransformToSurface) { Matrix residual; Matrix4x4 idealTransform = GetLocalTransform() * aTransformToSurface; idealTransform.ProjectTo2D(); mEffectiveTransform = SnapTransformTranslation(idealTransform, &residual); bool useIntermediateSurface; if (GetMaskLayer() || GetForceIsolatedGroup()) { useIntermediateSurface = true; #ifdef MOZ_DUMP_PAINTING } else if (gfxUtils::sDumpPainting) { useIntermediateSurface = true; #endif } else { float opacity = GetEffectiveOpacity(); CompositionOp blendMode = GetEffectiveMixBlendMode(); if ((opacity != 1.0f || blendMode != CompositionOp::OP_OVER) && HasMultipleChildren()) { useIntermediateSurface = true; } else { useIntermediateSurface = false; gfx::Matrix contTransform; if (!mEffectiveTransform.Is2D(&contTransform) || #ifdef MOZ_GFX_OPTIMIZE_MOBILE !contTransform.PreservesAxisAlignedRectangles()) { #else gfx::ThebesMatrix(contTransform).HasNonIntegerTranslation()) { #endif for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) { const nsIntRect *clipRect = child->GetEffectiveClipRect(); /* We can't (easily) forward our transform to children with a non-empty clip * rect since it would need to be adjusted for the transform. See * the calculations performed by CalculateScissorRect above. * Nor for a child with a mask layer. */ if ((clipRect && !clipRect->IsEmpty() && !child->GetVisibleRegion().IsEmpty()) || child->GetMaskLayer()) { useIntermediateSurface = true; break; } } } } } mUseIntermediateSurface = useIntermediateSurface; if (useIntermediateSurface) { ComputeEffectiveTransformsForChildren(Matrix4x4::From2D(residual)); } else { ComputeEffectiveTransformsForChildren(idealTransform); } if (idealTransform.CanDraw2D()) { ComputeEffectiveTransformForMaskLayer(aTransformToSurface); } else { ComputeEffectiveTransformForMaskLayer(Matrix4x4()); } }
void BasicImageLayer::Paint(gfxContext* aContext, Layer* aMaskLayer) { if (IsHidden()) return; nsRefPtr<gfxPattern> dontcare = GetAndPaintCurrentImage(aContext, GetEffectiveOpacity(), aMaskLayer); }
void BasicCanvasLayer::Paint(gfxContext* aContext, Layer* aMaskLayer) { if (IsHidden()) return; UpdateSurface(); FireDidTransactionCallback(); PaintWithOpacity(aContext, GetEffectiveOpacity(), aMaskLayer); }
void ThebesLayerComposite::RenderLayer(const nsIntRect& aClipRect) { if (!mBuffer || !mBuffer->IsAttached()) { return; } PROFILER_LABEL("ThebesLayerComposite", "RenderLayer", js::ProfileEntry::Category::GRAPHICS); MOZ_ASSERT(mBuffer->GetCompositor() == mCompositeManager->GetCompositor() && mBuffer->GetLayer() == this, "buffer is corrupted"); gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height); #ifdef MOZ_DUMP_PAINTING if (gfxUtils::sDumpPainting) { RefPtr<gfx::DataSourceSurface> surf = mBuffer->GetAsSurface(); if (surf) { WriteSnapshotToDumpFile(this, surf); } } #endif EffectChain effectChain(this); LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(mMaskLayer, effectChain); AddBlendModeEffect(effectChain); const nsIntRegion& visibleRegion = GetEffectiveVisibleRegion(); TiledLayerProperties tiledLayerProps; if (mRequiresTiledProperties) { tiledLayerProps.mVisibleRegion = visibleRegion; tiledLayerProps.mEffectiveResolution = GetEffectiveResolution(); tiledLayerProps.mValidRegion = mValidRegion; } mBuffer->SetPaintWillResample(MayResample()); mBuffer->Composite(effectChain, GetEffectiveOpacity(), GetEffectiveTransform(), gfx::Filter::LINEAR, clipRect, &visibleRegion, mRequiresTiledProperties ? &tiledLayerProps : nullptr); mBuffer->BumpFlashCounter(); if (mRequiresTiledProperties) { mValidRegion = tiledLayerProps.mValidRegion; } mCompositeManager->GetCompositor()->MakeCurrent(); }
void BasicCanvasLayer::Paint(DrawTarget* aTarget, SourceSurface* aMaskSurface) { if (IsHidden()) return; FirePreTransactionCallback(); UpdateTarget(); FireDidTransactionCallback(); CompositionOp mixBlendMode = GetEffectiveMixBlendMode(); PaintWithOpacity(aTarget, GetEffectiveOpacity(), aMaskSurface, mixBlendMode != CompositionOp::OP_OVER ? mixBlendMode : GetOperator()); }
virtual void Paint(DrawTarget* aDT, const gfx::Point& aDeviceOffset, Layer* aMaskLayer) override { if (IsHidden()) { return; } Rect snapped(mBounds.X(), mBounds.Y(), mBounds.Width(), mBounds.Height()); MaybeSnapToDevicePixels(snapped, *aDT, true); // Clip drawing in case we're using (unbounded) operator source. aDT->PushClipRect(snapped); FillRectWithMask( aDT, aDeviceOffset, snapped, mColor, DrawOptions(GetEffectiveOpacity(), GetEffectiveOperator(this)), aMaskLayer); aDT->PopClip(); }
void BasicCanvasLayer::DeprecatedPaint(gfxContext* aContext, Layer* aMaskLayer) { if (IsHidden()) return; FirePreTransactionCallback(); DeprecatedUpdateSurface(); FireDidTransactionCallback(); gfxContext::GraphicsOperator mixBlendMode = DeprecatedGetEffectiveMixBlendMode(); DeprecatedPaintWithOpacity(aContext, GetEffectiveOpacity(), aMaskLayer, mixBlendMode != gfxContext::OPERATOR_OVER ? mixBlendMode : DeprecatedGetOperator()); }
void BasicContainerLayer::ComputeEffectiveTransforms(const Matrix4x4& aTransformToSurface) { // We push groups for container layers if we need to, which always // are aligned in device space, so it doesn't really matter how we snap // containers. Matrix residual; Matrix4x4 idealTransform = GetLocalTransform() * aTransformToSurface; idealTransform.ProjectTo2D(); if (!idealTransform.CanDraw2D()) { mEffectiveTransform = idealTransform; ComputeEffectiveTransformsForChildren(Matrix4x4()); ComputeEffectiveTransformForMaskLayer(Matrix4x4()); mUseIntermediateSurface = true; return; } mEffectiveTransform = SnapTransformTranslation(idealTransform, &residual); // We always pass the ideal matrix down to our children, so there is no // need to apply any compensation using the residual from SnapTransformTranslation. ComputeEffectiveTransformsForChildren(idealTransform); ComputeEffectiveTransformForMaskLayer(aTransformToSurface); Layer* child = GetFirstChild(); bool hasSingleBlendingChild = false; if (!HasMultipleChildren() && child) { hasSingleBlendingChild = child->GetMixBlendMode() != CompositionOp::OP_OVER; } /* If we have a single childand it is not blending,, it can just inherit our opacity, * otherwise we need a PushGroup and we need to mark ourselves as using * an intermediate surface so our children don't inherit our opacity * via GetEffectiveOpacity. * Having a mask layer always forces our own push group * Having a blend mode also always forces our own push group */ mUseIntermediateSurface = GetMaskLayer() || GetForceIsolatedGroup() || (GetMixBlendMode() != CompositionOp::OP_OVER && HasMultipleChildren()) || (GetEffectiveOpacity() != 1.0 && (HasMultipleChildren() || hasSingleBlendingChild)); }
void PaintedLayerComposite::RenderLayer(const gfx::IntRect& aClipRect) { if (!mBuffer || !mBuffer->IsAttached()) { return; } PROFILER_LABEL("PaintedLayerComposite", "RenderLayer", js::ProfileEntry::Category::GRAPHICS); Compositor* compositor = mCompositeManager->GetCompositor(); MOZ_ASSERT(mBuffer->GetCompositor() == compositor && mBuffer->GetLayer() == this, "buffer is corrupted"); const nsIntRegion& visibleRegion = GetEffectiveVisibleRegion(); #ifdef MOZ_DUMP_PAINTING if (gfxUtils::sDumpPainting) { RefPtr<gfx::DataSourceSurface> surf = mBuffer->GetAsSurface(); if (surf) { WriteSnapshotToDumpFile(this, surf); } } #endif RenderWithAllMasks(this, compositor, aClipRect, [&](EffectChain& effectChain, const Rect& clipRect) { mBuffer->SetPaintWillResample(MayResample()); mBuffer->Composite(this, effectChain, GetEffectiveOpacity(), GetEffectiveTransform(), GetEffectFilter(), clipRect, &visibleRegion); }); mBuffer->BumpFlashCounter(); compositor->MakeCurrent(); }
void BasicCanvasLayer::Paint(DrawTarget* aDT, const Point& aDeviceOffset, Layer* aMaskLayer) { if (IsHidden()) return; if (IsDirty()) { Painted(); FirePreTransactionCallback(); UpdateTarget(); FireDidTransactionCallback(); } if (!mSurface) { return; } const bool needsYFlip = (mOriginPos == gl::OriginPos::BottomLeft); Matrix oldTM; if (needsYFlip) { oldTM = aDT->GetTransform(); aDT->SetTransform(Matrix(oldTM). PreTranslate(0.0f, mBounds.height). PreScale(1.0f, -1.0f)); } FillRectWithMask(aDT, aDeviceOffset, Rect(0, 0, mBounds.width, mBounds.height), mSurface, ToFilter(mFilter), DrawOptions(GetEffectiveOpacity(), GetEffectiveOperator(this)), aMaskLayer); if (needsYFlip) { aDT->SetTransform(oldTM); } }
void ContainerLayer::DefaultComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface) { gfxMatrix residual; gfx3DMatrix idealTransform = GetLocalTransform()*aTransformToSurface; mEffectiveTransform = SnapTransform(idealTransform, gfxRect(0, 0, 0, 0), &residual); PRBool useIntermediateSurface; float opacity = GetEffectiveOpacity(); if (opacity != 1.0f && HasMultipleChildren()) { useIntermediateSurface = PR_TRUE; } else { useIntermediateSurface = PR_FALSE; gfxMatrix contTransform; if (!mEffectiveTransform.Is2D(&contTransform) || !contTransform.PreservesAxisAlignedRectangles()) { for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) { const nsIntRect *clipRect = child->GetEffectiveClipRect(); /* We can't (easily) forward our transform to children with a non-empty clip * rect since it would need to be adjusted for the transform. * TODO: This is easily solvable for translation/scaling transforms. */ if (clipRect && !clipRect->IsEmpty() && !child->GetVisibleRegion().IsEmpty()) { useIntermediateSurface = PR_TRUE; break; } } } } mUseIntermediateSurface = useIntermediateSurface; if (useIntermediateSurface) { ComputeEffectiveTransformsForChildren(gfx3DMatrix::From2D(residual)); } else { ComputeEffectiveTransformsForChildren(idealTransform); } }
void BasicShadowCanvasLayer::Paint(gfxContext* aContext, Layer* aMaskLayer) { NS_ASSERTION(BasicManager()->InDrawing(), "Can only draw in drawing phase"); if (!IsSurfaceDescriptorValid(mFrontSurface)) { return; } AutoOpenSurface autoSurface(OPEN_READ_ONLY, mFrontSurface); nsRefPtr<gfxPattern> pat = new gfxPattern(autoSurface.Get()); pat->SetFilter(mFilter); pat->SetExtend(gfxPattern::EXTEND_PAD); gfxRect r(0, 0, mBounds.width, mBounds.height); gfxMatrix m; if (mNeedsYFlip) { m = aContext->CurrentMatrix(); aContext->Translate(gfxPoint(0.0, mBounds.height)); aContext->Scale(1.0, -1.0); } AutoSetOperator setOperator(aContext, GetOperator()); aContext->NewPath(); // No need to snap here; our transform has already taken care of it aContext->Rectangle(r); aContext->SetPattern(pat); FillWithMask(aContext, GetEffectiveOpacity(), aMaskLayer); if (mNeedsYFlip) { aContext->SetMatrix(m); } }
void ImageLayerComposite::RenderLayer(const nsIntPoint& aOffset, const nsIntRect& aClipRect) { if (!mImageHost) { return; } mCompositor->MakeCurrent(); EffectChain effectChain; LayerManagerComposite::AddMaskEffect(mMaskLayer, effectChain); gfx::Matrix4x4 transform; ToMatrix4x4(GetEffectiveTransform(), transform); gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height); mImageHost->SetCompositor(mCompositor); mImageHost->Composite(effectChain, GetEffectiveOpacity(), transform, gfx::Point(aOffset.x, aOffset.y), gfx::ToFilter(mFilter), clipRect); }
void ContainerLayerD3D10::RenderLayer() { float renderTargetOffset[] = { 0, 0 }; nsIntRect visibleRect = mVisibleRegion.GetBounds(); float opacity = GetEffectiveOpacity(); bool useIntermediate = UseIntermediateSurface(); nsRefPtr<ID3D10RenderTargetView> previousRTView; nsRefPtr<ID3D10Texture2D> renderTexture; nsRefPtr<ID3D10RenderTargetView> rtView; float previousRenderTargetOffset[2]; nsIntSize previousViewportSize; gfx3DMatrix oldViewMatrix; if (useIntermediate) { device()->OMGetRenderTargets(1, getter_AddRefs(previousRTView), NULL); D3D10_TEXTURE2D_DESC desc; memset(&desc, 0, sizeof(D3D10_TEXTURE2D_DESC)); desc.ArraySize = 1; desc.MipLevels = 1; desc.Width = visibleRect.width; desc.Height = visibleRect.height; desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE; desc.SampleDesc.Count = 1; desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; HRESULT hr; hr = device()->CreateTexture2D(&desc, NULL, getter_AddRefs(renderTexture)); if (FAILED(hr)) { LayerManagerD3D10::ReportFailure(NS_LITERAL_CSTRING("Failed to create new texture for ContainerLayerD3D10!"), hr); return; } hr = device()->CreateRenderTargetView(renderTexture, NULL, getter_AddRefs(rtView)); NS_ASSERTION(SUCCEEDED(hr), "Failed to create render target view for ContainerLayerD3D10!"); effect()->GetVariableByName("vRenderTargetOffset")-> GetRawValue(previousRenderTargetOffset, 0, 8); previousViewportSize = mD3DManager->GetViewport(); if (mVisibleRegion.GetNumRects() != 1 || !(GetContentFlags() & CONTENT_OPAQUE)) { const gfx3DMatrix& transform3D = GetEffectiveTransform(); gfxMatrix transform; // If we have an opaque ancestor layer, then we can be sure that // all the pixels we draw into are either opaque already or will be // covered by something opaque. Otherwise copying up the background is // not safe. if (mSupportsComponentAlphaChildren) { bool is2d = transform3D.Is2D(&transform); NS_ASSERTION(is2d, "Transform should be 2d when mSupportsComponentAlphaChildren."); // Copy background up from below. This applies any 2D transform that is // applied to use relative to our parent, and compensates for the offset // that was applied on our parent's rendering. D3D10_BOX srcBox; srcBox.left = std::max<int32_t>(visibleRect.x + int32_t(transform.x0) - int32_t(previousRenderTargetOffset[0]), 0); srcBox.top = std::max<int32_t>(visibleRect.y + int32_t(transform.y0) - int32_t(previousRenderTargetOffset[1]), 0); srcBox.right = std::min<int32_t>(srcBox.left + visibleRect.width, previousViewportSize.width); srcBox.bottom = std::min<int32_t>(srcBox.top + visibleRect.height, previousViewportSize.height); srcBox.back = 1; srcBox.front = 0; nsRefPtr<ID3D10Resource> srcResource; previousRTView->GetResource(getter_AddRefs(srcResource)); device()->CopySubresourceRegion(renderTexture, 0, 0, 0, 0, srcResource, 0, &srcBox); } else { float black[] = { 0, 0, 0, 0}; device()->ClearRenderTargetView(rtView, black); } } ID3D10RenderTargetView *rtViewPtr = rtView; device()->OMSetRenderTargets(1, &rtViewPtr, NULL); renderTargetOffset[0] = (float)visibleRect.x; renderTargetOffset[1] = (float)visibleRect.y; effect()->GetVariableByName("vRenderTargetOffset")-> SetRawValue(renderTargetOffset, 0, 8); mD3DManager->SetViewport(nsIntSize(visibleRect.Size())); } D3D10_RECT oldD3D10Scissor; UINT numRects = 1; device()->RSGetScissorRects(&numRects, &oldD3D10Scissor); // Convert scissor to an nsIntRect. D3D10_RECT's are exclusive // on the bottom and right values. nsIntRect oldScissor(oldD3D10Scissor.left, oldD3D10Scissor.top, oldD3D10Scissor.right - oldD3D10Scissor.left, oldD3D10Scissor.bottom - oldD3D10Scissor.top); nsAutoTArray<Layer*, 12> children; SortChildrenBy3DZOrder(children); /* * Render this container's contents. */ for (uint32_t i = 0; i < children.Length(); i++) { LayerD3D10* layerToRender = static_cast<LayerD3D10*>(children.ElementAt(i)->ImplData()); if (layerToRender->GetLayer()->GetEffectiveVisibleRegion().IsEmpty()) { continue; } nsIntRect scissorRect = layerToRender->GetLayer()->CalculateScissorRect(oldScissor, nullptr); if (scissorRect.IsEmpty()) { continue; } D3D10_RECT d3drect; d3drect.left = scissorRect.x; d3drect.top = scissorRect.y; d3drect.right = scissorRect.x + scissorRect.width; d3drect.bottom = scissorRect.y + scissorRect.height; device()->RSSetScissorRects(1, &d3drect); layerToRender->RenderLayer(); } device()->RSSetScissorRects(1, &oldD3D10Scissor); if (useIntermediate) { mD3DManager->SetViewport(previousViewportSize); ID3D10RenderTargetView *rtView = previousRTView; device()->OMSetRenderTargets(1, &rtView, NULL); effect()->GetVariableByName("vRenderTargetOffset")-> SetRawValue(previousRenderTargetOffset, 0, 8); SetEffectTransformAndOpacity(); ID3D10EffectTechnique *technique; if (LoadMaskTexture()) { if (GetTransform().CanDraw2D()) { technique = SelectShader(SHADER_RGBA | SHADER_PREMUL | SHADER_MASK); } else { technique = SelectShader(SHADER_RGBA | SHADER_PREMUL | SHADER_MASK_3D); } } else { technique = SelectShader(SHADER_RGBA | SHADER_PREMUL | SHADER_NO_MASK); } effect()->GetVariableByName("vLayerQuad")->AsVector()->SetFloatVector( ShaderConstantRectD3D10( (float)visibleRect.x, (float)visibleRect.y, (float)visibleRect.width, (float)visibleRect.height) ); technique->GetPassByIndex(0)->Apply(0); ID3D10ShaderResourceView *view; device()->CreateShaderResourceView(renderTexture, NULL, &view); device()->PSSetShaderResources(0, 1, &view); device()->Draw(4, 0); view->Release(); } }
void BasicThebesLayer::PaintThebes(gfxContext* aContext, Layer* aMaskLayer, LayerManager::DrawThebesLayerCallback aCallback, void* aCallbackData, ReadbackProcessor* aReadback) { PROFILER_LABEL("BasicThebesLayer", "PaintThebes"); NS_ASSERTION(BasicManager()->InDrawing(), "Can only draw in drawing phase"); nsRefPtr<gfxASurface> targetSurface = aContext->CurrentSurface(); if (!mContentClient) { // we pass a null pointer for the Forwarder argument, which means // this will not have a ContentHost on the other side. mContentClient = new ContentClientBasic(nullptr, BasicManager()); } nsTArray<ReadbackProcessor::Update> readbackUpdates; if (aReadback && UsedForReadback()) { aReadback->GetThebesLayerUpdates(this, &readbackUpdates); } //TODO: This is going to copy back pixels that we might end up // drawing over anyway. It would be nice if we could avoid // this duplication. mContentClient->SyncFrontBufferToBackBuffer(); bool canUseOpaqueSurface = CanUseOpaqueSurface(); ContentType contentType = canUseOpaqueSurface ? gfxASurface::CONTENT_COLOR : gfxASurface::CONTENT_COLOR_ALPHA; float opacity = GetEffectiveOpacity(); if (!BasicManager()->IsRetained()) { NS_ASSERTION(readbackUpdates.IsEmpty(), "Can't do readback for non-retained layer"); mValidRegion.SetEmpty(); mContentClient->Clear(); nsIntRegion toDraw = IntersectWithClip(GetEffectiveVisibleRegion(), aContext); RenderTraceInvalidateStart(this, "FFFF00", toDraw.GetBounds()); if (!toDraw.IsEmpty() && !IsHidden()) { if (!aCallback) { BasicManager()->SetTransactionIncomplete(); return; } aContext->Save(); bool needsClipToVisibleRegion = GetClipToVisibleRegion(); bool needsGroup = opacity != 1.0 || GetOperator() != gfxContext::OPERATOR_OVER || aMaskLayer; nsRefPtr<gfxContext> groupContext; if (needsGroup) { groupContext = BasicManager()->PushGroupForLayer(aContext, this, toDraw, &needsClipToVisibleRegion); if (GetOperator() != gfxContext::OPERATOR_OVER) { needsClipToVisibleRegion = true; } } else { groupContext = aContext; } SetAntialiasingFlags(this, groupContext); aCallback(this, groupContext, toDraw, CLIP_NONE, nsIntRegion(), aCallbackData); if (needsGroup) { BasicManager()->PopGroupToSourceWithCachedSurface(aContext, groupContext); if (needsClipToVisibleRegion) { gfxUtils::ClipToRegion(aContext, toDraw); } AutoSetOperator setOperator(aContext, GetOperator()); PaintWithMask(aContext, opacity, aMaskLayer); } aContext->Restore(); } RenderTraceInvalidateEnd(this, "FFFF00"); return; } { uint32_t flags = 0; #ifndef MOZ_WIDGET_ANDROID if (BasicManager()->CompositorMightResample()) { flags |= ThebesLayerBuffer::PAINT_WILL_RESAMPLE; } if (!(flags & ThebesLayerBuffer::PAINT_WILL_RESAMPLE)) { if (MayResample()) { flags |= ThebesLayerBuffer::PAINT_WILL_RESAMPLE; } } #endif if (mDrawAtomically) { flags |= ThebesLayerBuffer::PAINT_NO_ROTATION; } PaintState state = mContentClient->BeginPaintBuffer(this, contentType, flags); mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate); if (state.mContext) { // The area that became invalid and is visible needs to be repainted // (this could be the whole visible area if our buffer switched // from RGB to RGBA, because we might need to repaint with // subpixel AA) state.mRegionToInvalidate.And(state.mRegionToInvalidate, GetEffectiveVisibleRegion()); nsIntRegion extendedDrawRegion = state.mRegionToDraw; SetAntialiasingFlags(this, state.mContext); RenderTraceInvalidateStart(this, "FFFF00", state.mRegionToDraw.GetBounds()); PaintBuffer(state.mContext, state.mRegionToDraw, extendedDrawRegion, state.mRegionToInvalidate, state.mDidSelfCopy, state.mClip, aCallback, aCallbackData); MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PaintThebes", this)); Mutated(); RenderTraceInvalidateEnd(this, "FFFF00"); } else { // It's possible that state.mRegionToInvalidate is nonempty here, // if we are shrinking the valid region to nothing. So use mRegionToDraw // instead. NS_WARN_IF_FALSE(state.mRegionToDraw.IsEmpty(), "No context when we have something to draw, resource exhaustion?"); } } if (BasicManager()->IsTransactionIncomplete()) return; gfxRect clipExtents; clipExtents = aContext->GetClipExtents(); // Pull out the mask surface and transform here, because the mask // is internal to basic layers AutoMaskData mask; gfxASurface* maskSurface = nullptr; const gfxMatrix* maskTransform = nullptr; if (GetMaskData(aMaskLayer, &mask)) { maskSurface = mask.GetSurface(); maskTransform = &mask.GetTransform(); } if (!IsHidden() && !clipExtents.IsEmpty()) { AutoSetOperator setOperator(aContext, GetOperator()); mContentClient->DrawTo(this, aContext, opacity, maskSurface, maskTransform); } for (uint32_t i = 0; i < readbackUpdates.Length(); ++i) { ReadbackProcessor::Update& update = readbackUpdates[i]; nsIntPoint offset = update.mLayer->GetBackgroundLayerOffset(); nsRefPtr<gfxContext> ctx = update.mLayer->GetSink()->BeginUpdate(update.mUpdateRect + offset, update.mSequenceCounter); if (ctx) { NS_ASSERTION(opacity == 1.0, "Should only read back opaque layers"); ctx->Translate(gfxPoint(offset.x, offset.y)); mContentClient->DrawTo(this, ctx, 1.0, maskSurface, maskTransform); update.mLayer->GetSink()->EndUpdate(ctx, update.mUpdateRect + offset); } } }
void BasicThebesLayer::PaintThebes(gfxContext* aContext, Layer* aMaskLayer, LayerManager::DrawThebesLayerCallback aCallback, void* aCallbackData, ReadbackProcessor* aReadback) { PROFILER_LABEL("BasicThebesLayer", "PaintThebes"); NS_ASSERTION(BasicManager()->InDrawing(), "Can only draw in drawing phase"); nsTArray<ReadbackProcessor::Update> readbackUpdates; if (aReadback && UsedForReadback()) { aReadback->GetThebesLayerUpdates(this, &readbackUpdates); } float opacity = GetEffectiveOpacity(); CompositionOp effectiveOperator = GetEffectiveOperator(this); if (!BasicManager()->IsRetained()) { NS_ASSERTION(readbackUpdates.IsEmpty(), "Can't do readback for non-retained layer"); mValidRegion.SetEmpty(); mContentClient->Clear(); nsIntRegion toDraw = IntersectWithClip(GetEffectiveVisibleRegion(), aContext); RenderTraceInvalidateStart(this, "FFFF00", toDraw.GetBounds()); if (!toDraw.IsEmpty() && !IsHidden()) { if (!aCallback) { BasicManager()->SetTransactionIncomplete(); return; } aContext->Save(); bool needsClipToVisibleRegion = GetClipToVisibleRegion(); bool needsGroup = opacity != 1.0 || effectiveOperator != CompositionOp::OP_OVER || aMaskLayer; nsRefPtr<gfxContext> groupContext; if (needsGroup) { groupContext = BasicManager()->PushGroupForLayer(aContext, this, toDraw, &needsClipToVisibleRegion); if (effectiveOperator != CompositionOp::OP_OVER) { needsClipToVisibleRegion = true; } } else { groupContext = aContext; } SetAntialiasingFlags(this, groupContext); aCallback(this, groupContext, toDraw, DrawRegionClip::CLIP_NONE, nsIntRegion(), aCallbackData); if (needsGroup) { BasicManager()->PopGroupToSourceWithCachedSurface(aContext, groupContext); if (needsClipToVisibleRegion) { gfxUtils::ClipToRegion(aContext, toDraw); } AutoSetOperator setOptimizedOperator(aContext, ThebesOp(effectiveOperator)); PaintWithMask(aContext, opacity, aMaskLayer); } aContext->Restore(); } RenderTraceInvalidateEnd(this, "FFFF00"); return; } if (BasicManager()->IsTransactionIncomplete()) return; gfxRect clipExtents; clipExtents = aContext->GetClipExtents(); // Pull out the mask surface and transform here, because the mask // is internal to basic layers AutoMoz2DMaskData mask; SourceSurface* maskSurface = nullptr; Matrix maskTransform; if (GetMaskData(aMaskLayer, &mask)) { maskSurface = mask.GetSurface(); maskTransform = mask.GetTransform(); } if (!IsHidden() && !clipExtents.IsEmpty()) { mContentClient->DrawTo(this, aContext->GetDrawTarget(), opacity, GetOperator(), maskSurface, &maskTransform); } for (uint32_t i = 0; i < readbackUpdates.Length(); ++i) { ReadbackProcessor::Update& update = readbackUpdates[i]; nsIntPoint offset = update.mLayer->GetBackgroundLayerOffset(); nsRefPtr<gfxContext> ctx = update.mLayer->GetSink()->BeginUpdate(update.mUpdateRect + offset, update.mSequenceCounter); if (ctx) { NS_ASSERTION(opacity == 1.0, "Should only read back opaque layers"); ctx->Translate(gfxPoint(offset.x, offset.y)); mContentClient->DrawTo(this, ctx->GetDrawTarget(), 1.0, CompositionOpForOp(ctx->CurrentOperator()), maskSurface, &maskTransform); update.mLayer->GetSink()->EndUpdate(ctx, update.mUpdateRect + offset); } } }
void BasicContainerLayer::ComputeEffectiveTransforms(const Matrix4x4& aTransformToSurface) { // We push groups for container layers if we need to, which always // are aligned in device space, so it doesn't really matter how we snap // containers. Matrix residual; Matrix4x4 idealTransform = GetLocalTransform() * aTransformToSurface; if (!Extend3DContext() && !Is3DContextLeaf()) { // For 3D transform leaked from extended parent layer. idealTransform.ProjectTo2D(); } if (!idealTransform.CanDraw2D()) { if (!Extend3DContext() || (!idealTransform.Is2D() && Creates3DContextWithExtendingChildren())) { if (!Creates3DContextWithExtendingChildren()) { idealTransform.ProjectTo2D(); } mEffectiveTransform = idealTransform; ComputeEffectiveTransformsForChildren(Matrix4x4()); ComputeEffectiveTransformForMaskLayers(Matrix4x4()); mUseIntermediateSurface = true; return; } mEffectiveTransform = idealTransform; ComputeEffectiveTransformsForChildren(idealTransform); ComputeEffectiveTransformForMaskLayers(idealTransform); mUseIntermediateSurface = false; return; } // With 2D transform or extended 3D context. Layer* child = GetFirstChild(); bool hasSingleBlendingChild = false; if (!HasMultipleChildren() && child) { hasSingleBlendingChild = child->GetMixBlendMode() != CompositionOp::OP_OVER; } /* If we have a single childand it is not blending,, it can just inherit our opacity, * otherwise we need a PushGroup and we need to mark ourselves as using * an intermediate surface so our children don't inherit our opacity * via GetEffectiveOpacity. * Having a mask layer always forces our own push group * Having a blend mode also always forces our own push group */ mUseIntermediateSurface = GetMaskLayer() || GetForceIsolatedGroup() || (GetMixBlendMode() != CompositionOp::OP_OVER && HasMultipleChildren()) || (GetEffectiveOpacity() != 1.0 && (HasMultipleChildren() || hasSingleBlendingChild)); if (!Extend3DContext()) { idealTransform.ProjectTo2D(); } mEffectiveTransform = !mUseIntermediateSurface ? idealTransform : SnapTransformTranslation(idealTransform, &residual); Matrix4x4 childTransformToSurface = (!mUseIntermediateSurface || (mUseIntermediateSurface && !Extend3DContext() /* 2D */)) ? idealTransform : Matrix4x4::From2D(residual); ComputeEffectiveTransformsForChildren(childTransformToSurface); ComputeEffectiveTransformForMaskLayers(aTransformToSurface); }
void ContainerLayerOGL::RenderLayer(int aPreviousFrameBuffer, const nsIntPoint& aOffset) { /** * Setup our temporary texture for rendering the contents of this container. */ GLuint containerSurface; GLuint frameBuffer; nsIntPoint childOffset(aOffset); nsIntRect visibleRect = GetEffectiveVisibleRegion().GetBounds(); nsIntRect cachedScissor = gl()->ScissorRect(); gl()->PushScissorRect(); mSupportsComponentAlphaChildren = false; float opacity = GetEffectiveOpacity(); const gfx3DMatrix& transform = GetEffectiveTransform(); bool needsFramebuffer = UseIntermediateSurface(); if (needsFramebuffer) { nsIntRect framebufferRect = visibleRect; // we're about to create a framebuffer backed by textures to use as an intermediate // surface. What to do if its size (as given by framebufferRect) would exceed the // maximum texture size supported by the GL? The present code chooses the compromise // of just clamping the framebuffer's size to the max supported size. // This gives us a lower resolution rendering of the intermediate surface (children layers). // See bug 827170 for a discussion. GLint maxTexSize; gl()->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &maxTexSize); framebufferRect.width = std::min(framebufferRect.width, maxTexSize); framebufferRect.height = std::min(framebufferRect.height, maxTexSize); LayerManagerOGL::InitMode mode = LayerManagerOGL::InitModeClear; if (GetEffectiveVisibleRegion().GetNumRects() == 1 && (GetContentFlags() & Layer::CONTENT_OPAQUE)) { // don't need a background, we're going to paint all opaque stuff mSupportsComponentAlphaChildren = true; mode = LayerManagerOGL::InitModeNone; } else { const gfx3DMatrix& transform3D = GetEffectiveTransform(); gfxMatrix transform; // If we have an opaque ancestor layer, then we can be sure that // all the pixels we draw into are either opaque already or will be // covered by something opaque. Otherwise copying up the background is // not safe. if (HasOpaqueAncestorLayer(this) && transform3D.Is2D(&transform) && !transform.HasNonIntegerTranslation()) { mode = gfxPlatform::ComponentAlphaEnabled() ? LayerManagerOGL::InitModeCopy : LayerManagerOGL::InitModeClear; framebufferRect.x += transform.x0; framebufferRect.y += transform.y0; mSupportsComponentAlphaChildren = gfxPlatform::ComponentAlphaEnabled(); } } gl()->PushViewportRect(); framebufferRect -= childOffset; if (!mOGLManager->CompositingDisabled()) { if (!mOGLManager->CreateFBOWithTexture(framebufferRect, mode, aPreviousFrameBuffer, &frameBuffer, &containerSurface)) { gl()->PopViewportRect(); gl()->PopScissorRect(); gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer); return; } } childOffset.x = visibleRect.x; childOffset.y = visibleRect.y; } else { frameBuffer = aPreviousFrameBuffer; mSupportsComponentAlphaChildren = (GetContentFlags() & Layer::CONTENT_OPAQUE) || (GetParent() && GetParent()->SupportsComponentAlphaChildren()); } nsAutoTArray<Layer*, 12> children; SortChildrenBy3DZOrder(children); /** * Render this container's contents. */ for (uint32_t i = 0; i < children.Length(); i++) { LayerOGL* layerToRender = static_cast<LayerOGL*>(children.ElementAt(i)->ImplData()); if (layerToRender->GetLayer()->GetEffectiveVisibleRegion().IsEmpty()) { continue; } nsIntRect scissorRect = layerToRender->GetLayer()-> CalculateScissorRect(cachedScissor, &mOGLManager->GetWorldTransform()); if (scissorRect.IsEmpty()) { continue; } gl()->fScissor(scissorRect.x, scissorRect.y, scissorRect.width, scissorRect.height); layerToRender->RenderLayer(frameBuffer, childOffset); gl()->MakeCurrent(); } if (needsFramebuffer) { // Unbind the current framebuffer and rebind the previous one. #ifdef MOZ_DUMP_PAINTING if (gfxUtils::sDumpPainting) { nsRefPtr<gfxImageSurface> surf = gl()->GetTexImage(containerSurface, true, mOGLManager->GetFBOTextureFormat()); WriteSnapshotToDumpFile(this, surf); } #endif // Restore the viewport gl()->PopViewportRect(); nsIntRect viewport = gl()->ViewportRect(); mOGLManager->SetupPipeline(viewport.width, viewport.height, LayerManagerOGL::ApplyWorldTransform); gl()->PopScissorRect(); if (!mOGLManager->CompositingDisabled()) { gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer); gl()->fDeleteFramebuffers(1, &frameBuffer); gl()->fActiveTexture(LOCAL_GL_TEXTURE0); gl()->fBindTexture(mOGLManager->FBOTextureTarget(), containerSurface); MaskType maskType = MaskNone; if (GetMaskLayer()) { if (!GetTransform().CanDraw2D()) { maskType = Mask3d; } else { maskType = Mask2d; } } ShaderProgramOGL *rgb = mOGLManager->GetFBOLayerProgram(maskType); rgb->Activate(); rgb->SetLayerQuadRect(visibleRect); rgb->SetLayerTransform(transform); rgb->SetTextureTransform(gfx3DMatrix()); rgb->SetLayerOpacity(opacity); rgb->SetRenderOffset(aOffset); rgb->SetTextureUnit(0); rgb->LoadMask(GetMaskLayer()); if (rgb->GetTexCoordMultiplierUniformLocation() != -1) { // 2DRect case, get the multiplier right for a sampler2DRect rgb->SetTexCoordMultiplier(visibleRect.width, visibleRect.height); } // Drawing is always flipped, but when copying between surfaces we want to avoid // this. Pass true for the flip parameter to introduce a second flip // that cancels the other one out. mOGLManager->BindAndDrawQuad(rgb, true); // Clean up resources. This also unbinds the texture. gl()->fDeleteTextures(1, &containerSurface); } } else { gl()->PopScissorRect(); } }
virtual void Paint(gfxContext* aContext, Layer* aMaskLayer) { AutoSetOperator setOperator(aContext, GetOperator()); BasicColorLayer::PaintColorTo(mColor, GetEffectiveOpacity(), aContext, aMaskLayer); }