1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "ContainerLayerMLGPU.h"
8 #include "mozilla/StaticPrefs_layers.h"
9 #include "LayersLogging.h"
10 #include "LayerManagerMLGPU.h"
11 #include "MLGDevice.h"
12 #include "mozilla/gfx/Rect.h"
13 #include "mozilla/gfx/Types.h"
14 #include "UnitTransforms.h"
15 #include "UtilityMLGPU.h"
22 ContainerLayerMLGPU::ContainerLayerMLGPU(LayerManagerMLGPU
* aManager
)
23 : ContainerLayer(aManager
, nullptr),
25 mInvalidateEntireSurface(false),
26 mSurfaceCopyNeeded(false),
29 ContainerLayerMLGPU::~ContainerLayerMLGPU() {
31 RemoveChild(mFirstChild
);
35 bool ContainerLayerMLGPU::OnPrepareToRender(FrameBuilder
* aBuilder
) {
38 if (!UseIntermediateSurface()) {
39 // Set this so we invalidate the entire cached render target (if any)
40 // if our container uses an intermediate surface again later.
41 mInvalidateEntireSurface
= true;
45 mChildrenChanged
= false;
47 mTargetOffset
= GetIntermediateSurfaceRect().TopLeft().ToUnknownPoint();
48 mTargetSize
= GetIntermediateSurfaceRect().Size().ToUnknownSize();
50 if (mRenderTarget
&& mRenderTarget
->GetSize() != mTargetSize
) {
51 mRenderTarget
= nullptr;
54 // Note that if a surface copy is needed, we always redraw the
55 // whole surface (on-demand). This is a rare case - the old
56 // Compositor already does this - and it saves us having to
57 // do much more complicated invalidation.
58 bool surfaceCopyNeeded
= false;
59 DefaultComputeSupportsComponentAlphaChildren(&surfaceCopyNeeded
);
60 if (surfaceCopyNeeded
!= mSurfaceCopyNeeded
|| surfaceCopyNeeded
) {
61 mInvalidateEntireSurface
= true;
63 mSurfaceCopyNeeded
= surfaceCopyNeeded
;
65 gfx::IntRect
viewport(gfx::IntPoint(0, 0), mTargetSize
);
66 if (!mRenderTarget
|| !StaticPrefs::layers_mlgpu_enable_invalidation() ||
67 mInvalidateEntireSurface
) {
68 // Fine-grained invalidation is disabled, invalidate everything.
69 mInvalidRect
= viewport
;
71 // Clamp the invalid rect to the viewport.
72 mInvalidRect
-= mTargetOffset
;
73 mInvalidRect
= mInvalidRect
.Intersect(viewport
);
76 mInvalidateEntireSurface
= false;
80 static IntRect
GetTransformedBounds(Layer
* aLayer
) {
81 IntRect bounds
= aLayer
->GetLocalVisibleRegion().GetBounds().ToUnknownRect();
82 if (bounds
.IsEmpty()) {
86 const Matrix4x4
& transform
= aLayer
->GetEffectiveTransform();
88 transform
.TransformAndClipBounds(Rect(bounds
), Rect::MaxIntRect());
90 rect
.ToIntRect(&bounds
);
95 Maybe
<IntRect
> ContainerLayerMLGPU::FindVisibleBounds(
96 Layer
* aLayer
, const Maybe
<RenderTargetIntRect
>& aClip
) {
97 AL_LOG(" visiting child %p\n", aLayer
);
98 AL_LOG_IF(aClip
, " parent clip: %s\n", Stringify(aClip
.value()).c_str());
100 ContainerLayer
* container
= aLayer
->AsContainerLayer();
102 if (container
->UseIntermediateSurface()) {
103 ContainerLayerMLGPU
* c
=
104 container
->AsHostLayer()->AsLayerMLGPU()->AsContainerLayerMLGPU();
108 << container
->AsHostLayer()->AsLayerMLGPU()->GetType();
110 MOZ_RELEASE_ASSERT(c
);
111 c
->ComputeIntermediateSurfaceBounds();
113 Maybe
<IntRect
> accumulated
= Some(IntRect());
115 // Traverse children.
116 for (Layer
* child
= container
->GetFirstChild(); child
;
117 child
= child
->GetNextSibling()) {
118 Maybe
<RenderTargetIntRect
> clip
= aClip
;
119 if (const Maybe
<ParentLayerIntRect
>& childClip
=
120 child
->AsHostLayer()->GetShadowClipRect()) {
121 RenderTargetIntRect rtChildClip
= TransformBy(
122 ViewAs
<ParentLayerToRenderTargetMatrix4x4
>(
123 aLayer
->GetEffectiveTransform(),
124 PixelCastJustification::RenderTargetIsParentLayerForRoot
),
126 clip
= IntersectMaybeRects(clip
, Some(rtChildClip
));
127 AL_LOG(" target clip: %s\n", Stringify(rtChildClip
).c_str());
128 AL_LOG_IF(clip
, " full clip: %s\n",
129 Stringify(clip
.value()).c_str());
132 Maybe
<IntRect
> childBounds
= FindVisibleBounds(child
, clip
);
137 accumulated
= accumulated
->SafeUnion(childBounds
.value());
146 IntRect bounds
= GetTransformedBounds(aLayer
);
147 AL_LOG(" layer bounds: %s\n", Stringify(bounds
).c_str());
150 bounds
= bounds
.Intersect(aClip
.value().ToUnknownRect());
151 AL_LOG(" clipped bounds: %s\n", Stringify(bounds
).c_str());
156 void ContainerLayerMLGPU::ComputeIntermediateSurfaceBounds() {
157 Maybe
<IntRect
> bounds
= Some(IntRect());
158 for (Layer
* child
= GetFirstChild(); child
; child
= child
->GetNextSibling()) {
159 Maybe
<RenderTargetIntRect
> clip
= ViewAs
<RenderTargetPixel
>(
160 child
->AsHostLayer()->GetShadowClipRect(),
161 PixelCastJustification::RenderTargetIsParentLayerForRoot
);
162 Maybe
<IntRect
> childBounds
= FindVisibleBounds(child
, clip
);
167 bounds
= bounds
->SafeUnion(childBounds
.value());
173 SetShadowVisibleRegion(LayerIntRect::FromUnknownRect(bounds
.value()));
176 void ContainerLayerMLGPU::OnLayerManagerChange(LayerManagerMLGPU
* aManager
) {
177 ClearCachedResources();
180 RefPtr
<MLGRenderTarget
> ContainerLayerMLGPU::UpdateRenderTarget(
181 MLGDevice
* aDevice
, MLGRenderTargetFlags aFlags
) {
183 return mRenderTarget
;
186 mRenderTarget
= aDevice
->CreateRenderTarget(mTargetSize
, aFlags
);
187 if (!mRenderTarget
) {
189 << "Failed to create an intermediate render target for ContainerLayer";
193 return mRenderTarget
;
196 void ContainerLayerMLGPU::SetInvalidCompositeRect(const gfx::IntRect
* aRect
) {
197 // For simplicity we only track the bounds of the invalid area, since regions
200 // Note we add the bounds to the invalid rect from the last frame, since we
201 // only clear the area that we actually paint. If this overflows we use the
202 // last render target size, since if that changes we'll invalidate everything
205 if (Maybe
<gfx::IntRect
> result
= mInvalidRect
.SafeUnion(*aRect
)) {
206 mInvalidRect
= result
.value();
208 mInvalidateEntireSurface
= true;
211 mInvalidateEntireSurface
= true;
215 void ContainerLayerMLGPU::ClearCachedResources() { mRenderTarget
= nullptr; }
217 bool ContainerLayerMLGPU::IsContentOpaque() {
218 if (GetMixBlendMode() != gfx::CompositionOp::OP_OVER
) {
219 // We need to read from what's underneath us, so we consider our content to
223 return LayerMLGPU::IsContentOpaque();
226 const LayerIntRegion
& ContainerLayerMLGPU::GetShadowVisibleRegion() {
227 if (!UseIntermediateSurface()) {
228 RecomputeShadowVisibleRegionFromChildren();
231 return mShadowVisibleRegion
;
234 const LayerIntRegion
& RefLayerMLGPU::GetShadowVisibleRegion() {
235 if (!UseIntermediateSurface()) {
236 RecomputeShadowVisibleRegionFromChildren();
239 return mShadowVisibleRegion
;
242 } // namespace layers
243 } // namespace mozilla