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 "LayerManagerComposite.h"
8 #include <stddef.h> // for size_t
9 #include <stdint.h> // for uint16_t, uint32_t
10 #include "CanvasLayerComposite.h" // for CanvasLayerComposite
11 #include "ColorLayerComposite.h" // for ColorLayerComposite
12 #include "CompositableHost.h" // for CompositableHost
13 #include "ContainerLayerComposite.h" // for ContainerLayerComposite, etc
14 #include "Diagnostics.h"
15 #include "FPSCounter.h" // for FPSState, FPSCounter
16 #include "FrameMetrics.h" // for FrameMetrics
17 #include "GeckoProfiler.h" // for profiler_*
18 #include "ImageLayerComposite.h" // for ImageLayerComposite
19 #include "Layers.h" // for Layer, ContainerLayer, etc
20 #include "LayerScope.h" // for LayerScope Tool
21 #include "protobuf/LayerScopePacket.pb.h" // for protobuf (LayerScope)
22 #include "PaintedLayerComposite.h" // for PaintedLayerComposite
23 #include "TiledContentHost.h"
24 #include "Units.h" // for ScreenIntRect
25 #include "UnitTransforms.h" // for ViewAs
26 #include "apz/src/AsyncPanZoomController.h" // for AsyncPanZoomController
27 #include "gfxPrefs.h" // for gfxPrefs
28 #ifdef XP_MACOSX
29 #include "gfxPlatformMac.h"
30 #endif
31 #include "gfxRect.h" // for gfxRect
32 #include "gfxUtils.h" // for frame color util
33 #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
34 #include "mozilla/RefPtr.h" // for RefPtr, already_AddRefed
35 #include "mozilla/gfx/2D.h" // for DrawTarget
36 #include "mozilla/gfx/Matrix.h" // for Matrix4x4
37 #include "mozilla/gfx/Point.h" // for IntSize, Point
38 #include "mozilla/gfx/Rect.h" // for Rect
39 #include "mozilla/gfx/Types.h" // for Color, SurfaceFormat
40 #include "mozilla/layers/Compositor.h" // for Compositor
41 #include "mozilla/layers/CompositorTypes.h"
42 #include "mozilla/layers/Effects.h" // for Effect, EffectChain, etc
43 #include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
44 #include "mozilla/layers/LayersTypes.h" // for etc
45 #include "mozilla/widget/CompositorWidget.h" // for WidgetRenderingContext
46 #include "ipc/CompositorBench.h" // for CompositorBench
47 #include "ipc/ShadowLayerUtils.h"
48 #include "mozilla/mozalloc.h" // for operator new, etc
49 #include "nsAppRunner.h"
50 #include "mozilla/RefPtr.h" // for nsRefPtr
51 #include "nsCOMPtr.h" // for already_AddRefed
52 #include "nsDebug.h" // for NS_WARNING, etc
53 #include "nsISupportsImpl.h" // for Layer::AddRef, etc
54 #include "nsPoint.h" // for nsIntPoint
55 #include "nsRect.h" // for mozilla::gfx::IntRect
56 #include "nsRegion.h" // for nsIntRegion, etc
57 #if defined(MOZ_WIDGET_ANDROID)
58 #include <android/log.h>
59 #include <android/native_window.h>
60 #include "mozilla/widget/AndroidCompositorWidget.h"
61 #include "opengl/CompositorOGL.h"
62 #include "GLConsts.h"
63 #include "GLContextEGL.h"
64 #include "GLContextProvider.h"
65 #include "mozilla/Unused.h"
66 #include "mozilla/widget/AndroidCompositorWidget.h"
67 #include "ScopedGLHelpers.h"
68 #endif
69 #include "GeckoProfiler.h"
70 #include "TextRenderer.h" // for TextRenderer
71 #include "mozilla/layers/CompositorBridgeParent.h"
72 #include "TreeTraversal.h" // for ForEachNode
73
74 #ifdef USE_SKIA
75 #include "PaintCounter.h" // For PaintCounter
76 #endif
77
78 class gfxContext;
79
80 namespace mozilla {
81 namespace layers {
82
83 class ImageLayer;
84
85 using namespace mozilla::gfx;
86 using namespace mozilla::gl;
87
ToLayerComposite(Layer * aLayer)88 static LayerComposite* ToLayerComposite(Layer* aLayer) {
89 return static_cast<LayerComposite*>(aLayer->ImplData());
90 }
91
ClearSubtree(Layer * aLayer)92 static void ClearSubtree(Layer* aLayer) {
93 ForEachNode<ForwardIterator>(aLayer, [](Layer* layer) {
94 ToLayerComposite(layer)->CleanupResources();
95 });
96 }
97
ClearCachedResources(Layer * aSubtree)98 void LayerManagerComposite::ClearCachedResources(Layer* aSubtree) {
99 MOZ_ASSERT(!aSubtree || aSubtree->Manager() == this);
100 Layer* subtree = aSubtree ? aSubtree : mRoot.get();
101 if (!subtree) {
102 return;
103 }
104
105 ClearSubtree(subtree);
106 // FIXME [bjacob]
107 // XXX the old LayerManagerOGL code had a mMaybeInvalidTree that it set to
108 // true here. Do we need that?
109 }
110
HostLayerManager()111 HostLayerManager::HostLayerManager()
112 : mDebugOverlayWantsNextFrame(false),
113 mWarningLevel(0.0f),
114 mCompositorBridgeID(0),
115 mWindowOverlayChanged(false),
116 mLastPaintTime(TimeDuration::Forever()),
117 mRenderStartTime(TimeStamp::Now()) {}
118
~HostLayerManager()119 HostLayerManager::~HostLayerManager() {}
120
RecordPaintTimes(const PaintTiming & aTiming)121 void HostLayerManager::RecordPaintTimes(const PaintTiming& aTiming) {
122 mDiagnostics->RecordPaintTimes(aTiming);
123 }
124
RecordUpdateTime(float aValue)125 void HostLayerManager::RecordUpdateTime(float aValue) {
126 mDiagnostics->RecordUpdateTime(aValue);
127 }
128
129 /**
130 * LayerManagerComposite
131 */
LayerManagerComposite(Compositor * aCompositor)132 LayerManagerComposite::LayerManagerComposite(Compositor* aCompositor)
133 : mUnusedApzTransformWarning(false),
134 mDisabledApzWarning(false),
135 mCompositor(aCompositor),
136 mInTransaction(false),
137 mIsCompositorReady(false)
138 #if defined(MOZ_WIDGET_ANDROID)
139 ,
140 mScreenPixelsTarget(nullptr)
141 #endif // defined(MOZ_WIDGET_ANDROID)
142 {
143 mTextRenderer = new TextRenderer();
144 mDiagnostics = MakeUnique<Diagnostics>();
145 MOZ_ASSERT(aCompositor);
146
147 #ifdef USE_SKIA
148 mPaintCounter = nullptr;
149 #endif
150 }
151
~LayerManagerComposite()152 LayerManagerComposite::~LayerManagerComposite() { Destroy(); }
153
Destroy()154 void LayerManagerComposite::Destroy() {
155 if (!mDestroyed) {
156 mCompositor->GetWidget()->CleanupWindowEffects();
157 if (mRoot) {
158 RootLayer()->Destroy();
159 }
160 mCompositor->CancelFrame();
161 mRoot = nullptr;
162 mClonedLayerTreeProperties = nullptr;
163 mDestroyed = true;
164
165 #ifdef USE_SKIA
166 mPaintCounter = nullptr;
167 #endif
168 }
169 }
170
UpdateRenderBounds(const IntRect & aRect)171 void LayerManagerComposite::UpdateRenderBounds(const IntRect& aRect) {
172 mRenderBounds = aRect;
173 }
174
AreComponentAlphaLayersEnabled()175 bool LayerManagerComposite::AreComponentAlphaLayersEnabled() {
176 return mCompositor->GetBackendType() != LayersBackend::LAYERS_BASIC &&
177 mCompositor->SupportsEffect(EffectTypes::COMPONENT_ALPHA) &&
178 LayerManager::AreComponentAlphaLayersEnabled();
179 }
180
BeginTransaction()181 bool LayerManagerComposite::BeginTransaction() {
182 mInTransaction = true;
183
184 if (!mCompositor->Ready()) {
185 return false;
186 }
187
188 mIsCompositorReady = true;
189 return true;
190 }
191
BeginTransactionWithDrawTarget(DrawTarget * aTarget,const IntRect & aRect)192 void LayerManagerComposite::BeginTransactionWithDrawTarget(
193 DrawTarget* aTarget, const IntRect& aRect) {
194 mInTransaction = true;
195
196 if (!mCompositor->Ready()) {
197 return;
198 }
199
200 #ifdef MOZ_LAYERS_HAVE_LOG
201 MOZ_LAYERS_LOG(("[----- BeginTransaction"));
202 Log();
203 #endif
204
205 if (mDestroyed) {
206 NS_WARNING("Call on destroyed layer manager");
207 return;
208 }
209
210 mIsCompositorReady = true;
211 mCompositor->SetTargetContext(aTarget, aRect);
212 mTarget = aTarget;
213 mTargetBounds = aRect;
214 }
215
PostProcessLayers(nsIntRegion & aOpaqueRegion)216 void LayerManagerComposite::PostProcessLayers(nsIntRegion& aOpaqueRegion) {
217 LayerIntRegion visible;
218 LayerComposite* rootComposite =
219 static_cast<LayerComposite*>(mRoot->AsHostLayer());
220 PostProcessLayers(
221 mRoot, aOpaqueRegion, visible,
222 ViewAs<RenderTargetPixel>(
223 rootComposite->GetShadowClipRect(),
224 PixelCastJustification::RenderTargetIsParentLayerForRoot),
225 Nothing());
226 }
227
228 // We want to skip directly through ContainerLayers that don't have an
229 // intermediate surface. We compute occlusions for leaves and intermediate
230 // surfaces against the layer that they actually composite into so that we can
231 // use the final (snapped) effective transform.
ShouldProcessLayer(Layer * aLayer)232 bool ShouldProcessLayer(Layer* aLayer) {
233 if (!aLayer->AsContainerLayer()) {
234 return true;
235 }
236
237 return aLayer->AsContainerLayer()->UseIntermediateSurface();
238 }
239
PostProcessLayers(Layer * aLayer,nsIntRegion & aOpaqueRegion,LayerIntRegion & aVisibleRegion,const Maybe<RenderTargetIntRect> & aRenderTargetClip,const Maybe<ParentLayerIntRect> & aClipFromAncestors)240 void LayerManagerComposite::PostProcessLayers(
241 Layer* aLayer, nsIntRegion& aOpaqueRegion, LayerIntRegion& aVisibleRegion,
242 const Maybe<RenderTargetIntRect>& aRenderTargetClip,
243 const Maybe<ParentLayerIntRect>& aClipFromAncestors) {
244 // Compute a clip that's the combination of our layer clip with the clip
245 // from our ancestors.
246 LayerComposite* composite =
247 static_cast<LayerComposite*>(aLayer->AsHostLayer());
248 Maybe<ParentLayerIntRect> layerClip = composite->GetShadowClipRect();
249 MOZ_ASSERT(!layerClip || !aLayer->Combines3DTransformWithAncestors(),
250 "The layer with a clip should not participate "
251 "a 3D rendering context");
252 Maybe<ParentLayerIntRect> outsideClip =
253 IntersectMaybeRects(layerClip, aClipFromAncestors);
254
255 Maybe<LayerIntRect> insideClip;
256 if (aLayer->Extend3DContext()) {
257 // If we're preserve-3d just pass the clip rect down directly, and we'll do
258 // the conversion at the preserve-3d leaf Layer.
259 if (outsideClip) {
260 insideClip = Some(ViewAs<LayerPixel>(
261 *outsideClip, PixelCastJustification::MovingDownToChildren));
262 }
263 } else if (outsideClip) {
264 // Convert the combined clip into our pre-transform coordinate space, so
265 // that it can later be intersected with our visible region.
266 // If our transform is a perspective, there's no meaningful insideClip rect
267 // we can compute (it would need to be a cone).
268 Matrix4x4 localTransform = aLayer->ComputeTransformToPreserve3DRoot();
269 if (!localTransform.HasPerspectiveComponent() && localTransform.Invert()) {
270 LayerRect insideClipFloat =
271 UntransformBy(ViewAs<ParentLayerToLayerMatrix4x4>(localTransform),
272 ParentLayerRect(*outsideClip), LayerRect::MaxIntRect())
273 .valueOr(LayerRect());
274 insideClipFloat.RoundOut();
275 LayerIntRect insideClipInt;
276 if (insideClipFloat.ToIntRect(&insideClipInt)) {
277 insideClip = Some(insideClipInt);
278 }
279 }
280 }
281
282 Maybe<ParentLayerIntRect> ancestorClipForChildren;
283 if (insideClip) {
284 ancestorClipForChildren = Some(ViewAs<ParentLayerPixel>(
285 *insideClip, PixelCastJustification::MovingDownToChildren));
286 }
287
288 nsIntRegion dummy;
289 nsIntRegion& opaqueRegion = aOpaqueRegion;
290 if (aLayer->Extend3DContext() || aLayer->Combines3DTransformWithAncestors()) {
291 opaqueRegion = dummy;
292 }
293
294 if (!ShouldProcessLayer(aLayer)) {
295 MOZ_ASSERT(aLayer->AsContainerLayer() &&
296 !aLayer->AsContainerLayer()->UseIntermediateSurface());
297 // For layers participating 3D rendering context, their visible
298 // region should be empty (invisible), so we pass through them
299 // without doing anything.
300 for (Layer* child = aLayer->GetLastChild(); child;
301 child = child->GetPrevSibling()) {
302 LayerComposite* childComposite =
303 static_cast<LayerComposite*>(child->AsHostLayer());
304 Maybe<RenderTargetIntRect> renderTargetClip = aRenderTargetClip;
305 if (childComposite->GetShadowClipRect()) {
306 RenderTargetIntRect clip = TransformBy(
307 ViewAs<ParentLayerToRenderTargetMatrix4x4>(
308 aLayer->GetEffectiveTransform(),
309 PixelCastJustification::RenderTargetIsParentLayerForRoot),
310 *childComposite->GetShadowClipRect());
311 renderTargetClip = IntersectMaybeRects(renderTargetClip, Some(clip));
312 }
313
314 PostProcessLayers(child, opaqueRegion, aVisibleRegion, renderTargetClip,
315 ancestorClipForChildren);
316 }
317 return;
318 }
319
320 nsIntRegion localOpaque;
321 // Treat layers on the path to the root of the 3D rendering context as
322 // a giant layer if it is a leaf.
323 Matrix4x4 transform = aLayer->GetEffectiveTransform();
324 Matrix transform2d;
325 Maybe<IntPoint> integerTranslation;
326 // If aLayer has a simple transform (only an integer translation) then we
327 // can easily convert aOpaqueRegion into pre-transform coordinates and include
328 // that region.
329 if (transform.Is2D(&transform2d)) {
330 if (transform2d.IsIntegerTranslation()) {
331 integerTranslation =
332 Some(IntPoint::Truncate(transform2d.GetTranslation()));
333 localOpaque = opaqueRegion;
334 localOpaque.MoveBy(-*integerTranslation);
335 }
336 }
337
338 // Save the value of localOpaque, which currently stores the region obscured
339 // by siblings (and uncles and such), before our descendants contribute to it.
340 nsIntRegion obscured = localOpaque;
341
342 // Recurse on our descendants, in front-to-back order. In this process:
343 // - Occlusions are computed for them, and they contribute to localOpaque.
344 // - They recalculate their visible regions, taking ancestorClipForChildren
345 // into account, and accumulate them into descendantsVisibleRegion.
346 LayerIntRegion descendantsVisibleRegion;
347
348 bool hasPreserve3DChild = false;
349 for (Layer* child = aLayer->GetLastChild(); child;
350 child = child->GetPrevSibling()) {
351 MOZ_ASSERT(aLayer->AsContainerLayer()->UseIntermediateSurface());
352 LayerComposite* childComposite =
353 static_cast<LayerComposite*>(child->AsHostLayer());
354 PostProcessLayers(
355 child, localOpaque, descendantsVisibleRegion,
356 ViewAs<RenderTargetPixel>(
357 childComposite->GetShadowClipRect(),
358 PixelCastJustification::RenderTargetIsParentLayerForRoot),
359 ancestorClipForChildren);
360 if (child->Extend3DContext()) {
361 hasPreserve3DChild = true;
362 }
363 }
364
365 // Recalculate our visible region.
366 LayerIntRegion visible = composite->GetShadowVisibleRegion();
367
368 // If we have descendants, throw away the visible region stored on this
369 // layer, and use the region accumulated by our descendants instead.
370 if (aLayer->GetFirstChild() && !hasPreserve3DChild) {
371 visible = descendantsVisibleRegion;
372 }
373
374 // Subtract any areas that we know to be opaque.
375 if (!obscured.IsEmpty()) {
376 visible.SubOut(LayerIntRegion::FromUnknownRegion(obscured));
377 }
378
379 // Clip the visible region using the combined clip.
380 if (insideClip) {
381 visible.AndWith(*insideClip);
382 }
383 composite->SetShadowVisibleRegion(visible);
384
385 // Transform the newly calculated visible region into our parent's space,
386 // apply our clip to it (if any), and accumulate it into |aVisibleRegion|
387 // for the caller to use.
388 ParentLayerIntRegion visibleParentSpace =
389 TransformBy(ViewAs<LayerToParentLayerMatrix4x4>(transform), visible);
390 aVisibleRegion.OrWith(ViewAs<LayerPixel>(
391 visibleParentSpace, PixelCastJustification::MovingDownToChildren));
392
393 // If we have a simple transform, then we can add our opaque area into
394 // aOpaqueRegion.
395 if (integerTranslation && !aLayer->HasMaskLayers() &&
396 aLayer->IsOpaqueForVisibility()) {
397 if (aLayer->IsOpaque()) {
398 localOpaque.OrWith(composite->GetFullyRenderedRegion());
399 }
400 localOpaque.MoveBy(*integerTranslation);
401 if (aRenderTargetClip) {
402 localOpaque.AndWith(aRenderTargetClip->ToUnknownRect());
403 }
404 opaqueRegion.OrWith(localOpaque);
405 }
406 }
407
EndTransaction(const TimeStamp & aTimeStamp,EndTransactionFlags aFlags)408 void LayerManagerComposite::EndTransaction(const TimeStamp& aTimeStamp,
409 EndTransactionFlags aFlags) {
410 NS_ASSERTION(mInTransaction, "Didn't call BeginTransaction?");
411 NS_ASSERTION(!(aFlags & END_NO_COMPOSITE),
412 "Shouldn't get END_NO_COMPOSITE here");
413 mInTransaction = false;
414 mRenderStartTime = TimeStamp::Now();
415
416 if (!mIsCompositorReady) {
417 return;
418 }
419 mIsCompositorReady = false;
420
421 #ifdef MOZ_LAYERS_HAVE_LOG
422 MOZ_LAYERS_LOG((" ----- (beginning paint)"));
423 Log();
424 #endif
425
426 if (mDestroyed) {
427 NS_WARNING("Call on destroyed layer manager");
428 return;
429 }
430
431 // Set composition timestamp here because we need it in
432 // ComputeEffectiveTransforms (so the correct video frame size is picked) and
433 // also to compute invalid regions properly.
434 SetCompositionTime(aTimeStamp);
435
436 if (mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) {
437 MOZ_ASSERT(!aTimeStamp.IsNull());
438 UpdateAndRender();
439 mCompositor->FlushPendingNotifyNotUsed();
440 }
441
442 mCompositor->ClearTargetContext();
443 mTarget = nullptr;
444
445 #ifdef MOZ_LAYERS_HAVE_LOG
446 Log();
447 MOZ_LAYERS_LOG(("]----- EndTransaction"));
448 #endif
449 }
450
UpdateAndRender()451 void LayerManagerComposite::UpdateAndRender() {
452 nsIntRegion invalid;
453 // The results of our drawing always go directly into a pixel buffer,
454 // so we don't need to pass any global transform here.
455 mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4());
456
457 nsIntRegion opaque;
458 PostProcessLayers(opaque);
459
460 if (mClonedLayerTreeProperties) {
461 // We need to compute layer tree differences even if we're not going to
462 // immediately use the resulting damage area, since ComputeDifferences
463 // is also responsible for invalidates intermediate surfaces in
464 // ContainerLayers.
465 nsIntRegion changed;
466 if (!mClonedLayerTreeProperties->ComputeDifferences(mRoot, changed,
467 nullptr)) {
468 changed = mTargetBounds;
469 }
470
471 if (mTarget) {
472 // Since we're composing to an external target, we're not going to use
473 // the damage region from layers changes - we want to composite
474 // everything in the target bounds. Instead we accumulate the layers
475 // damage region for the next window composite.
476 mInvalidRegion.Or(mInvalidRegion, changed);
477 } else {
478 invalid = Move(changed);
479 }
480 }
481
482 if (mTarget) {
483 invalid.Or(invalid, mTargetBounds);
484 } else {
485 // If we didn't have a previous layer tree, invalidate the entire render
486 // area.
487 if (!mClonedLayerTreeProperties) {
488 invalid.Or(invalid, mRenderBounds);
489 }
490
491 // Add any additional invalid rects from the window manager or previous
492 // damage computed during ComposeToTarget().
493 invalid.Or(invalid, mInvalidRegion);
494 mInvalidRegion.SetEmpty();
495 }
496
497 if (invalid.IsEmpty() && !mWindowOverlayChanged) {
498 // Composition requested, but nothing has changed. Don't do any work.
499 mClonedLayerTreeProperties = LayerProperties::CloneFrom(GetRoot());
500 return;
501 }
502
503 // We don't want our debug overlay to cause more frames to happen
504 // so we will invalidate after we've decided if something changed.
505 InvalidateDebugOverlay(invalid, mRenderBounds);
506
507 Render(invalid, opaque);
508 #if defined(MOZ_WIDGET_ANDROID)
509 RenderToPresentationSurface();
510 #endif
511 mWindowOverlayChanged = false;
512
513 // Update cached layer tree information.
514 mClonedLayerTreeProperties = LayerProperties::CloneFrom(GetRoot());
515 }
516
CreateOptimalMaskDrawTarget(const IntSize & aSize)517 already_AddRefed<DrawTarget> LayerManagerComposite::CreateOptimalMaskDrawTarget(
518 const IntSize& aSize) {
519 MOZ_CRASH("Should only be called on the drawing side");
520 return nullptr;
521 }
522
RootLayer() const523 LayerComposite* LayerManagerComposite::RootLayer() const {
524 if (mDestroyed) {
525 NS_WARNING("Call on destroyed layer manager");
526 return nullptr;
527 }
528
529 return ToLayerComposite(mRoot);
530 }
531
InvalidateDebugOverlay(nsIntRegion & aInvalidRegion,const IntRect & aBounds)532 void LayerManagerComposite::InvalidateDebugOverlay(nsIntRegion& aInvalidRegion,
533 const IntRect& aBounds) {
534 bool drawFps = gfxPrefs::LayersDrawFPS();
535 bool drawFrameColorBars = gfxPrefs::CompositorDrawColorBars();
536
537 if (drawFps) {
538 aInvalidRegion.Or(aInvalidRegion, nsIntRect(0, 0, 650, 400));
539 }
540 if (drawFrameColorBars) {
541 aInvalidRegion.Or(aInvalidRegion, nsIntRect(0, 0, 10, aBounds.Height()));
542 }
543
544 #ifdef USE_SKIA
545 bool drawPaintTimes = gfxPrefs::AlwaysPaint();
546 if (drawPaintTimes) {
547 aInvalidRegion.Or(aInvalidRegion, nsIntRect(PaintCounter::GetPaintRect()));
548 }
549 #endif
550 }
551
552 #ifdef USE_SKIA
DrawPaintTimes(Compositor * aCompositor)553 void LayerManagerComposite::DrawPaintTimes(Compositor* aCompositor) {
554 if (!mPaintCounter) {
555 mPaintCounter = new PaintCounter();
556 }
557
558 TimeDuration compositeTime = TimeStamp::Now() - mRenderStartTime;
559 mPaintCounter->Draw(aCompositor, mLastPaintTime, compositeTime);
560 }
561 #endif
562
563 static uint16_t sFrameCount = 0;
RenderDebugOverlay(const IntRect & aBounds)564 void LayerManagerComposite::RenderDebugOverlay(const IntRect& aBounds) {
565 bool drawFps = gfxPrefs::LayersDrawFPS();
566 bool drawFrameColorBars = gfxPrefs::CompositorDrawColorBars();
567
568 // Don't draw diagnostic overlays if we want to snapshot the output.
569 if (mTarget) {
570 return;
571 }
572
573 if (drawFps) {
574 float alpha = 1;
575 #ifdef ANDROID
576 // Draw a translation delay warning overlay
577 int width;
578 int border;
579
580 TimeStamp now = TimeStamp::Now();
581 if (!mWarnTime.IsNull() &&
582 (now - mWarnTime).ToMilliseconds() < kVisualWarningDuration) {
583 EffectChain effects;
584
585 // Black blorder
586 border = 4;
587 width = 6;
588 effects.mPrimaryEffect = new EffectSolidColor(gfx::Color(0, 0, 0, 1));
589 mCompositor->DrawQuad(
590 gfx::Rect(border, border, aBounds.Width() - 2 * border, width),
591 aBounds, effects, alpha, gfx::Matrix4x4());
592 mCompositor->DrawQuad(gfx::Rect(border, aBounds.Height() - border - width,
593 aBounds.Width() - 2 * border, width),
594 aBounds, effects, alpha, gfx::Matrix4x4());
595 mCompositor->DrawQuad(
596 gfx::Rect(border, border + width, width,
597 aBounds.Height() - 2 * border - width * 2),
598 aBounds, effects, alpha, gfx::Matrix4x4());
599 mCompositor->DrawQuad(
600 gfx::Rect(aBounds.Width() - border - width, border + width, width,
601 aBounds.Height() - 2 * border - 2 * width),
602 aBounds, effects, alpha, gfx::Matrix4x4());
603
604 // Content
605 border = 5;
606 width = 4;
607 effects.mPrimaryEffect =
608 new EffectSolidColor(gfx::Color(1, 1.f - mWarningLevel, 0, 1));
609 mCompositor->DrawQuad(
610 gfx::Rect(border, border, aBounds.Width() - 2 * border, width),
611 aBounds, effects, alpha, gfx::Matrix4x4());
612 mCompositor->DrawQuad(gfx::Rect(border, aBounds.height - border - width,
613 aBounds.Width() - 2 * border, width),
614 aBounds, effects, alpha, gfx::Matrix4x4());
615 mCompositor->DrawQuad(
616 gfx::Rect(border, border + width, width,
617 aBounds.Height() - 2 * border - width * 2),
618 aBounds, effects, alpha, gfx::Matrix4x4());
619 mCompositor->DrawQuad(
620 gfx::Rect(aBounds.Width() - border - width, border + width, width,
621 aBounds.Height() - 2 * border - 2 * width),
622 aBounds, effects, alpha, gfx::Matrix4x4());
623 SetDebugOverlayWantsNextFrame(true);
624 }
625 #endif
626
627 GPUStats stats;
628 stats.mScreenPixels = mRenderBounds.Width() * mRenderBounds.Height();
629 mCompositor->GetFrameStats(&stats);
630
631 std::string text = mDiagnostics->GetFrameOverlayString(stats);
632 mTextRenderer->RenderText(mCompositor, text, IntPoint(2, 5), Matrix4x4(),
633 24, 600, TextRenderer::FontType::FixedWidth);
634
635 if (mUnusedApzTransformWarning) {
636 // If we have an unused APZ transform on this composite, draw a 20x20 red
637 // box in the top-right corner
638 EffectChain effects;
639 effects.mPrimaryEffect = new EffectSolidColor(gfx::Color(1, 0, 0, 1));
640 mCompositor->DrawQuad(gfx::Rect(aBounds.Width() - 20, 0, 20, 20), aBounds,
641 effects, alpha, gfx::Matrix4x4());
642
643 mUnusedApzTransformWarning = false;
644 SetDebugOverlayWantsNextFrame(true);
645 }
646 if (mDisabledApzWarning) {
647 // If we have a disabled APZ on this composite, draw a 20x20 yellow box
648 // in the top-right corner, to the left of the unused-apz-transform
649 // warning box
650 EffectChain effects;
651 effects.mPrimaryEffect = new EffectSolidColor(gfx::Color(1, 1, 0, 1));
652 mCompositor->DrawQuad(gfx::Rect(aBounds.Width() - 40, 0, 20, 20), aBounds,
653 effects, alpha, gfx::Matrix4x4());
654
655 mDisabledApzWarning = false;
656 SetDebugOverlayWantsNextFrame(true);
657 }
658 }
659
660 if (drawFrameColorBars) {
661 gfx::IntRect sideRect(0, 0, 10, aBounds.Height());
662
663 EffectChain effects;
664 effects.mPrimaryEffect =
665 new EffectSolidColor(gfxUtils::GetColorForFrameNumber(sFrameCount));
666 mCompositor->DrawQuad(Rect(sideRect), sideRect, effects, 1.0,
667 gfx::Matrix4x4());
668 }
669
670 if (drawFrameColorBars) {
671 // We intentionally overflow at 2^16.
672 sFrameCount++;
673 }
674
675 #ifdef USE_SKIA
676 bool drawPaintTimes = gfxPrefs::AlwaysPaint();
677 if (drawPaintTimes) {
678 DrawPaintTimes(mCompositor);
679 }
680 #endif
681 }
682
683 RefPtr<CompositingRenderTarget>
PushGroupForLayerEffects()684 LayerManagerComposite::PushGroupForLayerEffects() {
685 // This is currently true, so just making sure that any new use of this
686 // method is flagged for investigation
687 MOZ_ASSERT(gfxPrefs::LayersEffectInvert() ||
688 gfxPrefs::LayersEffectGrayscale() ||
689 gfxPrefs::LayersEffectContrast() != 0.0);
690
691 RefPtr<CompositingRenderTarget> previousTarget =
692 mCompositor->GetCurrentRenderTarget();
693 // make our render target the same size as the destination target
694 // so that we don't have to change size if the drawing area changes.
695 IntRect rect(previousTarget->GetOrigin(), previousTarget->GetSize());
696 // XXX: I'm not sure if this is true or not...
697 MOZ_ASSERT(rect.IsEqualXY(0, 0));
698 if (!mTwoPassTmpTarget ||
699 mTwoPassTmpTarget->GetSize() != previousTarget->GetSize() ||
700 mTwoPassTmpTarget->GetOrigin() != previousTarget->GetOrigin()) {
701 mTwoPassTmpTarget = mCompositor->CreateRenderTarget(rect, INIT_MODE_NONE);
702 }
703 MOZ_ASSERT(mTwoPassTmpTarget);
704 mCompositor->SetRenderTarget(mTwoPassTmpTarget);
705 return previousTarget;
706 }
PopGroupForLayerEffects(RefPtr<CompositingRenderTarget> aPreviousTarget,IntRect aClipRect,bool aGrayscaleEffect,bool aInvertEffect,float aContrastEffect)707 void LayerManagerComposite::PopGroupForLayerEffects(
708 RefPtr<CompositingRenderTarget> aPreviousTarget, IntRect aClipRect,
709 bool aGrayscaleEffect, bool aInvertEffect, float aContrastEffect) {
710 MOZ_ASSERT(mTwoPassTmpTarget);
711
712 // This is currently true, so just making sure that any new use of this
713 // method is flagged for investigation
714 MOZ_ASSERT(aInvertEffect || aGrayscaleEffect || aContrastEffect != 0.0);
715
716 mCompositor->SetRenderTarget(aPreviousTarget);
717
718 EffectChain effectChain(RootLayer());
719 Matrix5x4 effectMatrix;
720 if (aGrayscaleEffect) {
721 // R' = G' = B' = luminance
722 // R' = 0.2126*R + 0.7152*G + 0.0722*B
723 // G' = 0.2126*R + 0.7152*G + 0.0722*B
724 // B' = 0.2126*R + 0.7152*G + 0.0722*B
725 Matrix5x4 grayscaleMatrix(0.2126f, 0.2126f, 0.2126f, 0, 0.7152f, 0.7152f,
726 0.7152f, 0, 0.0722f, 0.0722f, 0.0722f, 0, 0, 0, 0,
727 1, 0, 0, 0, 0);
728 effectMatrix = grayscaleMatrix;
729 }
730
731 if (aInvertEffect) {
732 // R' = 1 - R
733 // G' = 1 - G
734 // B' = 1 - B
735 Matrix5x4 colorInvertMatrix(-1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0,
736 1, 1, 1, 1, 0);
737 effectMatrix = effectMatrix * colorInvertMatrix;
738 }
739
740 if (aContrastEffect != 0.0) {
741 // Multiplying with:
742 // R' = (1 + c) * (R - 0.5) + 0.5
743 // G' = (1 + c) * (G - 0.5) + 0.5
744 // B' = (1 + c) * (B - 0.5) + 0.5
745 float cP1 = aContrastEffect + 1;
746 float hc = 0.5 * aContrastEffect;
747 Matrix5x4 contrastMatrix(cP1, 0, 0, 0, 0, cP1, 0, 0, 0, 0, cP1, 0, 0, 0, 0,
748 1, -hc, -hc, -hc, 0);
749 effectMatrix = effectMatrix * contrastMatrix;
750 }
751
752 effectChain.mPrimaryEffect = new EffectRenderTarget(mTwoPassTmpTarget);
753 effectChain.mSecondaryEffects[EffectTypes::COLOR_MATRIX] =
754 new EffectColorMatrix(effectMatrix);
755
756 mCompositor->DrawQuad(Rect(Point(0, 0), Size(mTwoPassTmpTarget->GetSize())),
757 aClipRect, effectChain, 1., Matrix4x4());
758 }
759
760 // Used to clear the 'mLayerComposited' flag at the beginning of each Render().
ClearLayerFlags(Layer * aLayer)761 static void ClearLayerFlags(Layer* aLayer) {
762 ForEachNode<ForwardIterator>(aLayer, [](Layer* layer) {
763 if (layer->AsHostLayer()) {
764 static_cast<LayerComposite*>(layer->AsHostLayer())
765 ->SetLayerComposited(false);
766 }
767 });
768 }
769
770 #if defined(MOZ_WIDGET_ANDROID)
771 class ScopedCompositorRenderOffset {
772 public:
ScopedCompositorRenderOffset(CompositorOGL * aCompositor,const ScreenPoint & aOffset)773 ScopedCompositorRenderOffset(CompositorOGL* aCompositor,
774 const ScreenPoint& aOffset)
775 : mCompositor(aCompositor),
776 mOriginalOffset(mCompositor->GetScreenRenderOffset()),
777 mOriginalProjection(mCompositor->GetProjMatrix()) {
778 ScreenPoint offset(mOriginalOffset.x + aOffset.x,
779 mOriginalOffset.y + aOffset.y);
780 mCompositor->SetScreenRenderOffset(offset);
781 // Calling CompositorOGL::SetScreenRenderOffset does not affect the
782 // projection matrix so adjust that as well.
783 gfx::Matrix4x4 mat = mOriginalProjection;
784 mat.PreTranslate(aOffset.x, aOffset.y, 0.0f);
785 mCompositor->SetProjMatrix(mat);
786 }
~ScopedCompositorRenderOffset()787 ~ScopedCompositorRenderOffset() {
788 mCompositor->SetScreenRenderOffset(mOriginalOffset);
789 mCompositor->SetProjMatrix(mOriginalProjection);
790 }
791
792 private:
793 CompositorOGL* const mCompositor;
794 const ScreenPoint mOriginalOffset;
795 const gfx::Matrix4x4 mOriginalProjection;
796 };
797 #endif // defined(MOZ_WIDGET_ANDROID)
798
Render(const nsIntRegion & aInvalidRegion,const nsIntRegion & aOpaqueRegion)799 void LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion,
800 const nsIntRegion& aOpaqueRegion) {
801 AUTO_PROFILER_LABEL("LayerManagerComposite::Render", GRAPHICS);
802
803 if (mDestroyed || !mCompositor || mCompositor->IsDestroyed()) {
804 NS_WARNING("Call on destroyed layer manager");
805 return;
806 }
807
808 ClearLayerFlags(mRoot);
809
810 // At this time, it doesn't really matter if these preferences change
811 // during the execution of the function; we should be safe in all
812 // permutations. However, may as well just get the values onces and
813 // then use them, just in case the consistency becomes important in
814 // the future.
815 bool invertVal = gfxPrefs::LayersEffectInvert();
816 bool grayscaleVal = gfxPrefs::LayersEffectGrayscale();
817 float contrastVal = gfxPrefs::LayersEffectContrast();
818 bool haveLayerEffects = (invertVal || grayscaleVal || contrastVal != 0.0);
819
820 // Set LayerScope begin/end frame
821 LayerScopeAutoFrame frame(PR_Now());
822
823 // Dump to console
824 if (gfxPrefs::LayersDump()) {
825 this->Dump(/* aSorted= */ true);
826 }
827
828 // Dump to LayerScope Viewer
829 if (LayerScope::CheckSendable()) {
830 // Create a LayersPacket, dump Layers into it and transfer the
831 // packet('s ownership) to LayerScope.
832 auto packet = MakeUnique<layerscope::Packet>();
833 layerscope::LayersPacket* layersPacket = packet->mutable_layers();
834 this->Dump(layersPacket);
835 LayerScope::SendLayerDump(Move(packet));
836 }
837
838 mozilla::widget::WidgetRenderingContext widgetContext;
839 #if defined(XP_MACOSX)
840 widgetContext.mLayerManager = this;
841 #elif defined(MOZ_WIDGET_ANDROID)
842 widgetContext.mCompositor = GetCompositor();
843 #endif
844
845 {
846 AUTO_PROFILER_LABEL("LayerManagerComposite::Render:Prerender", GRAPHICS);
847
848 if (!mCompositor->GetWidget()->PreRender(&widgetContext)) {
849 return;
850 }
851 }
852
853 ParentLayerIntRect clipRect;
854 IntRect bounds(mRenderBounds.X(), mRenderBounds.Y(), mRenderBounds.Width(),
855 mRenderBounds.Height());
856 IntRect actualBounds;
857
858 CompositorBench(mCompositor, bounds);
859
860 MOZ_ASSERT(mRoot->GetOpacity() == 1);
861 #if defined(MOZ_WIDGET_ANDROID)
862 LayerMetricsWrapper wrapper = GetRootContentLayer();
863 if (wrapper) {
864 mCompositor->SetClearColor(wrapper.Metadata().GetBackgroundColor());
865 } else {
866 mCompositor->SetClearColorToDefault();
867 }
868 #endif
869 if (mRoot->GetClipRect()) {
870 clipRect = *mRoot->GetClipRect();
871 IntRect rect(clipRect.X(), clipRect.Y(), clipRect.Width(),
872 clipRect.Height());
873 mCompositor->BeginFrame(aInvalidRegion, &rect, bounds, aOpaqueRegion,
874 nullptr, &actualBounds);
875 } else {
876 gfx::IntRect rect;
877 mCompositor->BeginFrame(aInvalidRegion, nullptr, bounds, aOpaqueRegion,
878 &rect, &actualBounds);
879 clipRect =
880 ParentLayerIntRect(rect.X(), rect.Y(), rect.Width(), rect.Height());
881 }
882 #if defined(MOZ_WIDGET_ANDROID)
883 ScreenCoord offset = GetContentShiftForToolbar();
884 ScopedCompositorRenderOffset scopedOffset(mCompositor->AsCompositorOGL(),
885 ScreenPoint(0.0f, offset));
886 #endif
887
888 if (actualBounds.IsEmpty()) {
889 mCompositor->GetWidget()->PostRender(&widgetContext);
890 return;
891 }
892
893 // Allow widget to render a custom background.
894 mCompositor->GetWidget()->DrawWindowUnderlay(
895 &widgetContext, LayoutDeviceIntRect::FromUnknownRect(actualBounds));
896
897 RefPtr<CompositingRenderTarget> previousTarget;
898 if (haveLayerEffects) {
899 previousTarget = PushGroupForLayerEffects();
900 } else {
901 mTwoPassTmpTarget = nullptr;
902 }
903
904 // Render our layers.
905 {
906 Diagnostics::Record record(mRenderStartTime);
907 RootLayer()->Prepare(ViewAs<RenderTargetPixel>(
908 clipRect, PixelCastJustification::RenderTargetIsParentLayerForRoot));
909 if (record.Recording()) {
910 mDiagnostics->RecordPrepareTime(record.Duration());
911 }
912 }
913 // Execute draw commands.
914 {
915 Diagnostics::Record record;
916 RootLayer()->RenderLayer(clipRect.ToUnknownRect(), Nothing());
917 if (record.Recording()) {
918 mDiagnostics->RecordCompositeTime(record.Duration());
919 }
920 }
921 RootLayer()->Cleanup();
922
923 if (!mRegionToClear.IsEmpty()) {
924 for (auto iter = mRegionToClear.RectIter(); !iter.Done(); iter.Next()) {
925 const IntRect& r = iter.Get();
926 mCompositor->ClearRect(Rect(r.X(), r.Y(), r.Width(), r.Height()));
927 }
928 }
929
930 if (mTwoPassTmpTarget) {
931 MOZ_ASSERT(haveLayerEffects);
932 PopGroupForLayerEffects(previousTarget, clipRect.ToUnknownRect(),
933 grayscaleVal, invertVal, contrastVal);
934 }
935
936 // Allow widget to render a custom foreground.
937 mCompositor->GetWidget()->DrawWindowOverlay(
938 &widgetContext, LayoutDeviceIntRect::FromUnknownRect(actualBounds));
939
940 mCompositor->NormalDrawingDone();
941
942 #if defined(MOZ_WIDGET_ANDROID)
943 // Depending on the content shift the toolbar may be rendered on top of
944 // some of the content so it must be rendered after the content.
945 RenderToolbar();
946 HandlePixelsTarget();
947 #endif // defined(MOZ_WIDGET_ANDROID)
948
949 // Debugging
950 RenderDebugOverlay(actualBounds);
951
952 {
953 AUTO_PROFILER_LABEL("LayerManagerComposite::Render:EndFrame", GRAPHICS);
954
955 mCompositor->EndFrame();
956
957 // Call after EndFrame()
958 mCompositor->SetDispAcquireFence(mRoot);
959 }
960
961 mCompositor->GetWidget()->PostRender(&widgetContext);
962
963 RecordFrame();
964 }
965
966 #if defined(MOZ_WIDGET_ANDROID)
967 class ScopedCompositorProjMatrix {
968 public:
ScopedCompositorProjMatrix(CompositorOGL * aCompositor,const Matrix4x4 & aProjMatrix)969 ScopedCompositorProjMatrix(CompositorOGL* aCompositor,
970 const Matrix4x4& aProjMatrix)
971 : mCompositor(aCompositor),
972 mOriginalProjMatrix(mCompositor->GetProjMatrix()) {
973 mCompositor->SetProjMatrix(aProjMatrix);
974 }
975
~ScopedCompositorProjMatrix()976 ~ScopedCompositorProjMatrix() {
977 mCompositor->SetProjMatrix(mOriginalProjMatrix);
978 }
979
980 private:
981 CompositorOGL* const mCompositor;
982 const Matrix4x4 mOriginalProjMatrix;
983 };
984
985 class ScopedCompostitorSurfaceSize {
986 public:
ScopedCompostitorSurfaceSize(CompositorOGL * aCompositor,const gfx::IntSize & aSize)987 ScopedCompostitorSurfaceSize(CompositorOGL* aCompositor,
988 const gfx::IntSize& aSize)
989 : mCompositor(aCompositor),
990 mOriginalSize(mCompositor->GetDestinationSurfaceSize()) {
991 mCompositor->SetDestinationSurfaceSize(aSize);
992 }
~ScopedCompostitorSurfaceSize()993 ~ScopedCompostitorSurfaceSize() {
994 mCompositor->SetDestinationSurfaceSize(mOriginalSize);
995 }
996
997 private:
998 CompositorOGL* const mCompositor;
999 const gfx::IntSize mOriginalSize;
1000 };
1001
1002 class ScopedContextSurfaceOverride {
1003 public:
ScopedContextSurfaceOverride(GLContextEGL * aContext,void * aSurface)1004 ScopedContextSurfaceOverride(GLContextEGL* aContext, void* aSurface)
1005 : mContext(aContext) {
1006 MOZ_ASSERT(aSurface);
1007 mContext->SetEGLSurfaceOverride(aSurface);
1008 mContext->MakeCurrent(true);
1009 }
~ScopedContextSurfaceOverride()1010 ~ScopedContextSurfaceOverride() {
1011 mContext->SetEGLSurfaceOverride(EGL_NO_SURFACE);
1012 mContext->MakeCurrent(true);
1013 }
1014
1015 private:
1016 GLContextEGL* const mContext;
1017 };
1018
RenderToPresentationSurface()1019 void LayerManagerComposite::RenderToPresentationSurface() {
1020 if (!mCompositor) {
1021 return;
1022 }
1023
1024 widget::CompositorWidget* const widget = mCompositor->GetWidget();
1025
1026 if (!widget) {
1027 return;
1028 }
1029
1030 ANativeWindow* window = widget->AsAndroid()->GetPresentationANativeWindow();
1031
1032 if (!window) {
1033 return;
1034 }
1035
1036 CompositorOGL* compositor = mCompositor->AsCompositorOGL();
1037 GLContext* gl = compositor->gl();
1038 GLContextEGL* egl = GLContextEGL::Cast(gl);
1039
1040 if (!egl) {
1041 return;
1042 }
1043
1044 EGLSurface surface = widget->AsAndroid()->GetPresentationEGLSurface();
1045
1046 if (!surface) {
1047 // create surface;
1048 surface = egl->CreateCompatibleSurface(window);
1049 if (!surface) {
1050 return;
1051 }
1052
1053 widget->AsAndroid()->SetPresentationEGLSurface(surface);
1054 }
1055
1056 const IntSize windowSize(ANativeWindow_getWidth(window),
1057 ANativeWindow_getHeight(window));
1058
1059 if ((windowSize.width <= 0) || (windowSize.height <= 0)) {
1060 return;
1061 }
1062
1063 ScreenRotation rotation = compositor->GetScreenRotation();
1064
1065 const int actualWidth = windowSize.width;
1066 const int actualHeight = windowSize.height;
1067
1068 const gfx::IntSize originalSize = compositor->GetDestinationSurfaceSize();
1069 const nsIntRect originalRect =
1070 nsIntRect(0, 0, originalSize.width, originalSize.height);
1071
1072 int pageWidth = originalSize.width;
1073 int pageHeight = originalSize.height;
1074 if (rotation == ROTATION_90 || rotation == ROTATION_270) {
1075 pageWidth = originalSize.height;
1076 pageHeight = originalSize.width;
1077 }
1078
1079 float scale = 1.0;
1080
1081 if ((pageWidth > actualWidth) || (pageHeight > actualHeight)) {
1082 const float scaleWidth = (float)actualWidth / (float)pageWidth;
1083 const float scaleHeight = (float)actualHeight / (float)pageHeight;
1084 scale = scaleWidth <= scaleHeight ? scaleWidth : scaleHeight;
1085 }
1086
1087 const gfx::IntSize actualSize(actualWidth, actualHeight);
1088 ScopedCompostitorSurfaceSize overrideSurfaceSize(compositor, actualSize);
1089
1090 const ScreenPoint offset((actualWidth - (int)(scale * pageWidth)) / 2, 0);
1091 ScopedContextSurfaceOverride overrideSurface(egl, surface);
1092
1093 Matrix viewMatrix = ComputeTransformForRotation(originalRect, rotation);
1094 viewMatrix.Invert(); // unrotate
1095 viewMatrix.PostScale(scale, scale);
1096 viewMatrix.PostTranslate(offset.x, offset.y);
1097 Matrix4x4 matrix = Matrix4x4::From2D(viewMatrix);
1098
1099 mRoot->ComputeEffectiveTransforms(matrix);
1100 nsIntRegion opaque;
1101 PostProcessLayers(opaque);
1102
1103 nsIntRegion invalid;
1104 IntRect bounds = IntRect::Truncate(0, 0, scale * pageWidth, actualHeight);
1105 IntRect rect, actualBounds;
1106 MOZ_ASSERT(mRoot->GetOpacity() == 1);
1107 mCompositor->BeginFrame(invalid, nullptr, bounds, nsIntRegion(), &rect,
1108 &actualBounds);
1109
1110 // The Java side of Fennec sets a scissor rect that accounts for
1111 // chrome such as the URL bar. Override that so that the entire frame buffer
1112 // is cleared.
1113 ScopedScissorRect scissorRect(egl, 0, 0, actualWidth, actualHeight);
1114 egl->fClearColor(0.0, 0.0, 0.0, 0.0);
1115 egl->fClear(LOCAL_GL_COLOR_BUFFER_BIT);
1116
1117 const IntRect clipRect = IntRect::Truncate(0, 0, actualWidth, actualHeight);
1118
1119 RootLayer()->Prepare(RenderTargetIntRect::FromUnknownRect(clipRect));
1120 RootLayer()->RenderLayer(clipRect, Nothing());
1121
1122 mCompositor->EndFrame();
1123 }
1124
GetContentShiftForToolbar()1125 ScreenCoord LayerManagerComposite::GetContentShiftForToolbar() {
1126 ScreenCoord result(0.0f);
1127 // If GetTargetContext return is not null we are not drawing to the screen so
1128 // there will not be any content offset.
1129 if (mCompositor->GetTargetContext() != nullptr) {
1130 return result;
1131 }
1132
1133 if (CompositorBridgeParent* bridge =
1134 mCompositor->GetCompositorBridgeParent()) {
1135 AndroidDynamicToolbarAnimator* animator =
1136 bridge->GetAndroidDynamicToolbarAnimator();
1137 MOZ_RELEASE_ASSERT(animator);
1138 result.value = (float)animator->GetCurrentContentOffset().value;
1139 }
1140 return result;
1141 }
1142
RenderToolbar()1143 void LayerManagerComposite::RenderToolbar() {
1144 // If GetTargetContext return is not null we are not drawing to the screen so
1145 // don't draw the toolbar.
1146 if (mCompositor->GetTargetContext() != nullptr) {
1147 return;
1148 }
1149
1150 if (CompositorBridgeParent* bridge =
1151 mCompositor->GetCompositorBridgeParent()) {
1152 AndroidDynamicToolbarAnimator* animator =
1153 bridge->GetAndroidDynamicToolbarAnimator();
1154 MOZ_RELEASE_ASSERT(animator);
1155
1156 animator->UpdateToolbarSnapshotTexture(mCompositor->AsCompositorOGL());
1157
1158 int32_t toolbarHeight = animator->GetCurrentToolbarHeight();
1159 if (toolbarHeight == 0) {
1160 return;
1161 }
1162
1163 EffectChain effects;
1164 effects.mPrimaryEffect = animator->GetToolbarEffect();
1165
1166 // If GetToolbarEffect returns null, nothing is rendered for the static
1167 // snapshot of the toolbar. If the real toolbar chrome is not covering this
1168 // portion of the surface, the clear color of the surface will be visible.
1169 // On Android the clear color is the background color of the page.
1170 if (effects.mPrimaryEffect) {
1171 ScopedCompositorRenderOffset toolbarOffset(
1172 mCompositor->AsCompositorOGL(),
1173 ScreenPoint(0.0f, -animator->GetCurrentContentOffset()));
1174 mCompositor->DrawQuad(gfx::Rect(0, 0, mRenderBounds.width, toolbarHeight),
1175 IntRect(0, 0, mRenderBounds.width, toolbarHeight),
1176 effects, 1.0, gfx::Matrix4x4());
1177 }
1178 }
1179 }
1180
1181 // Used by robocop tests to get a snapshot of the frame buffer.
HandlePixelsTarget()1182 void LayerManagerComposite::HandlePixelsTarget() {
1183 if (!mScreenPixelsTarget) {
1184 return;
1185 }
1186
1187 int32_t bufferWidth = mRenderBounds.width;
1188 int32_t bufferHeight = mRenderBounds.height;
1189 ipc::Shmem mem;
1190 if (!mScreenPixelsTarget->AllocPixelBuffer(
1191 bufferWidth * bufferHeight * sizeof(uint32_t), &mem)) {
1192 // Failed to alloc shmem, Just bail out.
1193 return;
1194 }
1195 CompositorOGL* compositor = mCompositor->AsCompositorOGL();
1196 GLContext* gl = compositor->gl();
1197 MOZ_ASSERT(gl);
1198 gl->fReadPixels(0, 0, bufferWidth, bufferHeight, LOCAL_GL_RGBA,
1199 LOCAL_GL_UNSIGNED_BYTE, mem.get<uint8_t>());
1200 Unused << mScreenPixelsTarget->SendScreenPixels(
1201 mem, ScreenIntSize(bufferWidth, bufferHeight));
1202 mScreenPixelsTarget = nullptr;
1203 }
1204 #endif
1205
1206 class BorderLayerComposite : public BorderLayer, public LayerComposite {
1207 public:
BorderLayerComposite(LayerManagerComposite * aManager)1208 explicit BorderLayerComposite(LayerManagerComposite* aManager)
1209 : BorderLayer(aManager, nullptr), LayerComposite(aManager) {
1210 MOZ_COUNT_CTOR(BorderLayerComposite);
1211 mImplData = static_cast<LayerComposite*>(this);
1212 }
1213
1214 protected:
~BorderLayerComposite()1215 ~BorderLayerComposite() {
1216 MOZ_COUNT_DTOR(BorderLayerComposite);
1217 Destroy();
1218 }
1219
1220 public:
1221 // LayerComposite Implementation
GetLayer()1222 virtual Layer* GetLayer() override { return this; }
1223
SetLayerManager(HostLayerManager * aManager)1224 virtual void SetLayerManager(HostLayerManager* aManager) override {
1225 LayerComposite::SetLayerManager(aManager);
1226 mManager = aManager;
1227 }
1228
Destroy()1229 virtual void Destroy() override { mDestroyed = true; }
1230
RenderLayer(const gfx::IntRect & aClipRect,const Maybe<gfx::Polygon> & aGeometry)1231 virtual void RenderLayer(const gfx::IntRect& aClipRect,
1232 const Maybe<gfx::Polygon>& aGeometry) override {}
CleanupResources()1233 virtual void CleanupResources() override{};
1234
GenEffectChain(EffectChain & aEffect)1235 virtual void GenEffectChain(EffectChain& aEffect) override {}
1236
GetCompositableHost()1237 CompositableHost* GetCompositableHost() override { return nullptr; }
1238
AsHostLayer()1239 virtual HostLayer* AsHostLayer() override { return this; }
1240
Name() const1241 virtual const char* Name() const override { return "BorderLayerComposite"; }
1242 };
1243
CreatePaintedLayer()1244 already_AddRefed<PaintedLayer> LayerManagerComposite::CreatePaintedLayer() {
1245 if (mDestroyed) {
1246 NS_WARNING("Call on destroyed layer manager");
1247 return nullptr;
1248 }
1249 return RefPtr<PaintedLayer>(new PaintedLayerComposite(this)).forget();
1250 }
1251
CreateContainerLayer()1252 already_AddRefed<ContainerLayer> LayerManagerComposite::CreateContainerLayer() {
1253 if (mDestroyed) {
1254 NS_WARNING("Call on destroyed layer manager");
1255 return nullptr;
1256 }
1257 return RefPtr<ContainerLayer>(new ContainerLayerComposite(this)).forget();
1258 }
1259
CreateImageLayer()1260 already_AddRefed<ImageLayer> LayerManagerComposite::CreateImageLayer() {
1261 if (mDestroyed) {
1262 NS_WARNING("Call on destroyed layer manager");
1263 return nullptr;
1264 }
1265 return RefPtr<ImageLayer>(new ImageLayerComposite(this)).forget();
1266 }
1267
CreateColorLayer()1268 already_AddRefed<ColorLayer> LayerManagerComposite::CreateColorLayer() {
1269 if (LayerManagerComposite::mDestroyed) {
1270 NS_WARNING("Call on destroyed layer manager");
1271 return nullptr;
1272 }
1273 return RefPtr<ColorLayer>(new ColorLayerComposite(this)).forget();
1274 }
1275
CreateCanvasLayer()1276 already_AddRefed<CanvasLayer> LayerManagerComposite::CreateCanvasLayer() {
1277 if (LayerManagerComposite::mDestroyed) {
1278 NS_WARNING("Call on destroyed layer manager");
1279 return nullptr;
1280 }
1281 return RefPtr<CanvasLayer>(new CanvasLayerComposite(this)).forget();
1282 }
1283
CreateRefLayer()1284 already_AddRefed<RefLayer> LayerManagerComposite::CreateRefLayer() {
1285 if (LayerManagerComposite::mDestroyed) {
1286 NS_WARNING("Call on destroyed layer manager");
1287 return nullptr;
1288 }
1289 return RefPtr<RefLayer>(new RefLayerComposite(this)).forget();
1290 }
1291
CreateBorderLayer()1292 already_AddRefed<BorderLayer> LayerManagerComposite::CreateBorderLayer() {
1293 if (LayerManagerComposite::mDestroyed) {
1294 NS_WARNING("Call on destroyed layer manager");
1295 return nullptr;
1296 }
1297 return RefPtr<BorderLayer>(new BorderLayerComposite(this)).forget();
1298 }
1299
AutoAddMaskEffect(Layer * aMaskLayer,EffectChain & aEffects)1300 LayerManagerComposite::AutoAddMaskEffect::AutoAddMaskEffect(
1301 Layer* aMaskLayer, EffectChain& aEffects)
1302 : mCompositable(nullptr), mFailed(false) {
1303 if (!aMaskLayer) {
1304 return;
1305 }
1306
1307 mCompositable = ToLayerComposite(aMaskLayer)->GetCompositableHost();
1308 if (!mCompositable) {
1309 NS_WARNING("Mask layer with no compositable host");
1310 mFailed = true;
1311 return;
1312 }
1313
1314 if (!mCompositable->AddMaskEffect(aEffects,
1315 aMaskLayer->GetEffectiveTransform())) {
1316 mCompositable = nullptr;
1317 mFailed = true;
1318 }
1319 }
1320
~AutoAddMaskEffect()1321 LayerManagerComposite::AutoAddMaskEffect::~AutoAddMaskEffect() {
1322 if (!mCompositable) {
1323 return;
1324 }
1325
1326 mCompositable->RemoveMaskEffect();
1327 }
1328
IsCompositingToScreen() const1329 bool LayerManagerComposite::IsCompositingToScreen() const {
1330 if (!mCompositor) {
1331 return true;
1332 }
1333 return !mCompositor->GetTargetContext();
1334 }
1335
LayerComposite(LayerManagerComposite * aManager)1336 LayerComposite::LayerComposite(LayerManagerComposite* aManager)
1337 : HostLayer(aManager),
1338 mCompositeManager(aManager),
1339 mCompositor(aManager->GetCompositor()),
1340 mDestroyed(false),
1341 mLayerComposited(false) {}
1342
~LayerComposite()1343 LayerComposite::~LayerComposite() {}
1344
Destroy()1345 void LayerComposite::Destroy() {
1346 if (!mDestroyed) {
1347 mDestroyed = true;
1348 CleanupResources();
1349 }
1350 }
1351
AddBlendModeEffect(EffectChain & aEffectChain)1352 void LayerComposite::AddBlendModeEffect(EffectChain& aEffectChain) {
1353 gfx::CompositionOp blendMode = GetLayer()->GetEffectiveMixBlendMode();
1354 if (blendMode == gfx::CompositionOp::OP_OVER) {
1355 return;
1356 }
1357
1358 aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE] =
1359 new EffectBlendMode(blendMode);
1360 }
1361
CanUseCanvasLayerForSize(const IntSize & aSize)1362 bool LayerManagerComposite::CanUseCanvasLayerForSize(const IntSize& aSize) {
1363 return mCompositor->CanUseCanvasLayerForSize(
1364 gfx::IntSize(aSize.width, aSize.height));
1365 }
1366
NotifyShadowTreeTransaction()1367 void LayerManagerComposite::NotifyShadowTreeTransaction() {
1368 if (gfxPrefs::LayersDrawFPS()) {
1369 mDiagnostics->AddTxnFrame();
1370 }
1371 }
1372
SetLayerManager(HostLayerManager * aManager)1373 void LayerComposite::SetLayerManager(HostLayerManager* aManager) {
1374 HostLayer::SetLayerManager(aManager);
1375 mCompositeManager = static_cast<LayerManagerComposite*>(aManager);
1376 mCompositor = mCompositeManager->GetCompositor();
1377 }
1378
AsyncPanZoomEnabled() const1379 bool LayerManagerComposite::AsyncPanZoomEnabled() const {
1380 if (CompositorBridgeParent* bridge =
1381 mCompositor->GetCompositorBridgeParent()) {
1382 return bridge->GetOptions().UseAPZ();
1383 }
1384 return false;
1385 }
1386
AlwaysScheduleComposite() const1387 bool LayerManagerComposite::AlwaysScheduleComposite() const {
1388 return !!(mCompositor->GetDiagnosticTypes() & DiagnosticTypes::FLASH_BORDERS);
1389 }
1390
GetFullyRenderedRegion()1391 nsIntRegion LayerComposite::GetFullyRenderedRegion() {
1392 if (TiledContentHost* tiled =
1393 GetCompositableHost() ? GetCompositableHost()->AsTiledContentHost()
1394 : nullptr) {
1395 nsIntRegion shadowVisibleRegion =
1396 GetShadowVisibleRegion().ToUnknownRegion();
1397 // Discard the region which hasn't been drawn yet when doing
1398 // progressive drawing. Note that if the shadow visible region
1399 // shrunk the tiled valig region may not have discarded this yet.
1400 shadowVisibleRegion.And(shadowVisibleRegion, tiled->GetValidRegion());
1401 return shadowVisibleRegion;
1402 } else {
1403 return GetShadowVisibleRegion().ToUnknownRegion();
1404 }
1405 }
1406
GetShadowTransform()1407 Matrix4x4 HostLayer::GetShadowTransform() {
1408 Matrix4x4 transform = mShadowTransform;
1409 Layer* layer = GetLayer();
1410
1411 transform.PostScale(layer->GetPostXScale(), layer->GetPostYScale(), 1.0f);
1412 if (const ContainerLayer* c = layer->AsContainerLayer()) {
1413 transform.PreScale(c->GetPreXScale(), c->GetPreYScale(), 1.0f);
1414 }
1415
1416 return transform;
1417 }
1418
TransformRect(const LayerIntRect & aRect,const Matrix4x4 & aTransform)1419 static LayerIntRect TransformRect(const LayerIntRect& aRect,
1420 const Matrix4x4& aTransform) {
1421 if (aRect.IsEmpty()) {
1422 return LayerIntRect();
1423 }
1424
1425 Rect rect(aRect.X(), aRect.Y(), aRect.Width(), aRect.Height());
1426 rect = aTransform.TransformAndClipBounds(rect, Rect::MaxIntRect());
1427 rect.RoundOut();
1428
1429 IntRect intRect;
1430 if (!gfxUtils::GfxRectToIntRect(ThebesRect(rect), &intRect)) {
1431 return LayerIntRect();
1432 }
1433
1434 return ViewAs<LayerPixel>(intRect);
1435 }
1436
AddTransformedRegion(LayerIntRegion & aDest,const LayerIntRegion & aSource,const Matrix4x4 & aTransform)1437 static void AddTransformedRegion(LayerIntRegion& aDest,
1438 const LayerIntRegion& aSource,
1439 const Matrix4x4& aTransform) {
1440 for (auto iter = aSource.RectIter(); !iter.Done(); iter.Next()) {
1441 aDest.Or(aDest, TransformRect(iter.Get(), aTransform));
1442 }
1443 aDest.SimplifyOutward(20);
1444 }
1445
1446 // Async animations can move child layers without updating our visible region.
1447 // PostProcessLayers will recompute visible regions for layers with an
1448 // intermediate surface, but otherwise we need to do it now.
ComputeVisibleRegionForChildren(ContainerLayer * aContainer,LayerIntRegion & aResult)1449 void ComputeVisibleRegionForChildren(ContainerLayer* aContainer,
1450 LayerIntRegion& aResult) {
1451 for (Layer* l = aContainer->GetFirstChild(); l; l = l->GetNextSibling()) {
1452 if (l->Extend3DContext()) {
1453 MOZ_ASSERT(l->AsContainerLayer());
1454 ComputeVisibleRegionForChildren(l->AsContainerLayer(), aResult);
1455 } else {
1456 AddTransformedRegion(aResult, l->GetLocalVisibleRegion(),
1457 l->ComputeTransformToPreserve3DRoot());
1458 }
1459 }
1460 }
1461
RecomputeShadowVisibleRegionFromChildren()1462 void HostLayer::RecomputeShadowVisibleRegionFromChildren() {
1463 mShadowVisibleRegion.SetEmpty();
1464 ContainerLayer* container = GetLayer()->AsContainerLayer();
1465 MOZ_ASSERT(container);
1466 if (container) {
1467 ComputeVisibleRegionForChildren(container, mShadowVisibleRegion);
1468 }
1469 }
1470
HasStaleCompositor() const1471 bool LayerComposite::HasStaleCompositor() const {
1472 return mCompositeManager->GetCompositor() != mCompositor;
1473 }
1474
1475 #ifndef MOZ_HAVE_PLATFORM_SPECIFIC_LAYER_BUFFERS
1476
SupportsDirectTexturing()1477 /*static*/ bool LayerManagerComposite::SupportsDirectTexturing() {
1478 return false;
1479 }
1480
PlatformSyncBeforeReplyUpdate()1481 /*static*/ void LayerManagerComposite::PlatformSyncBeforeReplyUpdate() {}
1482
1483 #endif // !defined(MOZ_HAVE_PLATFORM_SPECIFIC_LAYER_BUFFERS)
1484
1485 } // namespace layers
1486 } // namespace mozilla
1487