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 #ifdef MOZ_ENABLE_PROFILER_SPS
39 #include "ProfilerMarkers.h" // for ProfilerMarkers
40 #endif
41
42 #define CULLING_LOG(...)
43 // #define CULLING_LOG(...) printf_stderr("CULLING: " __VA_ARGS__)
44
45 #define DUMP(...) do { if (gfxEnv::DumpDebug()) { printf_stderr(__VA_ARGS__); } } while(0)
46 #define XYWH(k) (k).x, (k).y, (k).width, (k).height
47 #define XY(k) (k).x, (k).y
48 #define WH(k) (k).width, (k).height
49
50 namespace mozilla {
51 namespace layers {
52
53 using namespace gfx;
54
DrawLayerInfo(const RenderTargetIntRect & aClipRect,LayerManagerComposite * aManager,Layer * aLayer)55 static void DrawLayerInfo(const RenderTargetIntRect& aClipRect,
56 LayerManagerComposite* aManager,
57 Layer* aLayer)
58 {
59
60 if (aLayer->GetType() == Layer::LayerType::TYPE_CONTAINER) {
61 // XXX - should figure out a way to render this, but for now this
62 // is hard to do, since it will often get superimposed over the first
63 // child of the layer, which is bad.
64 return;
65 }
66
67 std::stringstream ss;
68 aLayer->PrintInfo(ss, "");
69
70 LayerIntRegion visibleRegion = aLayer->GetVisibleRegion();
71
72 uint32_t maxWidth = std::min<uint32_t>(visibleRegion.GetBounds().width, 500);
73
74 IntPoint topLeft = visibleRegion.ToUnknownRegion().GetBounds().TopLeft();
75 aManager->GetTextRenderer()->RenderText(ss.str().c_str(), topLeft,
76 aLayer->GetEffectiveTransform(), 16,
77 maxWidth);
78 }
79
80 template<class ContainerT>
ContainerVisibleRect(ContainerT * aContainer)81 static gfx::IntRect ContainerVisibleRect(ContainerT* aContainer)
82 {
83 gfx::IntRect surfaceRect = aContainer->GetLocalVisibleRegion().ToUnknownRegion().GetBounds();
84 return surfaceRect;
85 }
86
PrintUniformityInfo(Layer * aLayer)87 static void PrintUniformityInfo(Layer* aLayer)
88 {
89 #ifdef MOZ_ENABLE_PROFILER_SPS
90 if (!profiler_is_active()) {
91 return;
92 }
93
94 // Don't want to print a log for smaller layers
95 if (aLayer->GetLocalVisibleRegion().GetBounds().width < 300 ||
96 aLayer->GetLocalVisibleRegion().GetBounds().height < 300) {
97 return;
98 }
99
100 Matrix4x4 transform = aLayer->AsLayerComposite()->GetShadowBaseTransform();
101 if (!transform.Is2D()) {
102 return;
103 }
104
105 Point translation = transform.As2D().GetTranslation();
106 LayerTranslationPayload* payload = new LayerTranslationPayload(aLayer, translation);
107 PROFILER_MARKER_PAYLOAD("LayerTranslation", payload);
108 #endif
109 }
110
111 /* all of the per-layer prepared data we need to maintain */
112 struct PreparedLayer
113 {
PreparedLayermozilla::layers::PreparedLayer114 PreparedLayer(Layer *aLayer, RenderTargetIntRect aClipRect) :
115 mLayer(aLayer), mClipRect(aClipRect) {}
116 RefPtr<Layer> mLayer;
117 RenderTargetIntRect mClipRect;
118 };
119
120 /* all of the prepared data that we need in RenderLayer() */
121 struct PreparedData
122 {
123 RefPtr<CompositingRenderTarget> mTmpTarget;
124 AutoTArray<PreparedLayer, 12> mLayers;
125 bool mNeedsSurfaceCopy;
126 };
127
128 // ContainerPrepare is shared between RefLayer and ContainerLayer
129 template<class ContainerT> void
ContainerPrepare(ContainerT * aContainer,LayerManagerComposite * aManager,const RenderTargetIntRect & aClipRect)130 ContainerPrepare(ContainerT* aContainer,
131 LayerManagerComposite* aManager,
132 const RenderTargetIntRect& aClipRect)
133 {
134 aContainer->mPrepared = MakeUnique<PreparedData>();
135 aContainer->mPrepared->mNeedsSurfaceCopy = false;
136
137 /**
138 * Determine which layers to draw.
139 */
140 AutoTArray<Layer*, 12> children;
141 aContainer->SortChildrenBy3DZOrder(children);
142
143 for (uint32_t i = 0; i < children.Length(); i++) {
144 LayerComposite* layerToRender = static_cast<LayerComposite*>(children.ElementAt(i)->ImplData());
145
146 RenderTargetIntRect clipRect = layerToRender->GetLayer()->
147 CalculateScissorRect(aClipRect);
148
149 if (layerToRender->GetLayer()->IsBackfaceHidden()) {
150 continue;
151 }
152
153 // We don't want to skip container layers because otherwise their mPrepared
154 // may be null which is not allowed.
155 if (!layerToRender->GetLayer()->AsContainerLayer()) {
156 if (!layerToRender->GetLayer()->IsVisible() &&
157 !layerToRender->NeedToDrawCheckerboarding(nullptr)) {
158 CULLING_LOG("Sublayer %p has no effective visible region\n", layerToRender->GetLayer());
159 continue;
160 }
161
162 if (clipRect.IsEmpty()) {
163 CULLING_LOG("Sublayer %p has an empty world clip rect\n", layerToRender->GetLayer());
164 continue;
165 }
166 }
167
168 CULLING_LOG("Preparing sublayer %p\n", layerToRender->GetLayer());
169
170 layerToRender->Prepare(clipRect);
171 aContainer->mPrepared->mLayers.AppendElement(PreparedLayer(layerToRender->GetLayer(),
172 clipRect));
173 }
174
175 CULLING_LOG("Preparing container layer %p\n", aContainer->GetLayer());
176
177 /**
178 * Setup our temporary surface for rendering the contents of this container.
179 */
180
181 gfx::IntRect surfaceRect = ContainerVisibleRect(aContainer);
182 if (surfaceRect.IsEmpty()) {
183 return;
184 }
185
186 bool surfaceCopyNeeded;
187 // DefaultComputeSupportsComponentAlphaChildren can mutate aContainer so call it unconditionally
188 aContainer->DefaultComputeSupportsComponentAlphaChildren(&surfaceCopyNeeded);
189 if (aContainer->UseIntermediateSurface()) {
190 if (!surfaceCopyNeeded) {
191 RefPtr<CompositingRenderTarget> surface = nullptr;
192
193 RefPtr<CompositingRenderTarget>& lastSurf = aContainer->mLastIntermediateSurface;
194 if (lastSurf && !aContainer->mChildrenChanged && lastSurf->GetRect().IsEqualEdges(surfaceRect)) {
195 surface = lastSurf;
196 }
197
198 if (!surface) {
199 // If we don't need a copy we can render to the intermediate now to avoid
200 // unecessary render target switching. This brings a big perf boost on mobile gpus.
201 surface = CreateOrRecycleTarget(aContainer, aManager);
202
203 MOZ_PERFORMANCE_WARNING("gfx", "[%p] Container layer requires intermediate surface rendering\n", aContainer);
204 RenderIntermediate(aContainer, aManager, aClipRect.ToUnknownRect(), surface);
205 aContainer->SetChildrenChanged(false);
206 }
207
208 aContainer->mPrepared->mTmpTarget = surface;
209 } else {
210 MOZ_PERFORMANCE_WARNING("gfx", "[%p] Container layer requires intermediate surface copy\n", aContainer);
211 aContainer->mPrepared->mNeedsSurfaceCopy = true;
212 aContainer->mLastIntermediateSurface = nullptr;
213 }
214 } else {
215 aContainer->mLastIntermediateSurface = nullptr;
216 }
217 }
218
219 template<class ContainerT> void
RenderMinimap(ContainerT * aContainer,LayerManagerComposite * aManager,const RenderTargetIntRect & aClipRect,Layer * aLayer)220 RenderMinimap(ContainerT* aContainer, LayerManagerComposite* aManager,
221 const RenderTargetIntRect& aClipRect, Layer* aLayer)
222 {
223 Compositor* compositor = aManager->GetCompositor();
224
225 if (aLayer->GetScrollMetadataCount() < 1) {
226 return;
227 }
228
229 AsyncPanZoomController* controller = aLayer->GetAsyncPanZoomController(0);
230 if (!controller) {
231 return;
232 }
233
234 ParentLayerPoint scrollOffset = controller->GetCurrentAsyncScrollOffset(AsyncPanZoomController::RESPECT_FORCE_DISABLE);
235
236 // Options
237 const int verticalPadding = 10;
238 const int horizontalPadding = 5;
239 gfx::Color backgroundColor(0.3f, 0.3f, 0.3f, 0.3f);
240 gfx::Color tileActiveColor(1, 1, 1, 0.4f);
241 gfx::Color tileBorderColor(0, 0, 0, 0.1f);
242 gfx::Color pageBorderColor(0, 0, 0);
243 gfx::Color criticalDisplayPortColor(1.f, 1.f, 0);
244 gfx::Color displayPortColor(0, 1.f, 0);
245 gfx::Color viewPortColor(0, 0, 1.f, 0.3f);
246 gfx::Color visibilityColor(1.f, 0, 0);
247
248 // Rects
249 const FrameMetrics& fm = aLayer->GetFrameMetrics(0);
250 ParentLayerRect compositionBounds = fm.GetCompositionBounds();
251 LayerRect scrollRect = fm.GetScrollableRect() * fm.LayersPixelsPerCSSPixel();
252 LayerRect viewRect = ParentLayerRect(scrollOffset, compositionBounds.Size()) / LayerToParentLayerScale(1);
253 LayerRect dp = (fm.GetDisplayPort() + fm.GetScrollOffset()) * fm.LayersPixelsPerCSSPixel();
254 Maybe<LayerRect> cdp;
255 if (!fm.GetCriticalDisplayPort().IsEmpty()) {
256 cdp = Some((fm.GetCriticalDisplayPort() + fm.GetScrollOffset()) * fm.LayersPixelsPerCSSPixel());
257 }
258
259 // Don't render trivial minimap. They can show up from textboxes and other tiny frames.
260 if (viewRect.width < 64 && viewRect.height < 64) {
261 return;
262 }
263
264 // Compute a scale with an appropriate aspect ratio
265 // We allocate up to 100px of width and the height of this layer.
266 float scaleFactor;
267 float scaleFactorX;
268 float scaleFactorY;
269 Rect dest = Rect(aClipRect.ToUnknownRect());
270 if (aLayer->GetLocalClipRect()) {
271 dest = Rect(aLayer->GetLocalClipRect().value().ToUnknownRect());
272 } else {
273 dest = aContainer->GetEffectiveTransform().Inverse().TransformBounds(dest);
274 }
275 dest = dest.Intersect(compositionBounds.ToUnknownRect());
276 scaleFactorX = std::min(100.f, dest.width - (2 * horizontalPadding)) / scrollRect.width;
277 scaleFactorY = (dest.height - (2 * verticalPadding)) / scrollRect.height;
278 scaleFactor = std::min(scaleFactorX, scaleFactorY);
279 if (scaleFactor <= 0) {
280 return;
281 }
282
283 Matrix4x4 transform = Matrix4x4::Scaling(scaleFactor, scaleFactor, 1);
284 transform.PostTranslate(horizontalPadding + dest.x, verticalPadding + dest.y, 0);
285
286 Rect transformedScrollRect = transform.TransformBounds(scrollRect.ToUnknownRect());
287
288 IntRect clipRect = RoundedOut(aContainer->GetEffectiveTransform().TransformBounds(transformedScrollRect));
289
290 // Render the scrollable area.
291 compositor->FillRect(transformedScrollRect, backgroundColor, clipRect, aContainer->GetEffectiveTransform());
292 compositor->SlowDrawRect(transformedScrollRect, pageBorderColor, clipRect, aContainer->GetEffectiveTransform());
293
294 // If enabled, render information about visibility.
295 if (gfxPrefs::APZMinimapVisibilityEnabled()) {
296 // Retrieve the APZC scrollable layer guid, which we'll use to get the
297 // appropriate visibility information from the layer manager.
298 AsyncPanZoomController* controller = aLayer->GetAsyncPanZoomController(0);
299 MOZ_ASSERT(controller);
300
301 ScrollableLayerGuid guid = controller->GetGuid();
302
303 // Get the approximately visible region.
304 static CSSIntRegion emptyRegion;
305 CSSIntRegion* visibleRegion = aManager->GetApproximatelyVisibleRegion(guid);
306 if (!visibleRegion) {
307 visibleRegion = &emptyRegion;
308 }
309
310 // Iterate through and draw the rects in the region.
311 for (CSSIntRegion::RectIterator iterator = visibleRegion->RectIter();
312 !iterator.Done();
313 iterator.Next())
314 {
315 CSSIntRect rect = iterator.Get();
316 LayerRect scaledRect = rect * fm.LayersPixelsPerCSSPixel();
317 Rect r = transform.TransformBounds(scaledRect.ToUnknownRect());
318 compositor->FillRect(r, visibilityColor, clipRect, aContainer->GetEffectiveTransform());
319 }
320 }
321
322 // Render the displayport.
323 Rect r = transform.TransformBounds(dp.ToUnknownRect());
324 compositor->FillRect(r, tileActiveColor, clipRect, aContainer->GetEffectiveTransform());
325 compositor->SlowDrawRect(r, displayPortColor, clipRect, aContainer->GetEffectiveTransform());
326
327 // Render the critical displayport if there is one
328 if (cdp) {
329 r = transform.TransformBounds(cdp->ToUnknownRect());
330 compositor->SlowDrawRect(r, criticalDisplayPortColor, clipRect, aContainer->GetEffectiveTransform());
331 }
332
333 // Render the viewport.
334 r = transform.TransformBounds(viewRect.ToUnknownRect());
335 compositor->SlowDrawRect(r, viewPortColor, clipRect, aContainer->GetEffectiveTransform(), 2);
336 }
337
338
339 template<class ContainerT> void
RenderLayers(ContainerT * aContainer,LayerManagerComposite * aManager,const RenderTargetIntRect & aClipRect)340 RenderLayers(ContainerT* aContainer,
341 LayerManagerComposite* aManager,
342 const RenderTargetIntRect& aClipRect)
343 {
344 Compositor* compositor = aManager->GetCompositor();
345
346 for (size_t i = 0u; i < aContainer->mPrepared->mLayers.Length(); i++) {
347 PreparedLayer& preparedData = aContainer->mPrepared->mLayers[i];
348 LayerComposite* layerToRender = static_cast<LayerComposite*>(preparedData.mLayer->ImplData());
349 const RenderTargetIntRect& clipRect = preparedData.mClipRect;
350 Layer* layer = layerToRender->GetLayer();
351
352 if (layerToRender->HasStaleCompositor()) {
353 continue;
354 }
355
356 if (gfxPrefs::LayersDrawFPS()) {
357 for (const auto& metadata : layer->GetAllScrollMetadata()) {
358 if (metadata.IsApzForceDisabled()) {
359 aManager->DisabledApzWarning();
360 break;
361 }
362 }
363 }
364
365 Color color;
366 if (layerToRender->NeedToDrawCheckerboarding(&color)) {
367 if (gfxPrefs::APZHighlightCheckerboardedAreas()) {
368 color = Color(255 / 255.f, 188 / 255.f, 217 / 255.f, 1.f); // "Cotton Candy"
369 }
370 // Ideally we would want to intersect the checkerboard region from the APZ with the layer bounds
371 // and only fill in that area. However the layer bounds takes into account the base translation
372 // for the painted layer whereas the checkerboard region does not. One does not simply
373 // intersect areas in different coordinate spaces. So we do this a little more permissively
374 // and only fill in the background when we know there is checkerboard, which in theory
375 // should only occur transiently.
376 gfx::IntRect layerBounds = layer->GetLayerBounds();
377 EffectChain effectChain(layer);
378 effectChain.mPrimaryEffect = new EffectSolidColor(color);
379 aManager->GetCompositor()->DrawQuad(gfx::Rect(layerBounds.x, layerBounds.y, layerBounds.width, layerBounds.height),
380 clipRect.ToUnknownRect(),
381 effectChain, layer->GetEffectiveOpacity(),
382 layer->GetEffectiveTransform());
383 }
384
385 if (layerToRender->HasLayerBeenComposited()) {
386 // Composer2D will compose this layer so skip GPU composition
387 // this time. The flag will be reset for the next composition phase
388 // at the beginning of LayerManagerComposite::Rener().
389 gfx::IntRect clearRect = layerToRender->GetClearRect();
390 if (!clearRect.IsEmpty()) {
391 // Clear layer's visible rect on FrameBuffer with transparent pixels
392 gfx::Rect fbRect(clearRect.x, clearRect.y, clearRect.width, clearRect.height);
393 compositor->ClearRect(fbRect);
394 layerToRender->SetClearRect(gfx::IntRect(0, 0, 0, 0));
395 }
396 } else {
397 layerToRender->RenderLayer(clipRect.ToUnknownRect());
398 }
399
400 if (gfxPrefs::UniformityInfo()) {
401 PrintUniformityInfo(layer);
402 }
403
404 if (gfxPrefs::DrawLayerInfo()) {
405 DrawLayerInfo(clipRect, aManager, layer);
406 }
407
408 // Draw a border around scrollable layers.
409 // A layer can be scrolled by multiple scroll frames. Draw a border
410 // for each.
411 // Within the list of scroll frames for a layer, the layer border for a
412 // scroll frame lower down is affected by the async transforms on scroll
413 // frames higher up, so loop from the top down, and accumulate an async
414 // transform as we go along.
415 Matrix4x4 asyncTransform;
416 for (uint32_t i = layer->GetScrollMetadataCount(); i > 0; --i) {
417 if (layer->GetFrameMetrics(i - 1).IsScrollable()) {
418 // Since the composition bounds are in the parent layer's coordinates,
419 // use the parent's effective transform rather than the layer's own.
420 ParentLayerRect compositionBounds = layer->GetFrameMetrics(i - 1).GetCompositionBounds();
421 aManager->GetCompositor()->DrawDiagnostics(DiagnosticFlags::CONTAINER,
422 compositionBounds.ToUnknownRect(),
423 aClipRect.ToUnknownRect(),
424 asyncTransform * aContainer->GetEffectiveTransform());
425 if (AsyncPanZoomController* apzc = layer->GetAsyncPanZoomController(i - 1)) {
426 asyncTransform =
427 apzc->GetCurrentAsyncTransformWithOverscroll(AsyncPanZoomController::RESPECT_FORCE_DISABLE).ToUnknownMatrix()
428 * asyncTransform;
429 }
430 }
431 }
432
433 if (gfxPrefs::APZMinimap()) {
434 RenderMinimap(aContainer, aManager, aClipRect, layer);
435 }
436
437 // invariant: our GL context should be current here, I don't think we can
438 // assert it though
439 }
440 }
441
442 template<class ContainerT> RefPtr<CompositingRenderTarget>
CreateOrRecycleTarget(ContainerT * aContainer,LayerManagerComposite * aManager)443 CreateOrRecycleTarget(ContainerT* aContainer,
444 LayerManagerComposite* aManager)
445 {
446 Compositor* compositor = aManager->GetCompositor();
447 SurfaceInitMode mode = INIT_MODE_CLEAR;
448 gfx::IntRect surfaceRect = ContainerVisibleRect(aContainer);
449 if (aContainer->GetLocalVisibleRegion().GetNumRects() == 1 &&
450 (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE))
451 {
452 mode = INIT_MODE_NONE;
453 }
454
455 RefPtr<CompositingRenderTarget>& lastSurf = aContainer->mLastIntermediateSurface;
456 if (lastSurf && lastSurf->GetRect().IsEqualEdges(surfaceRect)) {
457 if (mode == INIT_MODE_CLEAR) {
458 lastSurf->ClearOnBind();
459 }
460
461 return lastSurf;
462 } else {
463 lastSurf = compositor->CreateRenderTarget(surfaceRect, mode);
464
465 return lastSurf;
466 }
467 }
468
469 template<class ContainerT> RefPtr<CompositingRenderTarget>
CreateTemporaryTargetAndCopyFromBackground(ContainerT * aContainer,LayerManagerComposite * aManager)470 CreateTemporaryTargetAndCopyFromBackground(ContainerT* aContainer,
471 LayerManagerComposite* aManager)
472 {
473 Compositor* compositor = aManager->GetCompositor();
474 gfx::IntRect visibleRect = aContainer->GetLocalVisibleRegion().ToUnknownRegion().GetBounds();
475 RefPtr<CompositingRenderTarget> previousTarget = compositor->GetCurrentRenderTarget();
476 gfx::IntRect surfaceRect = gfx::IntRect(visibleRect.x, visibleRect.y,
477 visibleRect.width, visibleRect.height);
478
479 gfx::IntPoint sourcePoint = gfx::IntPoint(visibleRect.x, visibleRect.y);
480
481 gfx::Matrix4x4 transform = aContainer->GetEffectiveTransform();
482 DebugOnly<gfx::Matrix> transform2d;
483 MOZ_ASSERT(transform.Is2D(&transform2d) && !gfx::ThebesMatrix(transform2d).HasNonIntegerTranslation());
484 sourcePoint += gfx::IntPoint::Truncate(transform._41, transform._42);
485
486 sourcePoint -= compositor->GetCurrentRenderTarget()->GetOrigin();
487
488 return compositor->CreateRenderTargetFromSource(surfaceRect, previousTarget, sourcePoint);
489 }
490
491 template<class ContainerT> void
RenderIntermediate(ContainerT * aContainer,LayerManagerComposite * aManager,const gfx::IntRect & aClipRect,RefPtr<CompositingRenderTarget> surface)492 RenderIntermediate(ContainerT* aContainer,
493 LayerManagerComposite* aManager,
494 const gfx::IntRect& aClipRect,
495 RefPtr<CompositingRenderTarget> surface)
496 {
497 Compositor* compositor = aManager->GetCompositor();
498 RefPtr<CompositingRenderTarget> previousTarget = compositor->GetCurrentRenderTarget();
499
500 if (!surface) {
501 return;
502 }
503
504 compositor->SetRenderTarget(surface);
505 // pre-render all of the layers into our temporary
506 RenderLayers(aContainer, aManager, RenderTargetIntRect::FromUnknownRect(aClipRect));
507 // Unbind the current surface and rebind the previous one.
508 compositor->SetRenderTarget(previousTarget);
509 }
510
511 template<class ContainerT> void
ContainerRender(ContainerT * aContainer,LayerManagerComposite * aManager,const gfx::IntRect & aClipRect)512 ContainerRender(ContainerT* aContainer,
513 LayerManagerComposite* aManager,
514 const gfx::IntRect& aClipRect)
515 {
516 MOZ_ASSERT(aContainer->mPrepared);
517
518 if (aContainer->UseIntermediateSurface()) {
519 RefPtr<CompositingRenderTarget> surface;
520
521 if (aContainer->mPrepared->mNeedsSurfaceCopy) {
522 // we needed to copy the background so we waited until now to render the intermediate
523 surface = CreateTemporaryTargetAndCopyFromBackground(aContainer, aManager);
524 RenderIntermediate(aContainer, aManager,
525 aClipRect, surface);
526 } else {
527 surface = aContainer->mPrepared->mTmpTarget;
528 }
529
530 if (!surface) {
531 aContainer->mPrepared = nullptr;
532 return;
533 }
534
535 gfx::Rect visibleRect(aContainer->GetLocalVisibleRegion().ToUnknownRegion().GetBounds());
536 RefPtr<Compositor> compositor = aManager->GetCompositor();
537 #ifdef MOZ_DUMP_PAINTING
538 if (gfxEnv::DumpCompositorTextures()) {
539 RefPtr<gfx::DataSourceSurface> surf = surface->Dump(compositor);
540 if (surf) {
541 WriteSnapshotToDumpFile(aContainer, surf);
542 }
543 }
544 #endif
545
546 RefPtr<ContainerT> container = aContainer;
547 RenderWithAllMasks(aContainer, compositor, aClipRect,
548 [&, surface, compositor, container](EffectChain& effectChain, const IntRect& clipRect) {
549 effectChain.mPrimaryEffect = new EffectRenderTarget(surface);
550 compositor->DrawQuad(visibleRect, clipRect, effectChain,
551 container->GetEffectiveOpacity(),
552 container->GetEffectiveTransform());
553 });
554 } else {
555 RenderLayers(aContainer, aManager, RenderTargetIntRect::FromUnknownRect(aClipRect));
556 }
557 aContainer->mPrepared = nullptr;
558
559 // If it is a scrollable container layer with no child layers, and one of the APZCs
560 // attached to it has a nonempty async transform, then that transform is not applied
561 // to any visible content. Display a warning box (conditioned on the FPS display being
562 // enabled).
563 if (gfxPrefs::LayersDrawFPS() && aContainer->IsScrollInfoLayer()) {
564 // Since aContainer doesn't have any children we can just iterate from the top metrics
565 // on it down to the bottom using GetFirstChild and not worry about walking onto another
566 // underlying layer.
567 for (LayerMetricsWrapper i(aContainer); i; i = i.GetFirstChild()) {
568 if (AsyncPanZoomController* apzc = i.GetApzc()) {
569 if (!apzc->GetAsyncTransformAppliedToContent()
570 && !AsyncTransformComponentMatrix(apzc->GetCurrentAsyncTransform(AsyncPanZoomController::NORMAL)).IsIdentity()) {
571 aManager->UnusedApzTransformWarning();
572 break;
573 }
574 }
575 }
576 }
577 }
578
ContainerLayerComposite(LayerManagerComposite * aManager)579 ContainerLayerComposite::ContainerLayerComposite(LayerManagerComposite *aManager)
580 : ContainerLayer(aManager, nullptr)
581 , LayerComposite(aManager)
582 {
583 MOZ_COUNT_CTOR(ContainerLayerComposite);
584 mImplData = static_cast<LayerComposite*>(this);
585 }
586
~ContainerLayerComposite()587 ContainerLayerComposite::~ContainerLayerComposite()
588 {
589 MOZ_COUNT_DTOR(ContainerLayerComposite);
590
591 // We don't Destroy() on destruction here because this destructor
592 // can be called after remote content has crashed, and it may not be
593 // safe to free the IPC resources of our children. Those resources
594 // are automatically cleaned up by IPDL-generated code.
595 //
596 // In the common case of normal shutdown, either
597 // LayerManagerComposite::Destroy(), a parent
598 // *ContainerLayerComposite::Destroy(), or Disconnect() will trigger
599 // cleanup of our resources.
600 while (mFirstChild) {
601 RemoveChild(mFirstChild);
602 }
603 }
604
605 void
Destroy()606 ContainerLayerComposite::Destroy()
607 {
608 if (!mDestroyed) {
609 while (mFirstChild) {
610 static_cast<LayerComposite*>(GetFirstChild()->ImplData())->Destroy();
611 RemoveChild(mFirstChild);
612 }
613 mDestroyed = true;
614 }
615 }
616
617 LayerComposite*
GetFirstChildComposite()618 ContainerLayerComposite::GetFirstChildComposite()
619 {
620 if (!mFirstChild) {
621 return nullptr;
622 }
623 return static_cast<LayerComposite*>(mFirstChild->ImplData());
624 }
625
626 void
RenderLayer(const gfx::IntRect & aClipRect)627 ContainerLayerComposite::RenderLayer(const gfx::IntRect& aClipRect)
628 {
629 ContainerRender(this, mCompositeManager, aClipRect);
630 }
631
632 void
Prepare(const RenderTargetIntRect & aClipRect)633 ContainerLayerComposite::Prepare(const RenderTargetIntRect& aClipRect)
634 {
635 ContainerPrepare(this, mCompositeManager, aClipRect);
636 }
637
638 void
CleanupResources()639 ContainerLayerComposite::CleanupResources()
640 {
641 mLastIntermediateSurface = nullptr;
642 mPrepared = nullptr;
643
644 for (Layer* l = GetFirstChild(); l; l = l->GetNextSibling()) {
645 LayerComposite* layerToCleanup = static_cast<LayerComposite*>(l->ImplData());
646 layerToCleanup->CleanupResources();
647 }
648 }
649
RefLayerComposite(LayerManagerComposite * aManager)650 RefLayerComposite::RefLayerComposite(LayerManagerComposite* aManager)
651 : RefLayer(aManager, nullptr)
652 , LayerComposite(aManager)
653 {
654 mImplData = static_cast<LayerComposite*>(this);
655 }
656
~RefLayerComposite()657 RefLayerComposite::~RefLayerComposite()
658 {
659 Destroy();
660 }
661
662 void
Destroy()663 RefLayerComposite::Destroy()
664 {
665 MOZ_ASSERT(!mFirstChild);
666 mDestroyed = true;
667 }
668
669 LayerComposite*
GetFirstChildComposite()670 RefLayerComposite::GetFirstChildComposite()
671 {
672 if (!mFirstChild) {
673 return nullptr;
674 }
675 return static_cast<LayerComposite*>(mFirstChild->ImplData());
676 }
677
678 void
RenderLayer(const gfx::IntRect & aClipRect)679 RefLayerComposite::RenderLayer(const gfx::IntRect& aClipRect)
680 {
681 ContainerRender(this, mCompositeManager, aClipRect);
682 }
683
684 void
Prepare(const RenderTargetIntRect & aClipRect)685 RefLayerComposite::Prepare(const RenderTargetIntRect& aClipRect)
686 {
687 ContainerPrepare(this, mCompositeManager, aClipRect);
688 }
689
690 void
CleanupResources()691 RefLayerComposite::CleanupResources()
692 {
693 mLastIntermediateSurface = nullptr;
694 mPrepared = nullptr;
695 }
696
697 } // namespace layers
698 } // namespace mozilla
699