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