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