Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/layers/client/ClientLayerManager.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 "ClientLayerManager.h"
8
#include "GeckoProfiler.h"              // for AUTO_PROFILER_LABEL
9
#include "gfxEnv.h"                     // for gfxEnv
10
#include "gfxPrefs.h"                   // for gfxPrefs::LayersTile...
11
#include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
12
#include "mozilla/Hal.h"
13
#include "mozilla/dom/TabChild.h"       // for TabChild
14
#include "mozilla/dom/TabGroup.h"       // for TabGroup
15
#include "mozilla/hal_sandbox/PHal.h"   // for ScreenConfiguration
16
#include "mozilla/layers/CompositableClient.h"
17
#include "mozilla/layers/CompositorBridgeChild.h" // for CompositorBridgeChild
18
#include "mozilla/layers/FrameUniformityData.h"
19
#include "mozilla/layers/ISurfaceAllocator.h"
20
#include "mozilla/layers/LayersMessages.h"  // for EditReply, etc
21
#include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
22
#include "mozilla/layers/LayerTransactionChild.h"
23
#include "mozilla/layers/PersistentBufferProvider.h"
24
#include "mozilla/layers/SyncObject.h"
25
#include "ClientReadbackLayer.h"        // for ClientReadbackLayer
26
#include "nsAString.h"
27
#include "nsDisplayList.h"
28
#include "nsIWidgetListener.h"
29
#include "nsTArray.h"                   // for AutoTArray
30
#include "nsXULAppAPI.h"                // for XRE_GetProcessType, etc
31
#include "TiledLayerBuffer.h"
32
#include "FrameLayerBuilder.h"          // for FrameLayerbuilder
33
#ifdef MOZ_WIDGET_ANDROID
34
#include "AndroidBridge.h"
35
#include "LayerMetricsWrapper.h"
36
#endif
37
#ifdef XP_WIN
38
#include "mozilla/gfx/DeviceManagerDx.h"
39
#include "gfxDWriteFonts.h"
40
#endif
41
42
namespace mozilla {
43
namespace layers {
44
45
using namespace mozilla::gfx;
46
47
ClientLayerManager::ClientLayerManager(nsIWidget* aWidget)
48
  : mPhase(PHASE_NONE)
49
  , mWidget(aWidget)
50
  , mPaintedLayerCallback(nullptr)
51
  , mPaintedLayerCallbackData(nullptr)
52
  , mLatestTransactionId{0}
53
  , mLastPaintTime(TimeDuration::Forever())
54
  , mTargetRotation(ROTATION_0)
55
  , mRepeatTransaction(false)
56
  , mIsRepeatTransaction(false)
57
  , mTransactionIncomplete(false)
58
  , mCompositorMightResample(false)
59
  , mNeedsComposite(false)
60
  , mQueuedAsyncPaints(false)
61
  , mPaintSequenceNumber(0)
62
  , mForwarder(new ShadowLayerForwarder(this))
63
0
{
64
0
  MOZ_COUNT_CTOR(ClientLayerManager);
65
0
  mMemoryPressureObserver = MemoryPressureObserver::Create(this);
66
0
}
67
68
69
ClientLayerManager::~ClientLayerManager()
70
0
{
71
0
  mMemoryPressureObserver->Unregister();
72
0
  ClearCachedResources();
73
0
  // Stop receiveing AsyncParentMessage at Forwarder.
74
0
  // After the call, the message is directly handled by LayerTransactionChild.
75
0
  // Basically this function should be called in ShadowLayerForwarder's
76
0
  // destructor. But when the destructor is triggered by
77
0
  // CompositorBridgeChild::Destroy(), the destructor can not handle it correctly.
78
0
  // See Bug 1000525.
79
0
  mForwarder->StopReceiveAsyncParentMessge();
80
0
  mRoot = nullptr;
81
0
82
0
  MOZ_COUNT_DTOR(ClientLayerManager);
83
0
}
84
85
void
86
ClientLayerManager::Destroy()
87
0
{
88
0
  // It's important to call ClearCachedResource before Destroy because the
89
0
  // former will early-return if the later has already run.
90
0
  ClearCachedResources();
91
0
  LayerManager::Destroy();
92
0
93
0
  if (mTransactionIdAllocator) {
94
0
    // Make sure to notify the refresh driver just in case it's waiting on a
95
0
    // pending transaction. Do this at the top of the event loop so we don't
96
0
    // cause a paint to occur during compositor shutdown.
97
0
    RefPtr<TransactionIdAllocator> allocator = mTransactionIdAllocator;
98
0
    TransactionId id = mLatestTransactionId;
99
0
100
0
    RefPtr<Runnable> task = NS_NewRunnableFunction(
101
0
      "TransactionIdAllocator::NotifyTransactionCompleted",
102
0
      [allocator, id] () -> void {
103
0
      allocator->NotifyTransactionCompleted(id);
104
0
    });
105
0
    NS_DispatchToMainThread(task.forget());
106
0
  }
107
0
108
0
  // Forget the widget pointer in case we outlive our owning widget.
109
0
  mWidget = nullptr;
110
0
}
111
112
TabGroup*
113
ClientLayerManager::GetTabGroup()
114
0
{
115
0
  if (mWidget) {
116
0
    if (TabChild* tabChild = mWidget->GetOwningTabChild()) {
117
0
      return tabChild->TabGroup();
118
0
    }
119
0
  }
120
0
  return nullptr;
121
0
}
122
123
int32_t
124
ClientLayerManager::GetMaxTextureSize() const
125
0
{
126
0
  return mForwarder->GetMaxTextureSize();
127
0
}
128
129
void
130
ClientLayerManager::SetDefaultTargetConfiguration(BufferMode aDoubleBuffering,
131
                                                  ScreenRotation aRotation)
132
0
{
133
0
  mTargetRotation = aRotation;
134
0
 }
135
136
void
137
ClientLayerManager::SetRoot(Layer* aLayer)
138
0
{
139
0
  if (mRoot != aLayer) {
140
0
    // Have to hold the old root and its children in order to
141
0
    // maintain the same view of the layer tree in this process as
142
0
    // the parent sees.  Otherwise layers can be destroyed
143
0
    // mid-transaction and bad things can happen (v. bug 612573)
144
0
    if (mRoot) {
145
0
      Hold(mRoot);
146
0
    }
147
0
    mForwarder->SetRoot(Hold(aLayer));
148
0
    NS_ASSERTION(aLayer, "Root can't be null");
149
0
    NS_ASSERTION(aLayer->Manager() == this, "Wrong manager");
150
0
    NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
151
0
    mRoot = aLayer;
152
0
  }
153
0
}
154
155
void
156
ClientLayerManager::Mutated(Layer* aLayer)
157
0
{
158
0
  LayerManager::Mutated(aLayer);
159
0
160
0
  NS_ASSERTION(InConstruction() || InDrawing(), "wrong phase");
161
0
  mForwarder->Mutated(Hold(aLayer));
162
0
}
163
164
void
165
ClientLayerManager::MutatedSimple(Layer* aLayer)
166
0
{
167
0
  LayerManager::MutatedSimple(aLayer);
168
0
169
0
  NS_ASSERTION(InConstruction() || InDrawing(), "wrong phase");
170
0
  mForwarder->MutatedSimple(Hold(aLayer));
171
0
}
172
173
already_AddRefed<ReadbackLayer>
174
ClientLayerManager::CreateReadbackLayer()
175
0
{
176
0
  RefPtr<ReadbackLayer> layer = new ClientReadbackLayer(this);
177
0
  return layer.forget();
178
0
}
179
180
bool
181
ClientLayerManager::BeginTransactionWithTarget(gfxContext* aTarget)
182
0
{
183
#ifdef MOZ_DUMP_PAINTING
184
  // When we are dump painting, we expect to be able to read the contents of
185
  // compositable clients from previous paints inside this layer transaction
186
  // before we flush async paints in EndTransactionInternal.
187
  // So to work around this flush async paints now.
188
  if (gfxEnv::DumpPaint()) {
189
    FlushAsyncPaints();
190
  }
191
#endif
192
193
0
  MOZ_ASSERT(mForwarder, "ClientLayerManager::BeginTransaction without forwarder");
194
0
  if (!mForwarder->IPCOpen()) {
195
0
    gfxCriticalNote << "ClientLayerManager::BeginTransaction with IPC channel down. GPU process may have died.";
196
0
    return false;
197
0
  }
198
0
199
0
  mInTransaction = true;
200
0
  mTransactionStart = TimeStamp::Now();
201
0
202
0
#ifdef MOZ_LAYERS_HAVE_LOG
203
0
  MOZ_LAYERS_LOG(("[----- BeginTransaction"));
204
0
  Log();
205
0
#endif
206
0
207
0
  NS_ASSERTION(!InTransaction(), "Nested transactions not allowed");
208
0
  mPhase = PHASE_CONSTRUCTION;
209
0
210
0
  MOZ_ASSERT(mKeepAlive.IsEmpty(), "uncommitted txn?");
211
0
212
0
  // If the last transaction was incomplete (a failed DoEmptyTransaction),
213
0
  // don't signal a new transaction to ShadowLayerForwarder. Carry on adding
214
0
  // to the previous transaction.
215
0
  hal::ScreenOrientation orientation;
216
0
  if (dom::TabChild* window = mWidget->GetOwningTabChild()) {
217
0
    orientation = window->GetOrientation();
218
0
  } else {
219
0
    hal::ScreenConfiguration currentConfig;
220
0
    hal::GetCurrentScreenConfiguration(&currentConfig);
221
0
    orientation = currentConfig.orientation();
222
0
  }
223
0
  LayoutDeviceIntRect targetBounds = mWidget->GetNaturalBounds();
224
0
  targetBounds.MoveTo(0, 0);
225
0
  mForwarder->BeginTransaction(targetBounds.ToUnknownRect(), mTargetRotation,
226
0
                               orientation);
227
0
228
0
  // If we're drawing on behalf of a context with async pan/zoom
229
0
  // enabled, then the entire buffer of painted layers might be
230
0
  // composited (including resampling) asynchronously before we get
231
0
  // a chance to repaint, so we have to ensure that it's all valid
232
0
  // and not rotated.
233
0
  //
234
0
  // Desktop does not support async zoom yet, so we ignore this for those
235
0
  // platforms.
236
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_UIKIT)
237
  if (mWidget && mWidget->GetOwningTabChild()) {
238
    mCompositorMightResample = AsyncPanZoomEnabled();
239
  }
240
#endif
241
242
0
  // If we have a non-default target, we need to let our shadow manager draw
243
0
  // to it. This will happen at the end of the transaction.
244
0
  if (aTarget && XRE_IsParentProcess()) {
245
0
    mShadowTarget = aTarget;
246
0
  } else {
247
0
    NS_ASSERTION(!aTarget,
248
0
                 "Content-process ClientLayerManager::BeginTransactionWithTarget not supported");
249
0
  }
250
0
251
0
  // If this is a new paint, increment the paint sequence number.
252
0
  if (!mIsRepeatTransaction) {
253
0
    // Increment the paint sequence number even if test logging isn't
254
0
    // enabled in this process; it may be enabled in the parent process,
255
0
    // and the parent process expects unique sequence numbers.
256
0
    ++mPaintSequenceNumber;
257
0
    if (gfxPrefs::APZTestLoggingEnabled()) {
258
0
      mApzTestData.StartNewPaint(mPaintSequenceNumber);
259
0
    }
260
0
  }
261
0
  return true;
262
0
}
263
264
bool
265
ClientLayerManager::BeginTransaction()
266
0
{
267
0
  return BeginTransactionWithTarget(nullptr);
268
0
}
269
270
bool
271
ClientLayerManager::EndTransactionInternal(DrawPaintedLayerCallback aCallback,
272
                                           void* aCallbackData,
273
                                           EndTransactionFlags)
274
0
{
275
0
  // This just causes the compositor to check whether the GPU is done with its
276
0
  // textures or not and unlock them if it is. This helps us avoid the case
277
0
  // where we take a long time painting asynchronously, turn IPC back on at
278
0
  // the end of that, and then have to wait for the compositor to to get into
279
0
  // TiledLayerBufferComposite::UseTiles before getting a response.
280
0
  if (mForwarder) {
281
0
    mForwarder->UpdateTextureLocks();
282
0
  }
283
0
284
0
  // Wait for any previous async paints to complete before starting to paint again.
285
0
  // Do this outside the profiler and telemetry block so this doesn't count as time
286
0
  // spent rasterizing.
287
0
  {
288
0
    PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::FlushRasterization);
289
0
    FlushAsyncPaints();
290
0
  }
291
0
292
0
  PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::Rasterization);
293
0
  AUTO_PROFILER_TRACING("Paint", "Rasterize");
294
0
295
0
  Maybe<TimeStamp> startTime;
296
0
  if (gfxPrefs::LayersDrawFPS()) {
297
0
    startTime = Some(TimeStamp::Now());
298
0
  }
299
0
300
0
  AUTO_PROFILER_LABEL("ClientLayerManager::EndTransactionInternal", GRAPHICS);
301
0
302
0
#ifdef MOZ_LAYERS_HAVE_LOG
303
0
  MOZ_LAYERS_LOG(("  ----- (beginning paint)"));
304
0
  Log();
305
0
#endif
306
0
307
0
  NS_ASSERTION(InConstruction(), "Should be in construction phase");
308
0
  mPhase = PHASE_DRAWING;
309
0
310
0
  ClientLayer* root = ClientLayer::ToClientLayer(GetRoot());
311
0
312
0
  mTransactionIncomplete = false;
313
0
  mQueuedAsyncPaints = false;
314
0
315
0
  // Apply pending tree updates before recomputing effective
316
0
  // properties.
317
0
  GetRoot()->ApplyPendingUpdatesToSubtree();
318
0
319
0
  mPaintedLayerCallback = aCallback;
320
0
  mPaintedLayerCallbackData = aCallbackData;
321
0
322
0
  GetRoot()->ComputeEffectiveTransforms(Matrix4x4());
323
0
324
0
  // Skip the painting if the device is in device-reset status.
325
0
  if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
326
0
    if (gfxPrefs::AlwaysPaint() && XRE_IsContentProcess()) {
327
0
      TimeStamp start = TimeStamp::Now();
328
0
      root->RenderLayer();
329
0
      mLastPaintTime = TimeStamp::Now() - start;
330
0
    } else {
331
0
      root->RenderLayer();
332
0
    }
333
0
  } else {
334
0
    gfxCriticalNote << "LayerManager::EndTransaction skip RenderLayer().";
335
0
  }
336
0
337
0
  if (!mRepeatTransaction && !GetRoot()->GetInvalidRegion().IsEmpty()) {
338
0
    GetRoot()->Mutated();
339
0
  }
340
0
341
0
  if (!mIsRepeatTransaction) {
342
0
    mAnimationReadyTime = TimeStamp::Now();
343
0
    GetRoot()->StartPendingAnimations(mAnimationReadyTime);
344
0
  }
345
0
346
0
  mPaintedLayerCallback = nullptr;
347
0
  mPaintedLayerCallbackData = nullptr;
348
0
349
0
  // Go back to the construction phase if the transaction isn't complete.
350
0
  // Layout will update the layer tree and call EndTransaction().
351
0
  mPhase = mTransactionIncomplete ? PHASE_CONSTRUCTION : PHASE_NONE;
352
0
353
0
  NS_ASSERTION(!aCallback || !mTransactionIncomplete,
354
0
               "If callback is not null, transaction must be complete");
355
0
356
0
  if (gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
357
0
    FrameLayerBuilder::InvalidateAllLayers(this);
358
0
  }
359
0
360
0
  if (startTime) {
361
0
    PaintTiming& pt = mForwarder->GetPaintTiming();
362
0
    pt.rasterMs() = (TimeStamp::Now() - startTime.value()).ToMilliseconds();
363
0
  }
364
0
365
0
  return !mTransactionIncomplete;
366
0
}
367
368
void
369
ClientLayerManager::StorePluginWidgetConfigurations(const nsTArray<nsIWidget::Configuration>& aConfigurations)
370
0
{
371
0
  if (mForwarder) {
372
0
    mForwarder->StorePluginWidgetConfigurations(aConfigurations);
373
0
  }
374
0
}
375
376
void
377
ClientLayerManager::EndTransaction(DrawPaintedLayerCallback aCallback,
378
                                   void* aCallbackData,
379
                                   EndTransactionFlags aFlags)
380
0
{
381
0
  if (!mForwarder->IPCOpen()) {
382
0
    mInTransaction = false;
383
0
    return;
384
0
  }
385
0
386
0
  if (mWidget) {
387
0
    mWidget->PrepareWindowEffects();
388
0
  }
389
0
  EndTransactionInternal(aCallback, aCallbackData, aFlags);
390
0
  ForwardTransaction(!(aFlags & END_NO_REMOTE_COMPOSITE));
391
0
392
0
  if (mRepeatTransaction) {
393
0
    mRepeatTransaction = false;
394
0
    mIsRepeatTransaction = true;
395
0
396
0
    // BeginTransaction will reset the transaction start time, but we
397
0
    // would like to keep the original time for telemetry purposes.
398
0
    TimeStamp transactionStart = mTransactionStart;
399
0
    if (BeginTransaction()) {
400
0
      mTransactionStart = transactionStart;
401
0
      ClientLayerManager::EndTransaction(aCallback, aCallbackData, aFlags);
402
0
    }
403
0
404
0
    mIsRepeatTransaction = false;
405
0
  } else {
406
0
    MakeSnapshotIfRequired();
407
0
  }
408
0
409
0
  mInTransaction = false;
410
0
  mTransactionStart = TimeStamp();
411
0
}
412
413
bool
414
ClientLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags)
415
0
{
416
0
  mInTransaction = false;
417
0
418
0
  if (!mRoot || !mForwarder->IPCOpen()) {
419
0
    return false;
420
0
  }
421
0
422
0
  if (!EndTransactionInternal(nullptr, nullptr, aFlags)) {
423
0
    // Return without calling ForwardTransaction. This leaves the
424
0
    // ShadowLayerForwarder transaction open; the following
425
0
    // EndTransaction will complete it.
426
0
    if (PaintThread::Get() && mQueuedAsyncPaints) {
427
0
      PaintThread::Get()->QueueEndLayerTransaction(nullptr);
428
0
    }
429
0
    return false;
430
0
  }
431
0
  if (mWidget) {
432
0
    mWidget->PrepareWindowEffects();
433
0
  }
434
0
  ForwardTransaction(!(aFlags & END_NO_REMOTE_COMPOSITE));
435
0
  MakeSnapshotIfRequired();
436
0
  return true;
437
0
}
438
439
CompositorBridgeChild *
440
ClientLayerManager::GetRemoteRenderer()
441
0
{
442
0
  if (!mWidget) {
443
0
    return nullptr;
444
0
  }
445
0
446
0
  return mWidget->GetRemoteRenderer();
447
0
}
448
449
CompositorBridgeChild*
450
ClientLayerManager::GetCompositorBridgeChild()
451
0
{
452
0
  if (!XRE_IsParentProcess() && !recordreplay::IsRecordingOrReplaying()) {
453
0
    return CompositorBridgeChild::Get();
454
0
  }
455
0
  return GetRemoteRenderer();
456
0
}
457
458
void
459
ClientLayerManager::FlushAsyncPaints()
460
0
{
461
0
  AUTO_PROFILER_LABEL("ClientLayerManager::FlushAsyncPaints", GRAPHICS);
462
0
463
0
  CompositorBridgeChild* cbc = GetCompositorBridgeChild();
464
0
  if (cbc) {
465
0
    cbc->FlushAsyncPaints();
466
0
  }
467
0
}
468
469
void
470
ClientLayerManager::ScheduleComposite()
471
0
{
472
0
  mForwarder->ScheduleComposite();
473
0
}
474
475
void
476
ClientLayerManager::DidComposite(TransactionId aTransactionId,
477
                                 const TimeStamp& aCompositeStart,
478
                                 const TimeStamp& aCompositeEnd)
479
0
{
480
0
  if (!mWidget) {
481
0
    // When recording/replaying this manager may have already been destroyed.
482
0
    MOZ_ASSERT(recordreplay::IsRecordingOrReplaying());
483
0
    return;
484
0
  }
485
0
486
0
  // Notifying the observers may tick the refresh driver which can cause
487
0
  // a lot of different things to happen that may affect the lifetime of
488
0
  // this layer manager. So let's make sure this object stays alive until
489
0
  // the end of the method invocation.
490
0
  RefPtr<ClientLayerManager> selfRef = this;
491
0
492
0
  // |aTransactionId| will be > 0 if the compositor is acknowledging a shadow
493
0
  // layers transaction.
494
0
  if (aTransactionId.IsValid()) {
495
0
    nsIWidgetListener *listener = mWidget->GetWidgetListener();
496
0
    if (listener) {
497
0
      listener->DidCompositeWindow(aTransactionId, aCompositeStart, aCompositeEnd);
498
0
    }
499
0
    listener = mWidget->GetAttachedWidgetListener();
500
0
    if (listener) {
501
0
      listener->DidCompositeWindow(aTransactionId, aCompositeStart, aCompositeEnd);
502
0
    }
503
0
    if (mTransactionIdAllocator) {
504
0
      mTransactionIdAllocator->NotifyTransactionCompleted(aTransactionId);
505
0
    }
506
0
  }
507
0
508
0
  // These observers fire whether or not we were in a transaction.
509
0
  for (size_t i = 0; i < mDidCompositeObservers.Length(); i++) {
510
0
    mDidCompositeObservers[i]->DidComposite();
511
0
  }
512
0
}
513
514
void
515
ClientLayerManager::GetCompositorSideAPZTestData(APZTestData* aData) const
516
0
{
517
0
  if (mForwarder->HasShadowManager()) {
518
0
    if (!mForwarder->GetShadowManager()->SendGetAPZTestData(aData)) {
519
0
      NS_WARNING("Call to PLayerTransactionChild::SendGetAPZTestData() failed");
520
0
    }
521
0
  }
522
0
}
523
524
void
525
ClientLayerManager::SetTransactionIdAllocator(TransactionIdAllocator* aAllocator)
526
0
{
527
0
  // When changing the refresh driver, the previous refresh driver may never
528
0
  // receive updates of pending transactions it's waiting for. So clear the
529
0
  // waiting state before assigning another refresh driver.
530
0
  if (mTransactionIdAllocator && (aAllocator != mTransactionIdAllocator)) {
531
0
    mTransactionIdAllocator->ClearPendingTransactions();
532
0
533
0
    // We should also reset the transaction id of the new allocator to previous
534
0
    // allocator's last transaction id, so that completed transactions for
535
0
    // previous allocator will be ignored and won't confuse the new allocator.
536
0
    if (aAllocator) {
537
0
      aAllocator->ResetInitialTransactionId(mTransactionIdAllocator->LastTransactionId());
538
0
    }
539
0
  }
540
0
541
0
  mTransactionIdAllocator = aAllocator;
542
0
}
543
544
float
545
ClientLayerManager::RequestProperty(const nsAString& aProperty)
546
0
{
547
0
  if (mForwarder->HasShadowManager()) {
548
0
    float value;
549
0
    if (!mForwarder->GetShadowManager()->SendRequestProperty(nsString(aProperty), &value)) {
550
0
      NS_WARNING("Call to PLayerTransactionChild::SendGetAPZTestData() failed");
551
0
    }
552
0
    return value;
553
0
  }
554
0
  return -1;
555
0
}
556
557
void
558
ClientLayerManager::StartNewRepaintRequest(SequenceNumber aSequenceNumber)
559
0
{
560
0
  if (gfxPrefs::APZTestLoggingEnabled()) {
561
0
    mApzTestData.StartNewRepaintRequest(aSequenceNumber);
562
0
  }
563
0
}
564
565
void
566
ClientLayerManager::GetFrameUniformity(FrameUniformityData* aOutData)
567
0
{
568
0
  MOZ_ASSERT(XRE_IsParentProcess(), "Frame Uniformity only supported in parent process");
569
0
570
0
  if (HasShadowManager()) {
571
0
    CompositorBridgeChild* child = GetRemoteRenderer();
572
0
    child->SendGetFrameUniformity(aOutData);
573
0
    return;
574
0
  }
575
0
576
0
  return LayerManager::GetFrameUniformity(aOutData);
577
0
}
578
579
void
580
ClientLayerManager::MakeSnapshotIfRequired()
581
0
{
582
0
  if (!mShadowTarget) {
583
0
    return;
584
0
  }
585
0
  if (mWidget) {
586
0
    if (CompositorBridgeChild* remoteRenderer = GetRemoteRenderer()) {
587
0
      // The compositor doesn't draw to a different sized surface
588
0
      // when there's a rotation. Instead we rotate the result
589
0
      // when drawing into dt
590
0
      LayoutDeviceIntRect outerBounds = mWidget->GetBounds();
591
0
592
0
      IntRect bounds = ToOutsideIntRect(mShadowTarget->GetClipExtents());
593
0
      if (mTargetRotation) {
594
0
        bounds =
595
0
          RotateRect(bounds, outerBounds.ToUnknownRect(), mTargetRotation);
596
0
      }
597
0
598
0
      SurfaceDescriptor inSnapshot;
599
0
      if (!bounds.IsEmpty() &&
600
0
          mForwarder->AllocSurfaceDescriptor(bounds.Size(),
601
0
                                             gfxContentType::COLOR_ALPHA,
602
0
                                             &inSnapshot)) {
603
0
604
0
        // Make a copy of |inSnapshot| because the call to send it over IPC
605
0
        // will call forget() on the Shmem inside, and zero it out.
606
0
        SurfaceDescriptor outSnapshot = inSnapshot;
607
0
608
0
        if (remoteRenderer->SendMakeSnapshot(inSnapshot, bounds)) {
609
0
          RefPtr<DataSourceSurface> surf = GetSurfaceForDescriptor(outSnapshot);
610
0
          DrawTarget* dt = mShadowTarget->GetDrawTarget();
611
0
612
0
          Rect dstRect(bounds.X(), bounds.Y(), bounds.Width(), bounds.Height());
613
0
          Rect srcRect(0, 0, bounds.Width(), bounds.Height());
614
0
615
0
          gfx::Matrix rotate =
616
0
            ComputeTransformForUnRotation(outerBounds.ToUnknownRect(),
617
0
                                          mTargetRotation);
618
0
619
0
          gfx::Matrix oldMatrix = dt->GetTransform();
620
0
          dt->SetTransform(rotate * oldMatrix);
621
0
          dt->DrawSurface(surf, dstRect, srcRect,
622
0
                          DrawSurfaceOptions(),
623
0
                          DrawOptions(1.0f, CompositionOp::OP_OVER));
624
0
          dt->SetTransform(oldMatrix);
625
0
        }
626
0
        mForwarder->DestroySurfaceDescriptor(&outSnapshot);
627
0
      }
628
0
    }
629
0
  }
630
0
  mShadowTarget = nullptr;
631
0
}
632
633
void
634
ClientLayerManager::FlushRendering()
635
0
{
636
0
  if (mWidget) {
637
0
    if (CompositorBridgeChild* remoteRenderer = mWidget->GetRemoteRenderer()) {
638
0
      if (mWidget->SynchronouslyRepaintOnResize() || gfxPrefs::LayersForceSynchronousResize()) {
639
0
        remoteRenderer->SendFlushRendering();
640
0
      } else {
641
0
        remoteRenderer->SendFlushRenderingAsync();
642
0
      }
643
0
    }
644
0
  }
645
0
}
646
647
void
648
ClientLayerManager::WaitOnTransactionProcessed()
649
0
{
650
0
  CompositorBridgeChild* remoteRenderer = GetCompositorBridgeChild();
651
0
  if (remoteRenderer) {
652
0
    remoteRenderer->SendWaitOnTransactionProcessed();
653
0
  }
654
0
}
655
void
656
ClientLayerManager::UpdateTextureFactoryIdentifier(const TextureFactoryIdentifier& aNewIdentifier)
657
0
{
658
0
  mForwarder->IdentifyTextureHost(aNewIdentifier);
659
0
}
660
661
void
662
ClientLayerManager::SendInvalidRegion(const nsIntRegion& aRegion)
663
0
{
664
0
  if (mWidget) {
665
0
    if (CompositorBridgeChild* remoteRenderer = mWidget->GetRemoteRenderer()) {
666
0
      remoteRenderer->SendNotifyRegionInvalidated(aRegion);
667
0
    }
668
0
  }
669
0
}
670
671
uint32_t
672
ClientLayerManager::StartFrameTimeRecording(int32_t aBufferSize)
673
0
{
674
0
  CompositorBridgeChild* renderer = GetRemoteRenderer();
675
0
  if (renderer) {
676
0
    uint32_t startIndex;
677
0
    renderer->SendStartFrameTimeRecording(aBufferSize, &startIndex);
678
0
    return startIndex;
679
0
  }
680
0
  return -1;
681
0
}
682
683
void
684
ClientLayerManager::StopFrameTimeRecording(uint32_t         aStartIndex,
685
                                           nsTArray<float>& aFrameIntervals)
686
0
{
687
0
  CompositorBridgeChild* renderer = GetRemoteRenderer();
688
0
  if (renderer) {
689
0
    renderer->SendStopFrameTimeRecording(aStartIndex, &aFrameIntervals);
690
0
  }
691
0
}
692
693
void
694
ClientLayerManager::ForwardTransaction(bool aScheduleComposite)
695
0
{
696
0
  AUTO_PROFILER_TRACING("Paint", "ForwardTransaction");
697
0
  TimeStamp start = TimeStamp::Now();
698
0
699
0
  // Skip the synchronization for buffer since we also skip the painting during
700
0
  // device-reset status. With OMTP, we have to wait for async paints
701
0
  // before we synchronize and it's done on the paint thread.
702
0
  RefPtr<SyncObjectClient> syncObject = nullptr;
703
0
  if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
704
0
    if (mForwarder->GetSyncObject() &&
705
0
        mForwarder->GetSyncObject()->IsSyncObjectValid()) {
706
0
      syncObject = mForwarder->GetSyncObject();
707
0
    }
708
0
  }
709
0
710
0
  // If there were async paints queued, then we need to notify the paint thread
711
0
  // that we finished queuing async paints so it can schedule a runnable after
712
0
  // all async painting is finished to do a texture sync and unblock the main
713
0
  // thread if it is waiting before doing a new layer transaction.
714
0
  if (mQueuedAsyncPaints) {
715
0
    MOZ_ASSERT(PaintThread::Get());
716
0
    PaintThread::Get()->QueueEndLayerTransaction(syncObject);
717
0
  } else if (syncObject) {
718
0
    syncObject->Synchronize();
719
0
  }
720
0
721
0
  mPhase = PHASE_FORWARD;
722
0
723
0
  mLatestTransactionId = mTransactionIdAllocator->GetTransactionId(!mIsRepeatTransaction);
724
0
  TimeStamp refreshStart = mTransactionIdAllocator->GetTransactionStart();
725
0
726
0
  if (gfxPrefs::AlwaysPaint() && XRE_IsContentProcess()) {
727
0
    mForwarder->SendPaintTime(mLatestTransactionId, mLastPaintTime);
728
0
  }
729
0
730
0
  // forward this transaction's changeset to our LayerManagerComposite
731
0
  bool sent = false;
732
0
  bool ok = mForwarder->EndTransaction(
733
0
    mRegionToClear, mLatestTransactionId, aScheduleComposite,
734
0
    mPaintSequenceNumber, mIsRepeatTransaction,
735
0
    refreshStart, mTransactionStart,
736
0
    &sent);
737
0
  if (ok) {
738
0
    if (sent) {
739
0
      mNeedsComposite = false;
740
0
    }
741
0
  } else if (HasShadowManager()) {
742
0
    NS_WARNING("failed to forward Layers transaction");
743
0
  }
744
0
745
0
  if (!sent) {
746
0
    // Clear the transaction id so that it doesn't get returned
747
0
    // unless we forwarded to somewhere that doesn't actually
748
0
    // have a compositor.
749
0
    mTransactionIdAllocator->RevokeTransactionId(mLatestTransactionId);
750
0
  }
751
0
752
0
  mPhase = PHASE_NONE;
753
0
754
0
  // this may result in Layers being deleted, which results in
755
0
  // PLayer::Send__delete__() and DeallocShmem()
756
0
  mKeepAlive.Clear();
757
0
758
0
  TabChild* window = mWidget ? mWidget->GetOwningTabChild() : nullptr;
759
0
  if (window) {
760
0
    TimeStamp end = TimeStamp::Now();
761
0
    window->DidRequestComposite(start, end);
762
0
  }
763
0
}
764
765
ShadowableLayer*
766
ClientLayerManager::Hold(Layer* aLayer)
767
0
{
768
0
  MOZ_ASSERT(HasShadowManager(),
769
0
             "top-level tree, no shadow tree to remote to");
770
0
771
0
  ShadowableLayer* shadowable = ClientLayer::ToClientLayer(aLayer);
772
0
  MOZ_ASSERT(shadowable, "trying to remote an unshadowable layer");
773
0
774
0
  mKeepAlive.AppendElement(aLayer);
775
0
  return shadowable;
776
0
}
777
778
bool
779
ClientLayerManager::IsCompositingCheap()
780
0
{
781
0
  // Whether compositing is cheap depends on the parent backend.
782
0
  return mForwarder->mShadowManager &&
783
0
         LayerManager::IsCompositingCheap(mForwarder->GetCompositorBackendType());
784
0
}
785
786
bool
787
ClientLayerManager::AreComponentAlphaLayersEnabled()
788
0
{
789
0
  return GetCompositorBackendType() != LayersBackend::LAYERS_BASIC &&
790
0
         AsShadowForwarder()->SupportsComponentAlpha() &&
791
0
         LayerManager::AreComponentAlphaLayersEnabled();
792
0
}
793
794
void
795
ClientLayerManager::SetIsFirstPaint()
796
0
{
797
0
  mForwarder->SetIsFirstPaint();
798
0
}
799
800
void
801
ClientLayerManager::SetFocusTarget(const FocusTarget& aFocusTarget)
802
0
{
803
0
  mForwarder->SetFocusTarget(aFocusTarget);
804
0
}
805
806
void
807
ClientLayerManager::ClearCachedResources(Layer* aSubtree)
808
0
{
809
0
  if (mDestroyed) {
810
0
    // ClearCachedResource was already called by ClientLayerManager::Destroy
811
0
    return;
812
0
  }
813
0
  MOZ_ASSERT(!HasShadowManager() || !aSubtree);
814
0
  mForwarder->ClearCachedResources();
815
0
  if (aSubtree) {
816
0
    ClearLayer(aSubtree);
817
0
  } else if (mRoot) {
818
0
    ClearLayer(mRoot);
819
0
  }
820
0
}
821
822
void
823
ClientLayerManager::OnMemoryPressure(MemoryPressureReason aWhy)
824
0
{
825
0
  if (mRoot) {
826
0
    HandleMemoryPressureLayer(mRoot);
827
0
  }
828
0
829
0
  if (GetCompositorBridgeChild()) {
830
0
    GetCompositorBridgeChild()->HandleMemoryPressure();
831
0
  }
832
0
}
833
834
void
835
ClientLayerManager::ClearLayer(Layer* aLayer)
836
0
{
837
0
  aLayer->ClearCachedResources();
838
0
  for (Layer* child = aLayer->GetFirstChild(); child;
839
0
       child = child->GetNextSibling()) {
840
0
    ClearLayer(child);
841
0
  }
842
0
}
843
844
void
845
ClientLayerManager::HandleMemoryPressureLayer(Layer* aLayer)
846
0
{
847
0
  ClientLayer::ToClientLayer(aLayer)->HandleMemoryPressure();
848
0
  for (Layer* child = aLayer->GetFirstChild(); child;
849
0
       child = child->GetNextSibling()) {
850
0
    HandleMemoryPressureLayer(child);
851
0
  }
852
0
}
853
854
void
855
ClientLayerManager::GetBackendName(nsAString& aName)
856
0
{
857
0
  switch (mForwarder->GetCompositorBackendType()) {
858
0
    case LayersBackend::LAYERS_NONE: aName.AssignLiteral("None"); return;
859
0
    case LayersBackend::LAYERS_BASIC: aName.AssignLiteral("Basic"); return;
860
0
    case LayersBackend::LAYERS_OPENGL: aName.AssignLiteral("OpenGL"); return;
861
0
    case LayersBackend::LAYERS_D3D11: {
862
#ifdef XP_WIN
863
      if (DeviceManagerDx::Get()->IsWARP()) {
864
        aName.AssignLiteral("Direct3D 11 WARP");
865
      } else {
866
        aName.AssignLiteral("Direct3D 11");
867
      }
868
#endif
869
      return;
870
0
    }
871
0
    default: MOZ_CRASH("Invalid backend");
872
0
  }
873
0
}
874
875
bool
876
ClientLayerManager::AsyncPanZoomEnabled() const
877
0
{
878
0
  return mWidget && mWidget->AsyncPanZoomEnabled();
879
0
}
880
881
void
882
ClientLayerManager::SetLayersObserverEpoch(LayersObserverEpoch aEpoch)
883
0
{
884
0
  mForwarder->SetLayersObserverEpoch(aEpoch);
885
0
}
886
887
void
888
ClientLayerManager::AddDidCompositeObserver(DidCompositeObserver* aObserver)
889
0
{
890
0
  if (!mDidCompositeObservers.Contains(aObserver)) {
891
0
    mDidCompositeObservers.AppendElement(aObserver);
892
0
  }
893
0
}
894
895
void
896
ClientLayerManager::RemoveDidCompositeObserver(DidCompositeObserver* aObserver)
897
0
{
898
0
  mDidCompositeObservers.RemoveElement(aObserver);
899
0
}
900
901
already_AddRefed<PersistentBufferProvider>
902
ClientLayerManager::CreatePersistentBufferProvider(const gfx::IntSize& aSize,
903
                                                   gfx::SurfaceFormat aFormat)
904
0
{
905
0
  // Don't use a shared buffer provider if compositing is considered "not cheap"
906
0
  // because the canvas will most likely be flattened into a thebes layer instead
907
0
  // of being sent to the compositor, in which case rendering into shared memory
908
0
  // is wasteful.
909
0
  if (IsCompositingCheap() &&
910
0
      gfxPrefs::PersistentBufferProviderSharedEnabled()) {
911
0
    RefPtr<PersistentBufferProvider> provider
912
0
      = PersistentBufferProviderShared::Create(aSize, aFormat, AsShadowForwarder());
913
0
    if (provider) {
914
0
      return provider.forget();
915
0
    }
916
0
  }
917
0
918
0
  return LayerManager::CreatePersistentBufferProvider(aSize, aFormat);
919
0
}
920
921
922
ClientLayer::~ClientLayer()
923
0
{
924
0
  MOZ_COUNT_DTOR(ClientLayer);
925
0
}
926
927
} // namespace layers
928
} // namespace mozilla