Source code

Revision control

Other Tools

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