/src/mozilla-central/gfx/layers/mlgpu/ContainerLayerMLGPU.cpp
Line | Count | Source (jump to first uncovered line) |
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/. */ |
6 | | |
7 | | #include "ContainerLayerMLGPU.h" |
8 | | #include "gfxPrefs.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" |
16 | | |
17 | | namespace mozilla { |
18 | | namespace layers { |
19 | | |
20 | | using namespace gfx; |
21 | | |
22 | | ContainerLayerMLGPU::ContainerLayerMLGPU(LayerManagerMLGPU* aManager) |
23 | | : ContainerLayer(aManager, nullptr), |
24 | | LayerMLGPU(aManager), |
25 | | mInvalidateEntireSurface(false), |
26 | | mSurfaceCopyNeeded(false), |
27 | | mView(nullptr) |
28 | 0 | { |
29 | 0 | } |
30 | | |
31 | | ContainerLayerMLGPU::~ContainerLayerMLGPU() |
32 | 0 | { |
33 | 0 | while (mFirstChild) { |
34 | 0 | RemoveChild(mFirstChild); |
35 | 0 | } |
36 | 0 | } |
37 | | |
38 | | bool |
39 | | ContainerLayerMLGPU::OnPrepareToRender(FrameBuilder* aBuilder) |
40 | 0 | { |
41 | 0 | mView = nullptr; |
42 | 0 |
|
43 | 0 | if (!UseIntermediateSurface()) { |
44 | 0 | // Set this so we invalidate the entire cached render target (if any) |
45 | 0 | // if our container uses an intermediate surface again later. |
46 | 0 | mInvalidateEntireSurface = true; |
47 | 0 | return true; |
48 | 0 | } |
49 | 0 | |
50 | 0 | mChildrenChanged = false; |
51 | 0 |
|
52 | 0 | mTargetOffset = GetIntermediateSurfaceRect().TopLeft().ToUnknownPoint(); |
53 | 0 | mTargetSize = GetIntermediateSurfaceRect().Size().ToUnknownSize(); |
54 | 0 |
|
55 | 0 | if (mRenderTarget && mRenderTarget->GetSize() != mTargetSize) { |
56 | 0 | mRenderTarget = nullptr; |
57 | 0 | } |
58 | 0 |
|
59 | 0 | // Note that if a surface copy is needed, we always redraw the |
60 | 0 | // whole surface (on-demand). This is a rare case - the old |
61 | 0 | // Compositor already does this - and it saves us having to |
62 | 0 | // do much more complicated invalidation. |
63 | 0 | bool surfaceCopyNeeded = false; |
64 | 0 | DefaultComputeSupportsComponentAlphaChildren(&surfaceCopyNeeded); |
65 | 0 | if (surfaceCopyNeeded != mSurfaceCopyNeeded || |
66 | 0 | surfaceCopyNeeded) |
67 | 0 | { |
68 | 0 | mInvalidateEntireSurface = true; |
69 | 0 | } |
70 | 0 | mSurfaceCopyNeeded = surfaceCopyNeeded; |
71 | 0 |
|
72 | 0 | gfx::IntRect viewport(gfx::IntPoint(0, 0), mTargetSize); |
73 | 0 | if (!mRenderTarget || |
74 | 0 | !gfxPrefs::AdvancedLayersUseInvalidation() || |
75 | 0 | mInvalidateEntireSurface) |
76 | 0 | { |
77 | 0 | // Fine-grained invalidation is disabled, invalidate everything. |
78 | 0 | mInvalidRect = viewport; |
79 | 0 | } else { |
80 | 0 | // Clamp the invalid rect to the viewport. |
81 | 0 | mInvalidRect -= mTargetOffset; |
82 | 0 | mInvalidRect = mInvalidRect.Intersect(viewport); |
83 | 0 | } |
84 | 0 |
|
85 | 0 | mInvalidateEntireSurface = false; |
86 | 0 | return true; |
87 | 0 | } |
88 | | |
89 | | static IntRect |
90 | | GetTransformedBounds(Layer* aLayer) |
91 | 0 | { |
92 | 0 | IntRect bounds = aLayer->GetLocalVisibleRegion().GetBounds().ToUnknownRect(); |
93 | 0 | if (bounds.IsEmpty()) { |
94 | 0 | return bounds; |
95 | 0 | } |
96 | 0 | |
97 | 0 | const Matrix4x4& transform = aLayer->GetEffectiveTransform(); |
98 | 0 | Rect rect = transform.TransformAndClipBounds(Rect(bounds), Rect::MaxIntRect()); |
99 | 0 | rect.RoundOut(); |
100 | 0 | rect.ToIntRect(&bounds); |
101 | 0 | return bounds; |
102 | 0 | } |
103 | | |
104 | | /* static */ Maybe<IntRect> |
105 | | ContainerLayerMLGPU::FindVisibleBounds(Layer* aLayer, const Maybe<RenderTargetIntRect>& aClip) |
106 | 0 | { |
107 | 0 | AL_LOG(" visiting child %p\n", aLayer); |
108 | 0 | AL_LOG_IF(aClip, " parent clip: %s\n", Stringify(aClip.value()).c_str()); |
109 | 0 |
|
110 | 0 | ContainerLayer* container = aLayer->AsContainerLayer(); |
111 | 0 | if (container) { |
112 | 0 | if (container->UseIntermediateSurface()) { |
113 | 0 | container->AsHostLayer()->AsLayerMLGPU()->AsContainerLayerMLGPU()->ComputeIntermediateSurfaceBounds(); |
114 | 0 | } else { |
115 | 0 | Maybe<IntRect> accumulated = Some(IntRect()); |
116 | 0 |
|
117 | 0 | // Traverse children. |
118 | 0 | for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) { |
119 | 0 | Maybe<RenderTargetIntRect> clip = aClip; |
120 | 0 | if (const Maybe<ParentLayerIntRect>& childClip = child->AsHostLayer()->GetShadowClipRect()) { |
121 | 0 | RenderTargetIntRect rtChildClip = |
122 | 0 | TransformBy(ViewAs<ParentLayerToRenderTargetMatrix4x4>( |
123 | 0 | aLayer->GetEffectiveTransform(), |
124 | 0 | PixelCastJustification::RenderTargetIsParentLayerForRoot), |
125 | 0 | childClip.value()); |
126 | 0 | clip = IntersectMaybeRects(clip, Some(rtChildClip)); |
127 | 0 | AL_LOG(" target clip: %s\n", Stringify(rtChildClip).c_str()); |
128 | 0 | AL_LOG_IF(clip, " full clip: %s\n", Stringify(clip.value()).c_str()); |
129 | 0 | } |
130 | 0 |
|
131 | 0 | Maybe<IntRect> childBounds = FindVisibleBounds(child, clip); |
132 | 0 | if (!childBounds) { |
133 | 0 | return Nothing(); |
134 | 0 | } |
135 | 0 | |
136 | 0 | accumulated = accumulated->SafeUnion(childBounds.value()); |
137 | 0 | if (!accumulated) { |
138 | 0 | return Nothing(); |
139 | 0 | } |
140 | 0 | } |
141 | 0 | return accumulated; |
142 | 0 | } |
143 | 0 | } |
144 | 0 | |
145 | 0 | IntRect bounds = GetTransformedBounds(aLayer); |
146 | 0 | AL_LOG(" layer bounds: %s\n", Stringify(bounds).c_str()); |
147 | 0 |
|
148 | 0 | if (aClip) { |
149 | 0 | bounds = bounds.Intersect(aClip.value().ToUnknownRect()); |
150 | 0 | AL_LOG(" clipped bounds: %s\n", Stringify(bounds).c_str()); |
151 | 0 | } |
152 | 0 | return Some(bounds); |
153 | 0 | } |
154 | | |
155 | | void |
156 | | ContainerLayerMLGPU::ComputeIntermediateSurfaceBounds() |
157 | 0 | { |
158 | 0 | Maybe<IntRect> bounds = Some(IntRect()); |
159 | 0 | for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) { |
160 | 0 | Maybe<RenderTargetIntRect> clip = |
161 | 0 | ViewAs<RenderTargetPixel>(child->AsHostLayer()->GetShadowClipRect(), |
162 | 0 | PixelCastJustification::RenderTargetIsParentLayerForRoot); |
163 | 0 | Maybe<IntRect> childBounds = FindVisibleBounds(child, clip); |
164 | 0 | if (!childBounds) { |
165 | 0 | return; |
166 | 0 | } |
167 | 0 | |
168 | 0 | bounds = bounds->SafeUnion(childBounds.value()); |
169 | 0 | if (!bounds) { |
170 | 0 | return; |
171 | 0 | } |
172 | 0 | } |
173 | 0 |
|
174 | 0 | SetShadowVisibleRegion(LayerIntRect::FromUnknownRect(bounds.value())); |
175 | 0 | } |
176 | | |
177 | | void |
178 | | ContainerLayerMLGPU::OnLayerManagerChange(LayerManagerMLGPU* aManager) |
179 | 0 | { |
180 | 0 | ClearCachedResources(); |
181 | 0 | } |
182 | | |
183 | | RefPtr<MLGRenderTarget> |
184 | | ContainerLayerMLGPU::UpdateRenderTarget(MLGDevice* aDevice, MLGRenderTargetFlags aFlags) |
185 | 0 | { |
186 | 0 | if (mRenderTarget) { |
187 | 0 | return mRenderTarget; |
188 | 0 | } |
189 | 0 | |
190 | 0 | mRenderTarget = aDevice->CreateRenderTarget(mTargetSize, aFlags); |
191 | 0 | if (!mRenderTarget) { |
192 | 0 | gfxWarning() << "Failed to create an intermediate render target for ContainerLayer"; |
193 | 0 | return nullptr; |
194 | 0 | } |
195 | 0 |
|
196 | 0 | return mRenderTarget; |
197 | 0 | } |
198 | | |
199 | | void |
200 | | ContainerLayerMLGPU::SetInvalidCompositeRect(const gfx::IntRect* aRect) |
201 | 0 | { |
202 | 0 | // For simplicity we only track the bounds of the invalid area, since regions |
203 | 0 | // are expensive. |
204 | 0 | // |
205 | 0 | // Note we add the bounds to the invalid rect from the last frame, since we |
206 | 0 | // only clear the area that we actually paint. If this overflows we use the |
207 | 0 | // last render target size, since if that changes we'll invalidate everything |
208 | 0 | // anyway. |
209 | 0 | if (aRect) { |
210 | 0 | if (Maybe<gfx::IntRect> result = mInvalidRect.SafeUnion(*aRect)) { |
211 | 0 | mInvalidRect = result.value(); |
212 | 0 | } else { |
213 | 0 | mInvalidateEntireSurface = true; |
214 | 0 | } |
215 | 0 | } else { |
216 | 0 | mInvalidateEntireSurface = true; |
217 | 0 | } |
218 | 0 | } |
219 | | |
220 | | void |
221 | | ContainerLayerMLGPU::ClearCachedResources() |
222 | 0 | { |
223 | 0 | mRenderTarget = nullptr; |
224 | 0 | } |
225 | | |
226 | | bool |
227 | | ContainerLayerMLGPU::IsContentOpaque() |
228 | 0 | { |
229 | 0 | if (GetMixBlendMode() != gfx::CompositionOp::OP_OVER) { |
230 | 0 | // We need to read from what's underneath us, so we consider our content to |
231 | 0 | // be not opaque. |
232 | 0 | return false; |
233 | 0 | } |
234 | 0 | return LayerMLGPU::IsContentOpaque(); |
235 | 0 | } |
236 | | |
237 | | const LayerIntRegion& |
238 | | ContainerLayerMLGPU::GetShadowVisibleRegion() |
239 | 0 | { |
240 | 0 | if (!UseIntermediateSurface()) { |
241 | 0 | RecomputeShadowVisibleRegionFromChildren(); |
242 | 0 | } |
243 | 0 |
|
244 | 0 | return mShadowVisibleRegion; |
245 | 0 | } |
246 | | |
247 | | const LayerIntRegion& |
248 | | RefLayerMLGPU::GetShadowVisibleRegion() |
249 | 0 | { |
250 | 0 | if (!UseIntermediateSurface()) { |
251 | 0 | RecomputeShadowVisibleRegionFromChildren(); |
252 | 0 | } |
253 | 0 |
|
254 | 0 | return mShadowVisibleRegion; |
255 | 0 | } |
256 | | |
257 | | } // namespace layers |
258 | | } // namespace mozilla |