Line data Source code
1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "ContainerLayerMLGPU.h"
7 : #include "gfxPrefs.h"
8 : #include "LayersLogging.h"
9 : #include "LayerManagerMLGPU.h"
10 : #include "MLGDevice.h"
11 : #include "mozilla/gfx/Rect.h"
12 : #include "mozilla/gfx/Types.h"
13 : #include "UnitTransforms.h"
14 : #include "UtilityMLGPU.h"
15 :
16 : namespace mozilla {
17 : namespace layers {
18 :
19 : using namespace gfx;
20 :
21 0 : ContainerLayerMLGPU::ContainerLayerMLGPU(LayerManagerMLGPU* aManager)
22 : : ContainerLayer(aManager, nullptr)
23 0 : , LayerMLGPU(aManager)
24 : {
25 0 : }
26 :
27 0 : ContainerLayerMLGPU::~ContainerLayerMLGPU()
28 : {
29 0 : while (mFirstChild) {
30 0 : RemoveChild(mFirstChild);
31 : }
32 0 : }
33 :
34 : bool
35 0 : ContainerLayerMLGPU::OnPrepareToRender(FrameBuilder* aBuilder)
36 : {
37 0 : if (!UseIntermediateSurface()) {
38 0 : return true;
39 : }
40 :
41 0 : if ((!mRenderTarget || mChildrenChanged) &&
42 0 : gfxPrefs::AdvancedLayersEnableContainerResizing())
43 : {
44 : // Try to compute a more accurate visible region.
45 : AL_LOG("Computing new surface size for container %p:\n", GetLayer());
46 :
47 0 : Maybe<IntRect> bounds = ComputeIntermediateSurfaceBounds();
48 0 : if (bounds) {
49 0 : LayerIntRegion region = Move(GetShadowVisibleRegion());
50 0 : region.AndWith(LayerIntRect::FromUnknownRect(bounds.value()));
51 : AL_LOG(" computed bounds: %s\n", Stringify(bounds.value()).c_str());
52 : AL_LOG(" new visible: %s\n", Stringify(region).c_str());
53 :
54 0 : SetShadowVisibleRegion(Move(region));
55 : }
56 : }
57 0 : mChildrenChanged = false;
58 :
59 0 : mTargetOffset = GetIntermediateSurfaceRect().TopLeft().ToUnknownPoint();
60 0 : mTargetSize = GetIntermediateSurfaceRect().Size().ToUnknownSize();
61 :
62 0 : if (mRenderTarget && mRenderTarget->GetSize() != mTargetSize) {
63 0 : mRenderTarget = nullptr;
64 : }
65 :
66 0 : gfx::IntRect viewport(gfx::IntPoint(0, 0), mTargetSize);
67 0 : if (!mRenderTarget || !gfxPrefs::AdvancedLayersUseInvalidation()) {
68 : // Fine-grained invalidation is disabled, invalidate everything.
69 0 : mInvalidRect = viewport;
70 : } else {
71 : // Clamp the invalid rect to the viewport.
72 0 : mInvalidRect = mInvalidRect.Intersect(viewport);
73 : }
74 0 : return true;
75 : }
76 :
77 : static IntRect
78 0 : GetTransformedBounds(Layer* aLayer)
79 : {
80 0 : IntRect bounds = aLayer->GetLocalVisibleRegion().GetBounds().ToUnknownRect();
81 0 : if (bounds.IsEmpty()) {
82 0 : return bounds;
83 : }
84 :
85 0 : const Matrix4x4& transform = aLayer->GetEffectiveTransform();
86 0 : Rect rect = transform.TransformAndClipBounds(Rect(bounds), Rect::MaxIntRect());
87 0 : rect.RoundOut();
88 0 : rect.ToIntRect(&bounds);
89 0 : return bounds;
90 : }
91 :
92 : static Maybe<IntRect>
93 0 : FindVisibleBounds(Layer* aLayer, const Maybe<RenderTargetIntRect>& aClip)
94 : {
95 : AL_LOG(" visiting child %p\n", aLayer);
96 : AL_LOG_IF(aClip, " parent clip: %s\n", Stringify(aClip.value()).c_str());
97 :
98 0 : ContainerLayer* container = aLayer->AsContainerLayer();
99 0 : if (container && !container->UseIntermediateSurface()) {
100 0 : Maybe<IntRect> accumulated = Some(IntRect());
101 :
102 : // Traverse children.
103 0 : for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) {
104 0 : Maybe<RenderTargetIntRect> clip = aClip;
105 0 : if (const Maybe<ParentLayerIntRect>& childClip = child->AsHostLayer()->GetShadowClipRect()) {
106 : RenderTargetIntRect rtChildClip =
107 0 : TransformBy(ViewAs<ParentLayerToRenderTargetMatrix4x4>(
108 0 : aLayer->GetEffectiveTransform(),
109 : PixelCastJustification::RenderTargetIsParentLayerForRoot),
110 0 : childClip.value());
111 0 : clip = IntersectMaybeRects(clip, Some(rtChildClip));
112 : AL_LOG(" target clip: %s\n", Stringify(rtChildClip).c_str());
113 : AL_LOG_IF(clip, " full clip: %s\n", Stringify(clip.value()).c_str());
114 : }
115 :
116 0 : Maybe<IntRect> childBounds = FindVisibleBounds(child, clip);
117 0 : if (!childBounds) {
118 0 : return Nothing();
119 : }
120 :
121 0 : accumulated = accumulated->SafeUnion(childBounds.value());
122 0 : if (!accumulated) {
123 0 : return Nothing();
124 : }
125 : }
126 0 : return accumulated;
127 : }
128 :
129 0 : IntRect bounds = GetTransformedBounds(aLayer);
130 : AL_LOG(" layer bounds: %s\n", Stringify(bounds).c_str());
131 :
132 0 : if (aClip) {
133 0 : bounds = bounds.Intersect(aClip.value().ToUnknownRect());
134 : AL_LOG(" clipped bounds: %s\n", Stringify(bounds).c_str());
135 : }
136 0 : return Some(bounds);
137 : }
138 :
139 : Maybe<IntRect>
140 0 : ContainerLayerMLGPU::ComputeIntermediateSurfaceBounds()
141 : {
142 0 : Maybe<IntRect> bounds = Some(IntRect());
143 0 : for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
144 : Maybe<RenderTargetIntRect> clip =
145 0 : ViewAs<RenderTargetPixel>(child->AsHostLayer()->GetShadowClipRect(),
146 0 : PixelCastJustification::RenderTargetIsParentLayerForRoot);
147 0 : Maybe<IntRect> childBounds = FindVisibleBounds(child, clip);
148 0 : if (!childBounds) {
149 0 : return Nothing();
150 : }
151 :
152 0 : bounds = bounds->SafeUnion(childBounds.value());
153 0 : if (!bounds) {
154 0 : return Nothing();
155 : }
156 : }
157 0 : return bounds;
158 : }
159 :
160 : void
161 0 : ContainerLayerMLGPU::OnLayerManagerChange(LayerManagerMLGPU* aManager)
162 : {
163 0 : ClearCachedResources();
164 0 : }
165 :
166 : RefPtr<MLGRenderTarget>
167 0 : ContainerLayerMLGPU::UpdateRenderTarget(MLGDevice* aDevice, MLGRenderTargetFlags aFlags)
168 : {
169 0 : if (mRenderTarget) {
170 0 : return mRenderTarget;
171 : }
172 :
173 0 : mRenderTarget = aDevice->CreateRenderTarget(mTargetSize, aFlags);
174 0 : if (!mRenderTarget) {
175 0 : gfxWarning() << "Failed to create an intermediate render target for ContainerLayer";
176 0 : return nullptr;
177 : }
178 :
179 0 : return mRenderTarget;
180 : }
181 :
182 : void
183 0 : ContainerLayerMLGPU::SetInvalidCompositeRect(const gfx::IntRect& aRect)
184 : {
185 : // For simplicity we only track the bounds of the invalid area, since regions
186 : // are expensive. We can adjust this in the future if needed.
187 0 : gfx::IntRect bounds = aRect;
188 0 : bounds.MoveBy(-GetTargetOffset());
189 :
190 : // Note we add the bounds to the invalid rect from the last frame, since we
191 : // only clear the area that we actually paint.
192 0 : if (Maybe<gfx::IntRect> result = mInvalidRect.SafeUnion(bounds)) {
193 0 : mInvalidRect = result.value();
194 : } else {
195 0 : mInvalidRect = gfx::IntRect(gfx::IntPoint(0, 0), GetTargetSize());
196 : }
197 0 : }
198 :
199 : void
200 0 : ContainerLayerMLGPU::ClearCachedResources()
201 : {
202 0 : mRenderTarget = nullptr;
203 0 : }
204 :
205 : bool
206 0 : ContainerLayerMLGPU::IsContentOpaque()
207 : {
208 0 : if (GetMixBlendMode() != gfx::CompositionOp::OP_OVER) {
209 : // We need to read from what's underneath us, so we consider our content to
210 : // be not opaque.
211 0 : return false;
212 : }
213 0 : return LayerMLGPU::IsContentOpaque();
214 : }
215 :
216 : } // namespace layers
217 : } // namespace mozilla
|