Line data Source code
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 "ContainerLayerComposite.h"
8 : #include <algorithm> // for min
9 : #include "FrameMetrics.h" // for FrameMetrics
10 : #include "Units.h" // for LayerRect, LayerPixel, etc
11 : #include "CompositableHost.h" // for CompositableHost
12 : #include "gfxEnv.h" // for gfxEnv
13 : #include "gfxPrefs.h" // for gfxPrefs
14 : #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
15 : #include "mozilla/RefPtr.h" // for RefPtr
16 : #include "mozilla/UniquePtr.h" // for UniquePtr
17 : #include "mozilla/gfx/BaseRect.h" // for BaseRect
18 : #include "mozilla/gfx/Matrix.h" // for Matrix4x4
19 : #include "mozilla/gfx/Point.h" // for Point, IntPoint
20 : #include "mozilla/gfx/Rect.h" // for IntRect, Rect
21 : #include "mozilla/layers/APZSampler.h" // for APZSampler
22 : #include "mozilla/layers/Compositor.h" // for Compositor, etc
23 : #include "mozilla/layers/CompositorTypes.h" // for DiagnosticFlags::CONTAINER
24 : #include "mozilla/layers/Effects.h" // for Effect, EffectChain, etc
25 : #include "mozilla/layers/TextureHost.h" // for CompositingRenderTarget
26 : #include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform
27 : #include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
28 : #include "mozilla/mozalloc.h" // for operator delete, etc
29 : #include "mozilla/RefPtr.h" // for nsRefPtr
30 : #include "nsDebug.h" // for NS_ASSERTION
31 : #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
32 : #include "nsISupportsUtils.h" // for NS_ADDREF, NS_RELEASE
33 : #include "nsRegion.h" // for nsIntRegion
34 : #include "nsTArray.h" // for AutoTArray
35 : #include <stack>
36 : #include "TextRenderer.h" // for TextRenderer
37 : #include <vector>
38 : #include "GeckoProfiler.h" // for GeckoProfiler
39 :
40 : #ifdef MOZ_GECKO_PROFILER
41 : #include "ProfilerMarkerPayload.h" // for LayerTranslationMarkerPayload
42 : #endif
43 :
44 : #define CULLING_LOG(...)
45 : // #define CULLING_LOG(...) printf_stderr("CULLING: " __VA_ARGS__)
46 :
47 : #define DUMP(...) do { if (gfxEnv::DumpDebug()) { printf_stderr(__VA_ARGS__); } } while(0)
48 : #define XYWH(k) (k).X(), (k).Y(), (k).Width(), (k).Height()
49 : #define XY(k) (k).X(), (k).Y()
50 : #define WH(k) (k).Width(), (k).Height()
51 :
52 : namespace mozilla {
53 : namespace layers {
54 :
55 : using namespace gfx;
56 :
57 : static void
58 0 : DrawLayerInfo(const RenderTargetIntRect& aClipRect,
59 : LayerManagerComposite* aManager,
60 : Layer* aLayer)
61 : {
62 0 : if (aLayer->GetType() == Layer::LayerType::TYPE_CONTAINER) {
63 : // XXX - should figure out a way to render this, but for now this
64 : // is hard to do, since it will often get superimposed over the first
65 : // child of the layer, which is bad.
66 0 : return;
67 : }
68 :
69 0 : std::stringstream ss;
70 0 : aLayer->PrintInfo(ss, "");
71 :
72 0 : LayerIntRegion visibleRegion = aLayer->GetVisibleRegion();
73 :
74 0 : uint32_t maxWidth = std::min<uint32_t>(visibleRegion.GetBounds().Width(), 500);
75 :
76 0 : IntPoint topLeft = visibleRegion.ToUnknownRegion().GetBounds().TopLeft();
77 0 : aManager->GetTextRenderer()->RenderText(
78 : aManager->GetCompositor(),
79 0 : ss.str().c_str(),
80 : topLeft,
81 : aLayer->GetEffectiveTransform(), 16,
82 0 : maxWidth);
83 : }
84 :
85 : static void
86 0 : PrintUniformityInfo(Layer* aLayer)
87 : {
88 : #if defined(MOZ_GECKO_PROFILER)
89 0 : if (!profiler_is_active()) {
90 0 : return;
91 : }
92 :
93 : // Don't want to print a log for smaller layers
94 0 : if (aLayer->GetLocalVisibleRegion().GetBounds().Width() < 300 ||
95 0 : aLayer->GetLocalVisibleRegion().GetBounds().Height() < 300) {
96 : return;
97 : }
98 :
99 0 : Matrix4x4 transform = aLayer->AsHostLayer()->GetShadowBaseTransform();
100 0 : if (!transform.Is2D()) {
101 : return;
102 : }
103 :
104 0 : Point translation = transform.As2D().GetTranslation();
105 0 : profiler_add_marker(
106 : "LayerTranslation",
107 0 : MakeUnique<LayerTranslationMarkerPayload>(aLayer, translation,
108 0 : TimeStamp::Now()));
109 : #endif
110 : }
111 :
112 : static Maybe<gfx::Polygon>
113 0 : SelectLayerGeometry(const Maybe<gfx::Polygon>& aParentGeometry,
114 : const Maybe<gfx::Polygon>& aChildGeometry)
115 : {
116 : // Both the parent and the child layer were split.
117 0 : if (aParentGeometry && aChildGeometry) {
118 0 : return Some(aParentGeometry->ClipPolygon(*aChildGeometry));
119 : }
120 :
121 : // The parent layer was split.
122 0 : if (aParentGeometry) {
123 0 : return aParentGeometry;
124 : }
125 :
126 : // The child layer was split.
127 0 : if(aChildGeometry) {
128 0 : return aChildGeometry;
129 : }
130 :
131 : // No split.
132 : return Nothing();
133 : }
134 :
135 : void
136 0 : TransformLayerGeometry(Layer* aLayer, Maybe<gfx::Polygon>& aGeometry)
137 : {
138 0 : Layer* parent = aLayer;
139 0 : gfx::Matrix4x4 transform;
140 :
141 : // Collect all parent transforms.
142 0 : while (parent != nullptr && !parent->Is3DContextLeaf()) {
143 0 : transform = transform * parent->GetLocalTransform();
144 0 : parent = parent->GetParent();
145 : }
146 :
147 : // Transform the geometry to the parent 3D context leaf coordinate space.
148 0 : transform = transform.ProjectTo2D();
149 :
150 0 : if (!transform.IsSingular()) {
151 0 : aGeometry->TransformToScreenSpace(transform.Inverse());
152 : } else {
153 : // Discard the geometry since the result might not be correct.
154 0 : aGeometry.reset();
155 : }
156 0 : }
157 :
158 :
159 : template<class ContainerT>
160 0 : static gfx::IntRect ContainerVisibleRect(ContainerT* aContainer)
161 : {
162 0 : gfx::IntRect surfaceRect = aContainer->GetLocalVisibleRegion().ToUnknownRegion().GetBounds();
163 0 : return surfaceRect;
164 : }
165 :
166 :
167 : /* all of the per-layer prepared data we need to maintain */
168 0 : struct PreparedLayer
169 : {
170 0 : PreparedLayer(Layer *aLayer,
171 : RenderTargetIntRect aClipRect,
172 : Maybe<gfx::Polygon>&& aGeometry)
173 0 : : mLayer(aLayer), mClipRect(aClipRect), mGeometry(std::move(aGeometry)) {}
174 :
175 : RefPtr<Layer> mLayer;
176 : RenderTargetIntRect mClipRect;
177 : Maybe<Polygon> mGeometry;
178 : };
179 :
180 : /* all of the prepared data that we need in RenderLayer() */
181 0 : struct PreparedData
182 : {
183 : RefPtr<CompositingRenderTarget> mTmpTarget;
184 : AutoTArray<PreparedLayer, 12> mLayers;
185 : bool mNeedsSurfaceCopy;
186 : };
187 :
188 : // ContainerPrepare is shared between RefLayer and ContainerLayer
189 : template<class ContainerT> void
190 0 : ContainerPrepare(ContainerT* aContainer,
191 : LayerManagerComposite* aManager,
192 : const RenderTargetIntRect& aClipRect)
193 : {
194 : // We can end up calling prepare multiple times if we duplicated
195 : // layers due to preserve-3d plane splitting. The results
196 : // should be identical, so we only need to do it once.
197 0 : if (aContainer->mPrepared) {
198 0 : return;
199 : }
200 0 : aContainer->mPrepared = MakeUnique<PreparedData>();
201 0 : aContainer->mPrepared->mNeedsSurfaceCopy = false;
202 :
203 : const ContainerLayerComposite::SortMode sortMode =
204 0 : aManager->GetCompositor()->SupportsLayerGeometry()
205 : ? ContainerLayerComposite::SortMode::WITH_GEOMETRY
206 0 : : ContainerLayerComposite::SortMode::WITHOUT_GEOMETRY;
207 :
208 : nsTArray<LayerPolygon> polygons =
209 0 : aContainer->SortChildrenBy3DZOrder(sortMode);
210 :
211 0 : for (LayerPolygon& layer : polygons) {
212 : LayerComposite* layerToRender =
213 0 : static_cast<LayerComposite*>(layer.layer->ImplData());
214 :
215 : RenderTargetIntRect clipRect =
216 0 : layerToRender->GetLayer()->CalculateScissorRect(aClipRect);
217 :
218 0 : if (layerToRender->GetLayer()->IsBackfaceHidden()) {
219 0 : continue;
220 : }
221 :
222 : // We don't want to skip container layers because otherwise their mPrepared
223 : // may be null which is not allowed.
224 0 : if (!layerToRender->GetLayer()->AsContainerLayer()) {
225 0 : if (!layerToRender->GetLayer()->IsVisible()) {
226 : CULLING_LOG("Sublayer %p has no effective visible region\n", layerToRender->GetLayer());
227 : continue;
228 : }
229 :
230 0 : if (clipRect.IsEmpty()) {
231 : CULLING_LOG("Sublayer %p has an empty world clip rect\n", layerToRender->GetLayer());
232 : continue;
233 : }
234 : }
235 :
236 : CULLING_LOG("Preparing sublayer %p\n", layerToRender->GetLayer());
237 :
238 0 : layerToRender->Prepare(clipRect);
239 0 : aContainer->mPrepared->mLayers.AppendElement(PreparedLayer(layerToRender->GetLayer(),
240 : clipRect,
241 0 : std::move(layer.geometry)));
242 : }
243 :
244 : CULLING_LOG("Preparing container layer %p\n", aContainer->GetLayer());
245 :
246 : /**
247 : * Setup our temporary surface for rendering the contents of this container.
248 : */
249 :
250 0 : gfx::IntRect surfaceRect = ContainerVisibleRect(aContainer);
251 0 : if (surfaceRect.IsEmpty()) {
252 : return;
253 : }
254 :
255 : bool surfaceCopyNeeded;
256 : // DefaultComputeSupportsComponentAlphaChildren can mutate aContainer so call it unconditionally
257 0 : aContainer->DefaultComputeSupportsComponentAlphaChildren(&surfaceCopyNeeded);
258 0 : if (aContainer->UseIntermediateSurface()) {
259 0 : if (!surfaceCopyNeeded) {
260 0 : RefPtr<CompositingRenderTarget> surface = nullptr;
261 :
262 0 : RefPtr<CompositingRenderTarget>& lastSurf = aContainer->mLastIntermediateSurface;
263 0 : if (lastSurf && !aContainer->mChildrenChanged && lastSurf->GetRect().IsEqualEdges(surfaceRect)) {
264 0 : surface = lastSurf;
265 : }
266 :
267 0 : if (!surface) {
268 : // If we don't need a copy we can render to the intermediate now to avoid
269 : // unecessary render target switching. This brings a big perf boost on mobile gpus.
270 0 : surface = CreateOrRecycleTarget(aContainer, aManager);
271 :
272 0 : MOZ_PERFORMANCE_WARNING("gfx", "[%p] Container layer requires intermediate surface rendering\n", aContainer);
273 0 : RenderIntermediate(aContainer, aManager, aClipRect.ToUnknownRect(), surface);
274 0 : aContainer->SetChildrenChanged(false);
275 : }
276 :
277 0 : aContainer->mPrepared->mTmpTarget = surface;
278 : } else {
279 0 : MOZ_PERFORMANCE_WARNING("gfx", "[%p] Container layer requires intermediate surface copy\n", aContainer);
280 0 : aContainer->mPrepared->mNeedsSurfaceCopy = true;
281 0 : aContainer->mLastIntermediateSurface = nullptr;
282 : }
283 : } else {
284 0 : aContainer->mLastIntermediateSurface = nullptr;
285 : }
286 : }
287 :
288 : template<class ContainerT> void
289 0 : RenderMinimap(ContainerT* aContainer,
290 : const RefPtr<APZSampler>& aSampler,
291 : LayerManagerComposite* aManager,
292 : const RenderTargetIntRect& aClipRect, Layer* aLayer)
293 : {
294 0 : Compositor* compositor = aManager->GetCompositor();
295 0 : MOZ_ASSERT(aSampler);
296 :
297 0 : if (aLayer->GetScrollMetadataCount() < 1) {
298 0 : return;
299 : }
300 :
301 0 : LayerMetricsWrapper wrapper(aLayer, 0);
302 0 : if (!wrapper.GetApzc()) {
303 : return;
304 : }
305 0 : const FrameMetrics& fm = wrapper.Metrics();
306 0 : MOZ_ASSERT(fm.IsScrollable());
307 :
308 0 : ParentLayerPoint scrollOffset = aSampler->GetCurrentAsyncScrollOffset(wrapper);
309 :
310 : // Options
311 0 : const int verticalPadding = 10;
312 0 : const int horizontalPadding = 5;
313 0 : gfx::Color backgroundColor(0.3f, 0.3f, 0.3f, 0.3f);
314 0 : gfx::Color tileActiveColor(1, 1, 1, 0.4f);
315 0 : gfx::Color tileBorderColor(0, 0, 0, 0.1f);
316 0 : gfx::Color pageBorderColor(0, 0, 0);
317 0 : gfx::Color criticalDisplayPortColor(1.f, 1.f, 0);
318 0 : gfx::Color displayPortColor(0, 1.f, 0);
319 0 : gfx::Color layoutPortColor(1.f, 0, 0);
320 0 : gfx::Color visualPortColor(0, 0, 1.f, 0.3f);
321 :
322 : // Rects
323 0 : ParentLayerRect compositionBounds = fm.GetCompositionBounds();
324 0 : LayerRect scrollRect = fm.GetScrollableRect() * fm.LayersPixelsPerCSSPixel();
325 0 : LayerRect visualRect = ParentLayerRect(scrollOffset, compositionBounds.Size()) / LayerToParentLayerScale(1);
326 0 : LayerRect dp = (fm.GetDisplayPort() + fm.GetScrollOffset()) * fm.LayersPixelsPerCSSPixel();
327 0 : Maybe<LayerRect> layoutRect;
328 0 : Maybe<LayerRect> cdp;
329 0 : if (fm.IsRootContent()) {
330 0 : CSSRect viewport = aSampler->GetCurrentAsyncLayoutViewport(wrapper);
331 0 : layoutRect = Some(viewport * fm.LayersPixelsPerCSSPixel());
332 : }
333 0 : if (!fm.GetCriticalDisplayPort().IsEmpty()) {
334 0 : cdp = Some((fm.GetCriticalDisplayPort() + fm.GetScrollOffset()) * fm.LayersPixelsPerCSSPixel());
335 : }
336 :
337 : // Don't render trivial minimap. They can show up from textboxes and other tiny frames.
338 0 : if (visualRect.Width() < 64 && visualRect.Height() < 64) {
339 0 : return;
340 : }
341 :
342 : // Compute a scale with an appropriate aspect ratio
343 : // We allocate up to 100px of width and the height of this layer.
344 : float scaleFactor;
345 : float scaleFactorX;
346 : float scaleFactorY;
347 0 : Rect dest = Rect(aClipRect.ToUnknownRect());
348 0 : if (aLayer->GetLocalClipRect()) {
349 0 : dest = Rect(aLayer->GetLocalClipRect().value().ToUnknownRect());
350 : } else {
351 0 : dest = aContainer->GetEffectiveTransform().Inverse().TransformBounds(dest);
352 : }
353 0 : dest = dest.Intersect(compositionBounds.ToUnknownRect());
354 0 : scaleFactorX = std::min(100.f, dest.Width() - (2 * horizontalPadding)) / scrollRect.Width();
355 0 : scaleFactorY = (dest.Height() - (2 * verticalPadding)) / scrollRect.Height();
356 0 : scaleFactor = std::min(scaleFactorX, scaleFactorY);
357 0 : if (scaleFactor <= 0) {
358 : return;
359 : }
360 :
361 0 : Matrix4x4 transform = Matrix4x4::Scaling(scaleFactor, scaleFactor, 1);
362 0 : transform.PostTranslate(horizontalPadding + dest.X(), verticalPadding + dest.Y(), 0);
363 :
364 0 : Rect transformedScrollRect = transform.TransformBounds(scrollRect.ToUnknownRect());
365 :
366 0 : IntRect clipRect = RoundedOut(aContainer->GetEffectiveTransform().TransformBounds(transformedScrollRect));
367 :
368 : // Render the scrollable area.
369 0 : compositor->FillRect(transformedScrollRect, backgroundColor, clipRect, aContainer->GetEffectiveTransform());
370 0 : compositor->SlowDrawRect(transformedScrollRect, pageBorderColor, clipRect, aContainer->GetEffectiveTransform());
371 :
372 : // Render the displayport.
373 0 : Rect r = transform.TransformBounds(dp.ToUnknownRect());
374 0 : compositor->FillRect(r, tileActiveColor, clipRect, aContainer->GetEffectiveTransform());
375 0 : compositor->SlowDrawRect(r, displayPortColor, clipRect, aContainer->GetEffectiveTransform());
376 :
377 : // Render the critical displayport if there is one
378 0 : if (cdp) {
379 0 : r = transform.TransformBounds(cdp->ToUnknownRect());
380 0 : compositor->SlowDrawRect(r, criticalDisplayPortColor, clipRect, aContainer->GetEffectiveTransform());
381 : }
382 :
383 : // Render the layout viewport if it exists (which is only in the root
384 : // content APZC).
385 0 : if (layoutRect) {
386 0 : r = transform.TransformBounds(layoutRect->ToUnknownRect());
387 0 : compositor->SlowDrawRect(r, layoutPortColor, clipRect, aContainer->GetEffectiveTransform());
388 : }
389 :
390 : // Render the visual viewport.
391 0 : r = transform.TransformBounds(visualRect.ToUnknownRect());
392 0 : compositor->SlowDrawRect(r, visualPortColor, clipRect, aContainer->GetEffectiveTransform(), 2);
393 : }
394 :
395 : template<class ContainerT> void
396 0 : RenderLayers(ContainerT* aContainer, LayerManagerComposite* aManager,
397 : const RenderTargetIntRect& aClipRect,
398 : const Maybe<gfx::Polygon>& aGeometry)
399 : {
400 0 : Compositor* compositor = aManager->GetCompositor();
401 :
402 0 : RefPtr<APZSampler> sampler;
403 0 : if (CompositorBridgeParent* cbp = compositor->GetCompositorBridgeParent()) {
404 0 : sampler = cbp->GetAPZSampler();
405 : }
406 :
407 0 : for (size_t i = 0u; i < aContainer->mPrepared->mLayers.Length(); i++) {
408 0 : PreparedLayer& preparedData = aContainer->mPrepared->mLayers[i];
409 :
410 0 : const gfx::IntRect clipRect = preparedData.mClipRect.ToUnknownRect();
411 0 : LayerComposite* layerToRender = static_cast<LayerComposite*>(preparedData.mLayer->ImplData());
412 0 : const Maybe<gfx::Polygon>& childGeometry = preparedData.mGeometry;
413 :
414 0 : Layer* layer = layerToRender->GetLayer();
415 :
416 0 : if (layerToRender->HasStaleCompositor()) {
417 0 : continue;
418 : }
419 :
420 0 : if (gfxPrefs::LayersDrawFPS()) {
421 0 : for (const auto& metadata : layer->GetAllScrollMetadata()) {
422 0 : if (metadata.IsApzForceDisabled()) {
423 0 : aManager->DisabledApzWarning();
424 : break;
425 : }
426 : }
427 : }
428 :
429 0 : if (layerToRender->HasLayerBeenComposited()) {
430 : // Composer2D will compose this layer so skip GPU composition
431 : // this time. The flag will be reset for the next composition phase
432 : // at the beginning of LayerManagerComposite::Rener().
433 0 : gfx::IntRect clearRect = layerToRender->GetClearRect();
434 0 : if (!clearRect.IsEmpty()) {
435 : // Clear layer's visible rect on FrameBuffer with transparent pixels
436 0 : gfx::Rect fbRect(clearRect.X(), clearRect.Y(), clearRect.Width(), clearRect.Height());
437 0 : compositor->ClearRect(fbRect);
438 0 : layerToRender->SetClearRect(gfx::IntRect(0, 0, 0, 0));
439 : }
440 : } else {
441 : // Since we force an intermediate surface for nested 3D contexts,
442 : // aGeometry and childGeometry are both in the same coordinate space.
443 : Maybe<gfx::Polygon> geometry =
444 0 : SelectLayerGeometry(aGeometry, childGeometry);
445 :
446 : // If we are dealing with a nested 3D context, we might need to transform
447 : // the geometry back to the coordinate space of the current layer before
448 : // rendering the layer.
449 0 : ContainerLayer* container = layer->AsContainerLayer();
450 0 : const bool isLeafLayer = !container || container->UseIntermediateSurface();
451 :
452 0 : if (geometry && isLeafLayer) {
453 0 : TransformLayerGeometry(layer, geometry);
454 : }
455 :
456 0 : layerToRender->RenderLayer(clipRect, geometry);
457 : }
458 :
459 0 : if (gfxPrefs::UniformityInfo()) {
460 0 : PrintUniformityInfo(layer);
461 : }
462 :
463 0 : if (gfxPrefs::DrawLayerInfo()) {
464 0 : DrawLayerInfo(preparedData.mClipRect, aManager, layer);
465 : }
466 :
467 : // Draw a border around scrollable layers.
468 : // A layer can be scrolled by multiple scroll frames. Draw a border
469 : // for each.
470 : // Within the list of scroll frames for a layer, the layer border for a
471 : // scroll frame lower down is affected by the async transforms on scroll
472 : // frames higher up, so loop from the top down, and accumulate an async
473 : // transform as we go along.
474 0 : Matrix4x4 asyncTransform;
475 0 : if (sampler) {
476 0 : for (uint32_t i = layer->GetScrollMetadataCount(); i > 0; --i) {
477 0 : LayerMetricsWrapper wrapper(layer, i - 1);
478 0 : if (wrapper.GetApzc()) {
479 0 : MOZ_ASSERT(wrapper.Metrics().IsScrollable());
480 : // Since the composition bounds are in the parent layer's coordinates,
481 : // use the parent's effective transform rather than the layer's own.
482 0 : ParentLayerRect compositionBounds = wrapper.Metrics().GetCompositionBounds();
483 0 : aManager->GetCompositor()->DrawDiagnostics(DiagnosticFlags::CONTAINER,
484 0 : compositionBounds.ToUnknownRect(),
485 0 : aClipRect.ToUnknownRect(),
486 0 : asyncTransform * aContainer->GetEffectiveTransform());
487 0 : asyncTransform =
488 : sampler->GetCurrentAsyncTransformWithOverscroll(wrapper).ToUnknownMatrix()
489 : * asyncTransform;
490 : }
491 : }
492 :
493 0 : if (gfxPrefs::APZMinimap()) {
494 0 : RenderMinimap(aContainer, sampler, aManager, aClipRect, layer);
495 : }
496 : }
497 :
498 : // invariant: our GL context should be current here, I don't think we can
499 : // assert it though
500 : }
501 0 : }
502 :
503 : template<class ContainerT> RefPtr<CompositingRenderTarget>
504 0 : CreateOrRecycleTarget(ContainerT* aContainer,
505 : LayerManagerComposite* aManager)
506 : {
507 0 : Compositor* compositor = aManager->GetCompositor();
508 0 : SurfaceInitMode mode = INIT_MODE_CLEAR;
509 0 : gfx::IntRect surfaceRect = ContainerVisibleRect(aContainer);
510 0 : if (aContainer->GetLocalVisibleRegion().GetNumRects() == 1 &&
511 0 : (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE))
512 : {
513 0 : mode = INIT_MODE_NONE;
514 : }
515 :
516 0 : RefPtr<CompositingRenderTarget>& lastSurf = aContainer->mLastIntermediateSurface;
517 0 : if (lastSurf && lastSurf->GetRect().IsEqualEdges(surfaceRect)) {
518 0 : if (mode == INIT_MODE_CLEAR) {
519 0 : lastSurf->ClearOnBind();
520 : }
521 :
522 0 : return lastSurf;
523 : } else {
524 0 : lastSurf = compositor->CreateRenderTarget(surfaceRect, mode);
525 :
526 0 : return lastSurf;
527 : }
528 : }
529 :
530 : template<class ContainerT> RefPtr<CompositingRenderTarget>
531 0 : CreateTemporaryTargetAndCopyFromBackground(ContainerT* aContainer,
532 : LayerManagerComposite* aManager)
533 : {
534 0 : Compositor* compositor = aManager->GetCompositor();
535 0 : gfx::IntRect visibleRect = aContainer->GetLocalVisibleRegion().ToUnknownRegion().GetBounds();
536 0 : RefPtr<CompositingRenderTarget> previousTarget = compositor->GetCurrentRenderTarget();
537 : gfx::IntRect surfaceRect = gfx::IntRect(visibleRect.X(), visibleRect.Y(),
538 0 : visibleRect.Width(), visibleRect.Height());
539 :
540 0 : gfx::IntPoint sourcePoint = gfx::IntPoint(visibleRect.X(), visibleRect.Y());
541 :
542 0 : gfx::Matrix4x4 transform = aContainer->GetEffectiveTransform();
543 0 : DebugOnly<gfx::Matrix> transform2d;
544 0 : MOZ_ASSERT(transform.Is2D(&transform2d) && !gfx::ThebesMatrix(transform2d).HasNonIntegerTranslation());
545 0 : sourcePoint += gfx::IntPoint::Truncate(transform._41, transform._42);
546 :
547 0 : sourcePoint -= compositor->GetCurrentRenderTarget()->GetOrigin();
548 :
549 0 : return compositor->CreateRenderTargetFromSource(surfaceRect, previousTarget, sourcePoint);
550 : }
551 :
552 : template<class ContainerT> void
553 0 : RenderIntermediate(ContainerT* aContainer,
554 : LayerManagerComposite* aManager,
555 : const gfx::IntRect& aClipRect,
556 : RefPtr<CompositingRenderTarget> surface)
557 : {
558 0 : Compositor* compositor = aManager->GetCompositor();
559 0 : RefPtr<CompositingRenderTarget> previousTarget = compositor->GetCurrentRenderTarget();
560 :
561 0 : if (!surface) {
562 0 : return;
563 : }
564 :
565 0 : compositor->SetRenderTarget(surface);
566 : // pre-render all of the layers into our temporary
567 0 : RenderLayers(aContainer, aManager,
568 0 : RenderTargetIntRect::FromUnknownRect(aClipRect),
569 : Nothing());
570 :
571 : // Unbind the current surface and rebind the previous one.
572 0 : compositor->SetRenderTarget(previousTarget);
573 : }
574 :
575 : template<class ContainerT> void
576 0 : ContainerRender(ContainerT* aContainer,
577 : LayerManagerComposite* aManager,
578 : const gfx::IntRect& aClipRect,
579 : const Maybe<gfx::Polygon>& aGeometry)
580 : {
581 0 : MOZ_ASSERT(aContainer->mPrepared);
582 :
583 0 : if (aContainer->UseIntermediateSurface()) {
584 0 : RefPtr<CompositingRenderTarget> surface;
585 :
586 0 : if (aContainer->mPrepared->mNeedsSurfaceCopy) {
587 : // we needed to copy the background so we waited until now to render the intermediate
588 0 : surface = CreateTemporaryTargetAndCopyFromBackground(aContainer, aManager);
589 0 : RenderIntermediate(aContainer, aManager,
590 : aClipRect, surface);
591 : } else {
592 0 : surface = aContainer->mPrepared->mTmpTarget;
593 : }
594 :
595 0 : if (!surface) {
596 0 : return;
597 : }
598 :
599 0 : gfx::Rect visibleRect(aContainer->GetLocalVisibleRegion().ToUnknownRegion().GetBounds());
600 :
601 0 : RefPtr<Compositor> compositor = aManager->GetCompositor();
602 : #ifdef MOZ_DUMP_PAINTING
603 0 : if (gfxEnv::DumpCompositorTextures()) {
604 0 : RefPtr<gfx::DataSourceSurface> surf = surface->Dump(compositor);
605 0 : if (surf) {
606 0 : WriteSnapshotToDumpFile(aContainer, surf);
607 : }
608 : }
609 : #endif
610 :
611 0 : RefPtr<ContainerT> container = aContainer;
612 0 : RenderWithAllMasks(aContainer, compositor, aClipRect,
613 0 : [&, surface, compositor, container](EffectChain& effectChain, const IntRect& clipRect) {
614 0 : effectChain.mPrimaryEffect = new EffectRenderTarget(surface);
615 :
616 0 : compositor->DrawGeometry(visibleRect, clipRect, effectChain,
617 0 : container->GetEffectiveOpacity(),
618 0 : container->GetEffectiveTransform(), aGeometry);
619 0 : });
620 :
621 : } else {
622 0 : RenderLayers(aContainer, aManager,
623 0 : RenderTargetIntRect::FromUnknownRect(aClipRect),
624 : aGeometry);
625 : }
626 :
627 : // If it is a scrollable container layer with no child layers, and one of the APZCs
628 : // attached to it has a nonempty async transform, then that transform is not applied
629 : // to any visible content. Display a warning box (conditioned on the FPS display being
630 : // enabled).
631 0 : if (gfxPrefs::LayersDrawFPS() && aContainer->IsScrollableWithoutContent()) {
632 0 : RefPtr<APZSampler> sampler = aManager->GetCompositor()->GetCompositorBridgeParent()->GetAPZSampler();
633 : // Since aContainer doesn't have any children we can just iterate from the top metrics
634 : // on it down to the bottom using GetFirstChild and not worry about walking onto another
635 : // underlying layer.
636 0 : for (LayerMetricsWrapper i(aContainer); i; i = i.GetFirstChild()) {
637 0 : if (sampler->HasUnusedAsyncTransform(i)) {
638 0 : aManager->UnusedApzTransformWarning();
639 : break;
640 : }
641 : }
642 : }
643 : }
644 :
645 2 : ContainerLayerComposite::ContainerLayerComposite(LayerManagerComposite *aManager)
646 : : ContainerLayer(aManager, nullptr)
647 6 : , LayerComposite(aManager)
648 : {
649 2 : MOZ_COUNT_CTOR(ContainerLayerComposite);
650 2 : mImplData = static_cast<LayerComposite*>(this);
651 2 : }
652 :
653 0 : ContainerLayerComposite::~ContainerLayerComposite()
654 : {
655 0 : MOZ_COUNT_DTOR(ContainerLayerComposite);
656 :
657 : // We don't Destroy() on destruction here because this destructor
658 : // can be called after remote content has crashed, and it may not be
659 : // safe to free the IPC resources of our children. Those resources
660 : // are automatically cleaned up by IPDL-generated code.
661 : //
662 : // In the common case of normal shutdown, either
663 : // LayerManagerComposite::Destroy(), a parent
664 : // *ContainerLayerComposite::Destroy(), or Disconnect() will trigger
665 : // cleanup of our resources.
666 0 : RemoveAllChildren();
667 0 : }
668 :
669 : void
670 0 : ContainerLayerComposite::Destroy()
671 : {
672 0 : if (!mDestroyed) {
673 0 : while (mFirstChild) {
674 0 : GetFirstChildComposite()->Destroy();
675 0 : RemoveChild(mFirstChild);
676 : }
677 0 : mDestroyed = true;
678 : }
679 0 : }
680 :
681 : LayerComposite*
682 0 : ContainerLayerComposite::GetFirstChildComposite()
683 : {
684 0 : if (!mFirstChild) {
685 : return nullptr;
686 : }
687 0 : return static_cast<LayerComposite*>(mFirstChild->AsHostLayer());
688 : }
689 :
690 : void
691 0 : ContainerLayerComposite::Cleanup()
692 : {
693 0 : mPrepared = nullptr;
694 :
695 0 : for (Layer* l = GetFirstChild(); l; l = l->GetNextSibling()) {
696 0 : static_cast<LayerComposite*>(l->AsHostLayer())->Cleanup();
697 : }
698 0 : }
699 :
700 : void
701 0 : ContainerLayerComposite::RenderLayer(const gfx::IntRect& aClipRect,
702 : const Maybe<gfx::Polygon>& aGeometry)
703 : {
704 0 : ContainerRender(this, mCompositeManager, aClipRect, aGeometry);
705 0 : }
706 :
707 : void
708 0 : ContainerLayerComposite::Prepare(const RenderTargetIntRect& aClipRect)
709 : {
710 0 : ContainerPrepare(this, mCompositeManager, aClipRect);
711 0 : }
712 :
713 : void
714 0 : ContainerLayerComposite::CleanupResources()
715 : {
716 0 : mLastIntermediateSurface = nullptr;
717 0 : mPrepared = nullptr;
718 :
719 0 : for (Layer* l = GetFirstChild(); l; l = l->GetNextSibling()) {
720 0 : static_cast<LayerComposite*>(l->AsHostLayer())->CleanupResources();
721 : }
722 0 : }
723 :
724 : const LayerIntRegion&
725 7 : ContainerLayerComposite::GetShadowVisibleRegion()
726 : {
727 0 : if (!UseIntermediateSurface()) {
728 7 : RecomputeShadowVisibleRegionFromChildren();
729 : }
730 :
731 7 : return mShadowVisibleRegion;
732 : }
733 :
734 : const LayerIntRegion&
735 0 : RefLayerComposite::GetShadowVisibleRegion()
736 : {
737 0 : if (!UseIntermediateSurface()) {
738 0 : RecomputeShadowVisibleRegionFromChildren();
739 : }
740 :
741 0 : return mShadowVisibleRegion;
742 : }
743 :
744 0 : RefLayerComposite::RefLayerComposite(LayerManagerComposite* aManager)
745 : : RefLayer(aManager, nullptr)
746 0 : , LayerComposite(aManager)
747 : {
748 0 : mImplData = static_cast<LayerComposite*>(this);
749 0 : }
750 :
751 0 : RefLayerComposite::~RefLayerComposite()
752 : {
753 0 : Destroy();
754 0 : }
755 :
756 : void
757 0 : RefLayerComposite::Destroy()
758 : {
759 0 : MOZ_ASSERT(!mFirstChild);
760 0 : mDestroyed = true;
761 0 : }
762 :
763 : LayerComposite*
764 0 : RefLayerComposite::GetFirstChildComposite()
765 : {
766 0 : if (!mFirstChild) {
767 : return nullptr;
768 : }
769 0 : return static_cast<LayerComposite*>(mFirstChild->AsHostLayer());
770 : }
771 :
772 : void
773 0 : RefLayerComposite::RenderLayer(const gfx::IntRect& aClipRect,
774 : const Maybe<gfx::Polygon>& aGeometry)
775 : {
776 0 : ContainerRender(this, mCompositeManager, aClipRect, aGeometry);
777 0 : }
778 :
779 : void
780 0 : RefLayerComposite::Prepare(const RenderTargetIntRect& aClipRect)
781 : {
782 0 : ContainerPrepare(this, mCompositeManager, aClipRect);
783 0 : }
784 :
785 : void
786 0 : RefLayerComposite::Cleanup()
787 : {
788 0 : mPrepared = nullptr;
789 :
790 : for (Layer* l = GetFirstChild(); l; l = l->GetNextSibling()) {
791 : static_cast<LayerComposite*>(l->AsHostLayer())->Cleanup();
792 : }
793 : }
794 :
795 : void
796 : RefLayerComposite::CleanupResources()
797 : {
798 : mLastIntermediateSurface = nullptr;
799 : mPrepared = nullptr;
800 : }
801 :
802 : } // namespace layers
803 : } // namespace mozilla
|