Coverage Report

Created: 2018-09-25 14:53

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