Bug 1632310 [wpt PR 23186] - Add test for computed versus resolved style., a=testonly
[gecko.git] / gfx / layers / mlgpu / ContainerLayerMLGPU.cpp
blob1a1413b28d858432dd9261042c07894265e40f12
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"
17 namespace mozilla {
18 namespace layers {
20 using namespace gfx;
22 ContainerLayerMLGPU::ContainerLayerMLGPU(LayerManagerMLGPU* aManager)
23 : ContainerLayer(aManager, nullptr),
24 LayerMLGPU(aManager),
25 mInvalidateEntireSurface(false),
26 mSurfaceCopyNeeded(false),
27 mView(nullptr) {}
29 ContainerLayerMLGPU::~ContainerLayerMLGPU() {
30 while (mFirstChild) {
31 RemoveChild(mFirstChild);
35 bool ContainerLayerMLGPU::OnPrepareToRender(FrameBuilder* aBuilder) {
36 mView = nullptr;
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;
42 return 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;
70 } else {
71 // Clamp the invalid rect to the viewport.
72 mInvalidRect -= mTargetOffset;
73 mInvalidRect = mInvalidRect.Intersect(viewport);
76 mInvalidateEntireSurface = false;
77 return true;
80 static IntRect GetTransformedBounds(Layer* aLayer) {
81 IntRect bounds = aLayer->GetLocalVisibleRegion().GetBounds().ToUnknownRect();
82 if (bounds.IsEmpty()) {
83 return bounds;
86 const Matrix4x4& transform = aLayer->GetEffectiveTransform();
87 Rect rect =
88 transform.TransformAndClipBounds(Rect(bounds), Rect::MaxIntRect());
89 rect.RoundOut();
90 rect.ToIntRect(&bounds);
91 return bounds;
94 /* static */
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();
101 if (container) {
102 if (container->UseIntermediateSurface()) {
103 ContainerLayerMLGPU* c =
104 container->AsHostLayer()->AsLayerMLGPU()->AsContainerLayerMLGPU();
105 if (!c) {
106 gfxCriticalError()
107 << "not container: "
108 << container->AsHostLayer()->AsLayerMLGPU()->GetType();
110 MOZ_RELEASE_ASSERT(c);
111 c->ComputeIntermediateSurfaceBounds();
112 } else {
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),
125 childClip.value());
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);
133 if (!childBounds) {
134 return Nothing();
137 accumulated = accumulated->SafeUnion(childBounds.value());
138 if (!accumulated) {
139 return Nothing();
142 return accumulated;
146 IntRect bounds = GetTransformedBounds(aLayer);
147 AL_LOG(" layer bounds: %s\n", Stringify(bounds).c_str());
149 if (aClip) {
150 bounds = bounds.Intersect(aClip.value().ToUnknownRect());
151 AL_LOG(" clipped bounds: %s\n", Stringify(bounds).c_str());
153 return Some(bounds);
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);
163 if (!childBounds) {
164 return;
167 bounds = bounds->SafeUnion(childBounds.value());
168 if (!bounds) {
169 return;
173 SetShadowVisibleRegion(LayerIntRect::FromUnknownRect(bounds.value()));
176 void ContainerLayerMLGPU::OnLayerManagerChange(LayerManagerMLGPU* aManager) {
177 ClearCachedResources();
180 RefPtr<MLGRenderTarget> ContainerLayerMLGPU::UpdateRenderTarget(
181 MLGDevice* aDevice, MLGRenderTargetFlags aFlags) {
182 if (mRenderTarget) {
183 return mRenderTarget;
186 mRenderTarget = aDevice->CreateRenderTarget(mTargetSize, aFlags);
187 if (!mRenderTarget) {
188 gfxWarning()
189 << "Failed to create an intermediate render target for ContainerLayer";
190 return nullptr;
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
198 // are expensive.
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
203 // anyway.
204 if (aRect) {
205 if (Maybe<gfx::IntRect> result = mInvalidRect.SafeUnion(*aRect)) {
206 mInvalidRect = result.value();
207 } else {
208 mInvalidateEntireSurface = true;
210 } else {
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
220 // be not opaque.
221 return false;
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