Bug 1697579 Part 1: Add diagnostic asserts to ~CompositorBridgeParent(). r=sotaro
[gecko.git] / gfx / layers / ipc / CompositorBridgeParent.cpp
blob26b25322af6ae16c0c36ec23c39db0b71654d1ac
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 "mozilla/layers/CompositorBridgeParent.h"
9 #include <stdio.h> // for fprintf, stdout
10 #include <stdint.h> // for uint64_t
11 #include <map> // for _Rb_tree_iterator, etc
12 #include <utility> // for pair
14 #include "apz/src/APZCTreeManager.h" // for APZCTreeManager
15 #include "LayerTransactionParent.h" // for LayerTransactionParent
16 #include "RenderTrace.h" // for RenderTraceLayers
17 #include "base/process.h" // for ProcessId
18 #include "gfxContext.h" // for gfxContext
19 #include "gfxPlatform.h" // for gfxPlatform
20 #include "TreeTraversal.h" // for ForEachNode
21 #ifdef MOZ_WIDGET_GTK
22 # include "gfxPlatformGtk.h" // for gfxPlatform
23 #endif
24 #include "mozilla/AutoRestore.h" // for AutoRestore
25 #include "mozilla/ClearOnShutdown.h" // for ClearOnShutdown
26 #include "mozilla/DebugOnly.h" // for DebugOnly
27 #include "mozilla/StaticPrefs_gfx.h"
28 #include "mozilla/StaticPrefs_layers.h"
29 #include "mozilla/StaticPrefs_layout.h"
30 #include "mozilla/dom/BrowserParent.h"
31 #include "mozilla/gfx/2D.h" // for DrawTarget
32 #include "mozilla/gfx/Point.h" // for IntSize
33 #include "mozilla/gfx/Rect.h" // for IntSize
34 #include "mozilla/gfx/gfxVars.h" // for gfxVars
35 #include "mozilla/ipc/Transport.h" // for Transport
36 #include "mozilla/gfx/gfxVars.h"
37 #include "mozilla/gfx/GPUParent.h"
38 #include "mozilla/layers/APZCTreeManagerParent.h" // for APZCTreeManagerParent
39 #include "mozilla/layers/APZSampler.h" // for APZSampler
40 #include "mozilla/layers/APZThreadUtils.h" // for APZThreadUtils
41 #include "mozilla/layers/APZUpdater.h" // for APZUpdater
42 #include "mozilla/layers/AsyncCompositionManager.h"
43 #include "mozilla/layers/BasicCompositor.h" // for BasicCompositor
44 #include "mozilla/layers/CompositionRecorder.h" // for CompositionRecorder
45 #include "mozilla/layers/Compositor.h" // for Compositor
46 #include "mozilla/layers/CompositorAnimationStorage.h" // for CompositorAnimationStorage
47 #include "mozilla/layers/CompositorManagerParent.h" // for CompositorManagerParent
48 #include "mozilla/layers/CompositorOGL.h" // for CompositorOGL
49 #include "mozilla/layers/CompositorThread.h"
50 #include "mozilla/layers/CompositorTypes.h"
51 #include "mozilla/layers/CompositorVsyncScheduler.h"
52 #include "mozilla/layers/ContentCompositorBridgeParent.h"
53 #include "mozilla/layers/FrameUniformityData.h"
54 #include "mozilla/layers/GeckoContentController.h"
55 #include "mozilla/layers/ImageBridgeParent.h"
56 #include "mozilla/layers/LayerManagerComposite.h"
57 #include "mozilla/layers/LayerTreeOwnerTracker.h"
58 #include "mozilla/layers/LayersTypes.h"
59 #include "mozilla/layers/OMTASampler.h"
60 #include "mozilla/layers/PLayerTransactionParent.h"
61 #include "mozilla/layers/RemoteContentController.h"
62 #include "mozilla/layers/UiCompositorControllerParent.h"
63 #include "mozilla/layers/WebRenderBridgeParent.h"
64 #include "mozilla/layers/AsyncImagePipelineManager.h"
65 #include "mozilla/webrender/WebRenderAPI.h"
66 #include "mozilla/webgpu/WebGPUParent.h"
67 #include "mozilla/webrender/RenderThread.h"
68 #include "mozilla/media/MediaSystemResourceService.h" // for MediaSystemResourceService
69 #include "mozilla/mozalloc.h" // for operator new, etc
70 #include "mozilla/PerfStats.h"
71 #include "mozilla/PodOperations.h"
72 #include "mozilla/ProfilerLabels.h"
73 #include "mozilla/ProfilerMarkers.h"
74 #include "mozilla/Telemetry.h"
75 #ifdef MOZ_WIDGET_GTK
76 # include "basic/X11BasicCompositor.h" // for X11BasicCompositor
77 #endif
78 #include "nsCOMPtr.h" // for already_AddRefed
79 #include "nsDebug.h" // for NS_ASSERTION, etc
80 #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
81 #include "nsIWidget.h" // for nsIWidget
82 #include "nsTArray.h" // for nsTArray
83 #include "nsThreadUtils.h" // for NS_IsMainThread
84 #ifdef XP_WIN
85 # include "mozilla/layers/CompositorD3D11.h"
86 # include "mozilla/widget/WinCompositorWidget.h"
87 # include "mozilla/WindowsVersion.h"
88 #endif
89 #include "mozilla/ipc/ProtocolTypes.h"
90 #include "mozilla/Unused.h"
91 #include "mozilla/Hal.h"
92 #include "mozilla/HalTypes.h"
93 #include "mozilla/StaticPtr.h"
94 #include "mozilla/Telemetry.h"
95 #include "mozilla/VsyncDispatcher.h"
96 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
97 # include "VsyncSource.h"
98 #endif
99 #include "mozilla/widget/CompositorWidget.h"
100 #ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING
101 # include "mozilla/widget/CompositorWidgetParent.h"
102 #endif
103 #ifdef XP_WIN
104 # include "mozilla/gfx/DeviceManagerDx.h"
105 #endif
107 #include "LayerScope.h"
109 namespace mozilla {
111 namespace layers {
113 using namespace mozilla::ipc;
114 using namespace mozilla::gfx;
116 using base::ProcessId;
118 using mozilla::Telemetry::LABELS_CONTENT_FRAME_TIME_REASON;
120 /// Equivalent to asserting CompositorThreadHolder::IsInCompositorThread with
121 /// the addition that it doesn't assert if the compositor thread holder is
122 /// already gone during late shutdown.
123 static void AssertIsInCompositorThread() {
124 MOZ_RELEASE_ASSERT(!CompositorThread() ||
125 CompositorThreadHolder::IsInCompositorThread());
128 CompositorBridgeParentBase::CompositorBridgeParentBase(
129 CompositorManagerParent* aManager)
130 : mCanSend(true), mCompositorManager(aManager) {}
132 CompositorBridgeParentBase::~CompositorBridgeParentBase() = default;
134 ProcessId CompositorBridgeParentBase::GetChildProcessId() { return OtherPid(); }
136 void CompositorBridgeParentBase::NotifyNotUsed(PTextureParent* aTexture,
137 uint64_t aTransactionId) {
138 RefPtr<TextureHost> texture = TextureHost::AsTextureHost(aTexture);
139 if (!texture) {
140 return;
143 #ifdef MOZ_WIDGET_ANDROID
144 if (texture->GetAndroidHardwareBuffer()) {
145 MOZ_ASSERT(texture->GetFlags() & TextureFlags::RECYCLE);
146 ImageBridgeParent::NotifyBufferNotUsedOfCompositorBridge(
147 GetChildProcessId(), texture, aTransactionId);
149 #endif
151 if (!(texture->GetFlags() & TextureFlags::RECYCLE) &&
152 !(texture->GetFlags() & TextureFlags::WAIT_HOST_USAGE_END)) {
153 return;
156 uint64_t textureId = TextureHost::GetTextureSerial(aTexture);
157 mPendingAsyncMessage.push_back(OpNotifyNotUsed(textureId, aTransactionId));
160 void CompositorBridgeParentBase::SendAsyncMessage(
161 const nsTArray<AsyncParentMessageData>& aMessage) {
162 Unused << SendParentAsyncMessages(aMessage);
165 bool CompositorBridgeParentBase::AllocShmem(
166 size_t aSize, ipc::SharedMemory::SharedMemoryType aType,
167 ipc::Shmem* aShmem) {
168 return PCompositorBridgeParent::AllocShmem(aSize, aType, aShmem);
171 bool CompositorBridgeParentBase::AllocUnsafeShmem(
172 size_t aSize, ipc::SharedMemory::SharedMemoryType aType,
173 ipc::Shmem* aShmem) {
174 return PCompositorBridgeParent::AllocUnsafeShmem(aSize, aType, aShmem);
177 bool CompositorBridgeParentBase::DeallocShmem(ipc::Shmem& aShmem) {
178 return PCompositorBridgeParent::DeallocShmem(aShmem);
181 base::ProcessId CompositorBridgeParentBase::RemotePid() { return OtherPid(); }
183 bool CompositorBridgeParentBase::StartSharingMetrics(
184 ipc::SharedMemoryBasic::Handle aHandle,
185 CrossProcessMutexHandle aMutexHandle, LayersId aLayersId,
186 uint32_t aApzcId) {
187 if (!CompositorThreadHolder::IsInCompositorThread()) {
188 MOZ_ASSERT(CompositorThread());
189 CompositorThread()->Dispatch(
190 NewRunnableMethod<ipc::SharedMemoryBasic::Handle,
191 CrossProcessMutexHandle, LayersId, uint32_t>(
192 "layers::CompositorBridgeParent::StartSharingMetrics", this,
193 &CompositorBridgeParentBase::StartSharingMetrics, aHandle,
194 aMutexHandle, aLayersId, aApzcId));
195 return true;
198 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
199 if (!mCanSend) {
200 return false;
202 return PCompositorBridgeParent::SendSharedCompositorFrameMetrics(
203 aHandle, aMutexHandle, aLayersId, aApzcId);
206 bool CompositorBridgeParentBase::StopSharingMetrics(
207 ScrollableLayerGuid::ViewID aScrollId, uint32_t aApzcId) {
208 if (!CompositorThreadHolder::IsInCompositorThread()) {
209 MOZ_ASSERT(CompositorThread());
210 CompositorThread()->Dispatch(
211 NewRunnableMethod<ScrollableLayerGuid::ViewID, uint32_t>(
212 "layers::CompositorBridgeParent::StopSharingMetrics", this,
213 &CompositorBridgeParentBase::StopSharingMetrics, aScrollId,
214 aApzcId));
215 return true;
218 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
219 if (!mCanSend) {
220 return false;
222 return PCompositorBridgeParent::SendReleaseSharedCompositorFrameMetrics(
223 aScrollId, aApzcId);
226 CompositorBridgeParent::LayerTreeState::LayerTreeState()
227 : mApzcTreeManagerParent(nullptr),
228 mParent(nullptr),
229 mLayerManager(nullptr),
230 mContentCompositorBridgeParent(nullptr),
231 mLayerTree(nullptr) {}
233 CompositorBridgeParent::LayerTreeState::~LayerTreeState() {
234 if (mController) {
235 mController->Destroy();
239 typedef std::map<LayersId, CompositorBridgeParent::LayerTreeState> LayerTreeMap;
240 LayerTreeMap sIndirectLayerTrees;
241 StaticAutoPtr<mozilla::Monitor> sIndirectLayerTreesLock;
243 static void EnsureLayerTreeMapReady() {
244 MOZ_ASSERT(NS_IsMainThread());
245 if (!sIndirectLayerTreesLock) {
246 sIndirectLayerTreesLock = new Monitor("IndirectLayerTree");
247 mozilla::ClearOnShutdown(&sIndirectLayerTreesLock);
251 template <typename Lambda>
252 inline void CompositorBridgeParent::ForEachIndirectLayerTree(
253 const Lambda& aCallback) {
254 sIndirectLayerTreesLock->AssertCurrentThreadOwns();
255 for (auto it = sIndirectLayerTrees.begin(); it != sIndirectLayerTrees.end();
256 it++) {
257 LayerTreeState* state = &it->second;
258 if (state->mParent == this) {
259 aCallback(state, it->first);
264 /*static*/ template <typename Lambda>
265 inline void CompositorBridgeParent::ForEachWebRenderBridgeParent(
266 const Lambda& aCallback) {
267 sIndirectLayerTreesLock->AssertCurrentThreadOwns();
268 for (auto& it : sIndirectLayerTrees) {
269 LayerTreeState* state = &it.second;
270 if (state->mWrBridge) {
271 aCallback(state->mWrBridge);
277 * A global map referencing each compositor by ID.
279 * This map is used by the ImageBridge protocol to trigger
280 * compositions without having to keep references to the
281 * compositor
283 typedef std::map<uint64_t, CompositorBridgeParent*> CompositorMap;
284 static StaticAutoPtr<CompositorMap> sCompositorMap;
286 void CompositorBridgeParent::Setup() {
287 EnsureLayerTreeMapReady();
289 MOZ_ASSERT(!sCompositorMap);
290 sCompositorMap = new CompositorMap;
293 void CompositorBridgeParent::FinishShutdown() {
294 MOZ_ASSERT(NS_IsMainThread());
296 if (sCompositorMap) {
297 MOZ_ASSERT(sCompositorMap->empty());
298 sCompositorMap = nullptr;
301 // TODO: this should be empty by now...
302 sIndirectLayerTrees.clear();
305 #ifdef COMPOSITOR_PERFORMANCE_WARNING
306 static int32_t CalculateCompositionFrameRate() {
307 // Used when layout.frame_rate is -1. Needs to be kept in sync with
308 // DEFAULT_FRAME_RATE in nsRefreshDriver.cpp.
309 // TODO: This should actually return the vsync rate.
310 const int32_t defaultFrameRate = 60;
311 int32_t compositionFrameRatePref =
312 StaticPrefs::layers_offmainthreadcomposition_frame_rate();
313 if (compositionFrameRatePref < 0) {
314 // Use the same frame rate for composition as for layout.
315 int32_t layoutFrameRatePref = StaticPrefs::layout_frame_rate();
316 if (layoutFrameRatePref < 0) {
317 // TODO: The main thread frame scheduling code consults the actual
318 // monitor refresh rate in this case. We should do the same.
319 return defaultFrameRate;
321 return layoutFrameRatePref;
323 return compositionFrameRatePref;
325 #endif
327 CompositorBridgeParent::CompositorBridgeParent(
328 CompositorManagerParent* aManager, CSSToLayoutDeviceScale aScale,
329 const TimeDuration& aVsyncRate, const CompositorOptions& aOptions,
330 bool aUseExternalSurfaceSize, const gfx::IntSize& aSurfaceSize)
331 : CompositorBridgeParentBase(aManager),
332 mWidget(nullptr),
333 mScale(aScale),
334 mVsyncRate(aVsyncRate),
335 mPendingTransaction{0},
336 mPaused(false),
337 mHaveCompositionRecorder(false),
338 mIsForcedFirstPaint(false),
339 mUseExternalSurfaceSize(aUseExternalSurfaceSize),
340 mEGLSurfaceSize(aSurfaceSize),
341 mOptions(aOptions),
342 mPauseCompositionMonitor("PauseCompositionMonitor"),
343 mResumeCompositionMonitor("ResumeCompositionMonitor"),
344 mCompositorBridgeID(0),
345 mRootLayerTreeID{0},
346 mOverrideComposeReadiness(false),
347 mForceCompositionTask(nullptr),
348 mCompositorScheduler(nullptr),
349 mAnimationStorage(nullptr),
350 mPaintTime(TimeDuration::Forever()) {}
352 void CompositorBridgeParent::InitSameProcess(widget::CompositorWidget* aWidget,
353 const LayersId& aLayerTreeId) {
354 MOZ_ASSERT(XRE_IsParentProcess());
355 MOZ_ASSERT(NS_IsMainThread());
357 mWidget = aWidget;
358 mRootLayerTreeID = aLayerTreeId;
360 Initialize();
363 mozilla::ipc::IPCResult CompositorBridgeParent::RecvInitialize(
364 const LayersId& aRootLayerTreeId) {
365 MOZ_ASSERT(XRE_IsGPUProcess());
367 mRootLayerTreeID = aRootLayerTreeId;
368 #ifdef XP_WIN
369 if (XRE_IsGPUProcess()) {
370 mWidget->AsWindows()->SetRootLayerTreeID(mRootLayerTreeID);
372 #endif
374 Initialize();
375 return IPC_OK();
378 void CompositorBridgeParent::Initialize() {
379 MOZ_ASSERT(CompositorThread(),
380 "The compositor thread must be Initialized before instanciating a "
381 "CompositorBridgeParent.");
383 if (mOptions.UseAPZ()) {
384 MOZ_ASSERT(!mApzcTreeManager);
385 MOZ_ASSERT(!mApzSampler);
386 MOZ_ASSERT(!mApzUpdater);
387 mApzcTreeManager =
388 new APZCTreeManager(mRootLayerTreeID, mOptions.UseWebRender());
389 mApzSampler = new APZSampler(mApzcTreeManager, mOptions.UseWebRender());
390 mApzUpdater = new APZUpdater(mApzcTreeManager, mOptions.UseWebRender());
393 if (mOptions.UseWebRender()) {
394 CompositorAnimationStorage* animationStorage = GetAnimationStorage();
395 mOMTASampler = new OMTASampler(animationStorage, mRootLayerTreeID);
398 mPaused = mOptions.InitiallyPaused();
400 mCompositorBridgeID = 0;
401 // FIXME: This holds on the the fact that right now the only thing that
402 // can destroy this instance is initialized on the compositor thread after
403 // this task has been processed.
404 MOZ_ASSERT(CompositorThread());
405 CompositorThread()->Dispatch(NewRunnableFunction(
406 "AddCompositorRunnable", &AddCompositor, this, &mCompositorBridgeID));
408 { // scope lock
409 MonitorAutoLock lock(*sIndirectLayerTreesLock);
410 sIndirectLayerTrees[mRootLayerTreeID].mParent = this;
413 LayerScope::SetPixelScale(mScale.scale);
415 if (!mOptions.UseWebRender()) {
416 mCompositorScheduler = new CompositorVsyncScheduler(this, mWidget);
420 LayersId CompositorBridgeParent::RootLayerTreeId() {
421 MOZ_ASSERT(mRootLayerTreeID.IsValid());
422 return mRootLayerTreeID;
425 CompositorBridgeParent::~CompositorBridgeParent() {
426 MOZ_DIAGNOSTIC_ASSERT(
427 !mCanSend,
428 "ActorDestroy or RecvWillClose should have been called first.");
429 MOZ_DIAGNOSTIC_ASSERT(mRefCnt == 0,
430 "ActorDealloc should have been called first.");
431 nsTArray<PTextureParent*> textures;
432 ManagedPTextureParent(textures);
433 // We expect all textures to be destroyed by now.
434 MOZ_DIAGNOSTIC_ASSERT(textures.Length() == 0);
435 for (unsigned int i = 0; i < textures.Length(); ++i) {
436 RefPtr<TextureHost> tex = TextureHost::AsTextureHost(textures[i]);
437 tex->DeallocateDeviceData();
439 // Check if WebRender/Compositor was shutdown.
440 if (mWrBridge || mCompositor) {
441 gfxCriticalNote << "CompositorBridgeParent destroyed without shutdown";
445 void CompositorBridgeParent::ForceIsFirstPaint() {
446 if (mWrBridge) {
447 mIsForcedFirstPaint = true;
448 } else {
449 mCompositionManager->ForceIsFirstPaint();
453 void CompositorBridgeParent::StopAndClearResources() {
454 if (mForceCompositionTask) {
455 mForceCompositionTask->Cancel();
456 mForceCompositionTask = nullptr;
459 mPaused = true;
461 // We need to clear the APZ tree before we destroy the WebRender API below,
462 // because in the case of async scene building that will shut down the updater
463 // thread and we need to run the task before that happens.
464 MOZ_ASSERT((mApzSampler != nullptr) == (mApzcTreeManager != nullptr));
465 MOZ_ASSERT((mApzUpdater != nullptr) == (mApzcTreeManager != nullptr));
466 if (mApzUpdater) {
467 mApzSampler->Destroy();
468 mApzSampler = nullptr;
469 mApzUpdater->ClearTree(mRootLayerTreeID);
470 mApzUpdater = nullptr;
471 mApzcTreeManager = nullptr;
474 // Ensure that the layer manager is destroyed before CompositorBridgeChild.
475 if (mLayerManager) {
476 MonitorAutoLock lock(*sIndirectLayerTreesLock);
477 ForEachIndirectLayerTree([this](LayerTreeState* lts, LayersId) -> void {
478 mLayerManager->ClearCachedResources(lts->mRoot);
479 lts->mLayerManager = nullptr;
480 lts->mParent = nullptr;
482 mLayerManager->Destroy();
483 mLayerManager = nullptr;
484 mCompositionManager = nullptr;
487 if (mWrBridge) {
488 // Ensure we are not holding the sIndirectLayerTreesLock when destroying
489 // the WebRenderBridgeParent instances because it may block on WR.
490 std::vector<RefPtr<WebRenderBridgeParent>> indirectBridgeParents;
491 { // scope lock
492 MonitorAutoLock lock(*sIndirectLayerTreesLock);
493 ForEachIndirectLayerTree([&](LayerTreeState* lts, LayersId) -> void {
494 if (lts->mWrBridge) {
495 indirectBridgeParents.emplace_back(lts->mWrBridge.forget());
497 lts->mParent = nullptr;
500 for (const RefPtr<WebRenderBridgeParent>& bridge : indirectBridgeParents) {
501 bridge->Destroy();
503 indirectBridgeParents.clear();
505 RefPtr<wr::WebRenderAPI> api = mWrBridge->GetWebRenderAPI();
506 // Ensure we are not holding the sIndirectLayerTreesLock here because we
507 // are going to block on WR threads in order to shut it down properly.
508 mWrBridge->Destroy();
509 mWrBridge = nullptr;
511 if (api) {
512 // Make extra sure we are done cleaning WebRender up before continuing.
513 // After that we wont have a way to talk to a lot of the webrender parts.
514 api->FlushSceneBuilder();
515 api = nullptr;
518 if (mAsyncImageManager) {
519 mAsyncImageManager->Destroy();
520 // WebRenderAPI should be already destructed
521 mAsyncImageManager = nullptr;
525 if (mCompositor) {
526 mCompositor->Destroy();
527 mCompositor = nullptr;
530 // This must be destroyed now since it accesses the widget.
531 if (mCompositorScheduler) {
532 mCompositorScheduler->Destroy();
533 mCompositorScheduler = nullptr;
536 if (mOMTASampler) {
537 mOMTASampler->Destroy();
538 mOMTASampler = nullptr;
541 // After this point, it is no longer legal to access the widget.
542 mWidget = nullptr;
544 // Clear mAnimationStorage here to ensure that the compositor thread
545 // still exists when we destroy it.
546 mAnimationStorage = nullptr;
549 mozilla::ipc::IPCResult CompositorBridgeParent::RecvWillClose() {
550 StopAndClearResources();
551 // Once we get the WillClose message, the client side is going to go away
552 // soon and we can't be guaranteed that sending messages will work.
553 mCanSend = false;
554 return IPC_OK();
557 void CompositorBridgeParent::DeferredDestroy() {
558 MOZ_ASSERT(!NS_IsMainThread());
559 mSelfRef = nullptr;
562 mozilla::ipc::IPCResult CompositorBridgeParent::RecvPause() {
563 PauseComposition();
564 return IPC_OK();
567 mozilla::ipc::IPCResult CompositorBridgeParent::RecvRequestFxrOutput() {
568 #ifdef XP_WIN
569 // Continue forwarding the request to the Widget + SwapChain
570 mWidget->AsWindows()->RequestFxrOutput();
571 #endif
573 return IPC_OK();
576 mozilla::ipc::IPCResult CompositorBridgeParent::RecvResume() {
577 ResumeComposition();
578 return IPC_OK();
581 mozilla::ipc::IPCResult CompositorBridgeParent::RecvResumeAsync() {
582 ResumeComposition();
583 return IPC_OK();
586 mozilla::ipc::IPCResult CompositorBridgeParent::RecvMakeSnapshot(
587 const SurfaceDescriptor& aInSnapshot, const gfx::IntRect& aRect) {
588 RefPtr<DrawTarget> target = GetDrawTargetForDescriptor(aInSnapshot);
589 MOZ_ASSERT(target);
590 if (!target) {
591 // We kill the content process rather than have it continue with an invalid
592 // snapshot, that may be too harsh and we could decide to return some sort
593 // of error to the child process and let it deal with it...
594 return IPC_FAIL_NO_REASON(this);
596 ForceComposeToTarget(target, &aRect);
597 return IPC_OK();
600 mozilla::ipc::IPCResult
601 CompositorBridgeParent::RecvWaitOnTransactionProcessed() {
602 return IPC_OK();
605 mozilla::ipc::IPCResult CompositorBridgeParent::RecvFlushRendering() {
606 if (mWrBridge) {
607 mWrBridge->FlushRendering();
608 return IPC_OK();
611 if (mCompositorScheduler->NeedsComposite()) {
612 CancelCurrentCompositeTask();
613 ForceComposeToTarget(nullptr);
615 return IPC_OK();
618 mozilla::ipc::IPCResult CompositorBridgeParent::RecvFlushRenderingAsync() {
619 if (mWrBridge) {
620 mWrBridge->FlushRendering(false);
621 return IPC_OK();
624 return RecvFlushRendering();
627 mozilla::ipc::IPCResult CompositorBridgeParent::RecvForcePresent() {
628 if (mWrBridge) {
629 mWrBridge->ScheduleForcedGenerateFrame();
631 // During the shutdown sequence mLayerManager may be null
632 if (mLayerManager) {
633 mLayerManager->ForcePresent();
635 return IPC_OK();
638 mozilla::ipc::IPCResult CompositorBridgeParent::RecvNotifyRegionInvalidated(
639 const nsIntRegion& aRegion) {
640 if (mLayerManager) {
641 mLayerManager->AddInvalidRegion(aRegion);
643 return IPC_OK();
646 void CompositorBridgeParent::Invalidate() {
647 if (mLayerManager) {
648 mLayerManager->InvalidateAll();
652 mozilla::ipc::IPCResult CompositorBridgeParent::RecvStartFrameTimeRecording(
653 const int32_t& aBufferSize, uint32_t* aOutStartIndex) {
654 if (mLayerManager) {
655 *aOutStartIndex = mLayerManager->StartFrameTimeRecording(aBufferSize);
656 } else if (mWrBridge) {
657 *aOutStartIndex = mWrBridge->StartFrameTimeRecording(aBufferSize);
658 } else {
659 *aOutStartIndex = 0;
661 return IPC_OK();
664 mozilla::ipc::IPCResult CompositorBridgeParent::RecvStopFrameTimeRecording(
665 const uint32_t& aStartIndex, nsTArray<float>* intervals) {
666 if (mLayerManager) {
667 mLayerManager->StopFrameTimeRecording(aStartIndex, *intervals);
668 } else if (mWrBridge) {
669 mWrBridge->StopFrameTimeRecording(aStartIndex, *intervals);
671 return IPC_OK();
674 void CompositorBridgeParent::ActorDestroy(ActorDestroyReason why) {
675 mCanSend = false;
677 StopAndClearResources();
679 RemoveCompositor(mCompositorBridgeID);
681 mCompositionManager = nullptr;
683 { // scope lock
684 MonitorAutoLock lock(*sIndirectLayerTreesLock);
685 sIndirectLayerTrees.erase(mRootLayerTreeID);
688 // There are chances that the ref count reaches zero on the main thread
689 // shortly after this function returns while some ipdl code still needs to run
690 // on this thread. We must keep the compositor parent alive untill the code
691 // handling message reception is finished on this thread.
692 mSelfRef = this;
693 NS_GetCurrentThread()->Dispatch(
694 NewRunnableMethod("layers::CompositorBridgeParent::DeferredDestroy", this,
695 &CompositorBridgeParent::DeferredDestroy));
698 void CompositorBridgeParent::ScheduleRenderOnCompositorThread() {
699 MOZ_ASSERT(CompositorThread());
700 CompositorThread()->Dispatch(
701 NewRunnableMethod("layers::CompositorBridgeParent::ScheduleComposition",
702 this, &CompositorBridgeParent::ScheduleComposition));
705 void CompositorBridgeParent::PauseComposition() {
706 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread(),
707 "PauseComposition() can only be called on the compositor thread");
709 MonitorAutoLock lock(mPauseCompositionMonitor);
711 if (!mPaused) {
712 mPaused = true;
714 TimeStamp now = TimeStamp::Now();
715 if (mCompositor) {
716 mCompositor->Pause();
717 DidComposite(VsyncId(), now, now);
718 } else if (mWrBridge) {
719 mWrBridge->Pause();
720 NotifyPipelineRendered(mWrBridge->PipelineId(),
721 mWrBridge->GetCurrentEpoch(), VsyncId(), now, now,
722 now);
726 // if anyone's waiting to make sure that composition really got paused, tell
727 // them
728 lock.NotifyAll();
731 void CompositorBridgeParent::ResumeComposition() {
732 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread(),
733 "ResumeComposition() can only be called on the compositor thread");
735 MonitorAutoLock lock(mResumeCompositionMonitor);
737 bool resumed =
738 mOptions.UseWebRender() ? mWrBridge->Resume() : mCompositor->Resume();
739 if (!resumed) {
740 #ifdef MOZ_WIDGET_ANDROID
741 // We can't get a surface. This could be because the activity changed
742 // between the time resume was scheduled and now.
743 __android_log_print(
744 ANDROID_LOG_INFO, "CompositorBridgeParent",
745 "Unable to renew compositor surface; remaining in paused state");
746 #endif
747 lock.NotifyAll();
748 return;
751 mPaused = false;
753 Invalidate();
754 mCompositorScheduler->ForceComposeToTarget(nullptr, nullptr);
756 // if anyone's waiting to make sure that composition really got resumed, tell
757 // them
758 lock.NotifyAll();
761 void CompositorBridgeParent::ForceComposition() {
762 // Cancel the orientation changed state to force composition
763 mForceCompositionTask = nullptr;
764 ScheduleRenderOnCompositorThread();
767 void CompositorBridgeParent::CancelCurrentCompositeTask() {
768 mCompositorScheduler->CancelCurrentCompositeTask();
771 void CompositorBridgeParent::SetEGLSurfaceRect(int x, int y, int width,
772 int height) {
773 NS_ASSERTION(mUseExternalSurfaceSize,
774 "Compositor created without UseExternalSurfaceSize provided");
775 mEGLSurfaceSize.SizeTo(width, height);
776 if (mCompositor) {
777 mCompositor->SetDestinationSurfaceSize(
778 gfx::IntSize(mEGLSurfaceSize.width, mEGLSurfaceSize.height));
779 if (mCompositor->AsCompositorOGL()) {
780 mCompositor->AsCompositorOGL()->SetSurfaceOrigin(ScreenIntPoint(x, y));
785 void CompositorBridgeParent::ResumeCompositionAndResize(int x, int y, int width,
786 int height) {
787 SetEGLSurfaceRect(x, y, width, height);
788 ResumeComposition();
791 void CompositorBridgeParent::UpdatePaintTime(LayerTransactionParent* aLayerTree,
792 const TimeDuration& aPaintTime) {
793 // We get a lot of paint timings for things with empty transactions.
794 if (!mLayerManager || aPaintTime.ToMilliseconds() < 1.0) {
795 return;
798 mLayerManager->SetPaintTime(aPaintTime);
801 void CompositorBridgeParent::RegisterPayloads(
802 LayerTransactionParent* aLayerTree,
803 const nsTArray<CompositionPayload>& aPayload) {
804 // We get a lot of paint timings for things with empty transactions.
805 if (!mLayerManager) {
806 return;
809 mLayerManager->RegisterPayloads(aPayload);
812 void CompositorBridgeParent::NotifyShadowTreeTransaction(
813 LayersId aId, bool aIsFirstPaint, const FocusTarget& aFocusTarget,
814 bool aScheduleComposite, uint32_t aPaintSequenceNumber,
815 bool aIsRepeatTransaction, bool aHitTestUpdate) {
816 if (!aIsRepeatTransaction && mLayerManager && mLayerManager->GetRoot()) {
817 AutoResolveRefLayers resolve(mCompositionManager, this, nullptr);
819 if (mApzUpdater) {
820 mApzUpdater->UpdateFocusState(mRootLayerTreeID, aId, aFocusTarget);
821 if (aHitTestUpdate) {
822 mApzUpdater->UpdateHitTestingTree(
823 mLayerManager->GetRoot(), aIsFirstPaint, aId, aPaintSequenceNumber);
827 mLayerManager->NotifyShadowTreeTransaction();
829 if (aScheduleComposite) {
830 ScheduleComposition();
834 void CompositorBridgeParent::ScheduleComposition() {
835 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
836 if (mPaused) {
837 return;
840 if (mWrBridge) {
841 mWrBridge->ScheduleGenerateFrame();
842 } else {
843 mCompositorScheduler->ScheduleComposition();
847 // Go down the composite layer tree, setting properties to match their
848 // content-side counterparts.
849 /* static */
850 void CompositorBridgeParent::SetShadowProperties(Layer* aLayer) {
851 ForEachNode<ForwardIterator>(aLayer, [](Layer* layer) {
852 if (Layer* maskLayer = layer->GetMaskLayer()) {
853 SetShadowProperties(maskLayer);
855 for (size_t i = 0; i < layer->GetAncestorMaskLayerCount(); i++) {
856 SetShadowProperties(layer->GetAncestorMaskLayerAt(i));
859 // FIXME: Bug 717688 -- Do these updates in
860 // LayerTransactionParent::RecvUpdate.
861 HostLayer* layerCompositor = layer->AsHostLayer();
862 // Set the layerComposite's base transform to the layer's base transform.
863 const auto& animations = layer->GetPropertyAnimationGroups();
864 // If there is any animation, the animation value will override
865 // non-animated value later, so we don't need to set the non-animated
866 // value here.
867 if (animations.IsEmpty()) {
868 layerCompositor->SetShadowBaseTransform(layer->GetBaseTransform());
869 layerCompositor->SetShadowTransformSetByAnimation(false);
870 layerCompositor->SetShadowOpacity(layer->GetOpacity());
871 layerCompositor->SetShadowOpacitySetByAnimation(false);
873 layerCompositor->SetShadowVisibleRegion(layer->GetVisibleRegion());
874 layerCompositor->SetShadowClipRect(layer->GetClipRect());
878 void CompositorBridgeParent::CompositeToTarget(VsyncId aId, DrawTarget* aTarget,
879 const gfx::IntRect* aRect) {
880 AUTO_PROFILER_TRACING_MARKER("Paint", "Composite", GRAPHICS);
881 AUTO_PROFILER_LABEL("CompositorBridgeParent::CompositeToTarget", GRAPHICS);
882 PerfStats::AutoMetricRecording<PerfStats::Metric::Compositing> autoRecording;
884 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread(),
885 "Composite can only be called on the compositor thread");
886 TimeStamp start = TimeStamp::Now();
888 if (!CanComposite()) {
889 TimeStamp end = TimeStamp::Now();
890 DidComposite(aId, start, end);
891 return;
894 AutoResolveRefLayers resolve(mCompositionManager, this);
896 nsCString none;
897 if (aTarget) {
898 mLayerManager->BeginTransactionWithDrawTarget(aTarget, *aRect);
899 } else {
900 mLayerManager->BeginTransaction(none);
903 SetShadowProperties(mLayerManager->GetRoot());
905 if (mForceCompositionTask && !mOverrideComposeReadiness) {
906 if (mCompositionManager->ReadyForCompose()) {
907 mForceCompositionTask->Cancel();
908 mForceCompositionTask = nullptr;
909 } else {
910 return;
914 mCompositionManager->ComputeRotation();
916 SampleTime time = mTestTime ? SampleTime::FromTest(*mTestTime)
917 : mCompositorScheduler->GetLastComposeTime();
918 bool requestNextFrame =
919 mCompositionManager->TransformShadowTree(time, mVsyncRate);
921 if (requestNextFrame) {
922 ScheduleComposition();
925 RenderTraceLayers(mLayerManager->GetRoot(), "0000");
927 if (StaticPrefs::layers_dump_host_layers() || StaticPrefs::layers_dump()) {
928 printf_stderr("Painting --- compositing layer tree:\n");
929 mLayerManager->Dump(/* aSorted = */ true);
931 mLayerManager->SetDebugOverlayWantsNextFrame(false);
932 mLayerManager->EndTransaction(time.Time());
934 if (!aTarget) {
935 TimeStamp end = TimeStamp::Now();
936 DidComposite(aId, start, end);
939 // We're not really taking advantage of the stored composite-again-time here.
940 // We might be able to skip the next few composites altogether. However,
941 // that's a bit complex to implement and we'll get most of the advantage
942 // by skipping compositing when we detect there's nothing invalid. This is why
943 // we do "composite until" rather than "composite again at".
945 // TODO(bug 1328602) Figure out what we should do here with the render thread.
946 if (!mLayerManager->GetCompositeUntilTime().IsNull() ||
947 mLayerManager->DebugOverlayWantsNextFrame()) {
948 ScheduleComposition();
951 #ifdef COMPOSITOR_PERFORMANCE_WARNING
952 TimeDuration executionTime =
953 TimeStamp::Now() - mCompositorScheduler->GetLastComposeTime().Time();
954 TimeDuration frameBudget = TimeDuration::FromMilliseconds(15);
955 int32_t frameRate = CalculateCompositionFrameRate();
956 if (frameRate > 0) {
957 frameBudget = TimeDuration::FromSeconds(1.0 / frameRate);
959 if (executionTime > frameBudget) {
960 printf_stderr("Compositor: Composite execution took %4.1f ms\n",
961 executionTime.ToMilliseconds());
963 #endif
965 // 0 -> Full-tilt composite
966 if (StaticPrefs::layers_offmainthreadcomposition_frame_rate() == 0 ||
967 mLayerManager->AlwaysScheduleComposite()) {
968 // Special full-tilt composite mode for performance testing
969 ScheduleComposition();
972 // TODO(bug 1328602) Need an equivalent that works with the rende thread.
973 mLayerManager->SetCompositionTime(TimeStamp());
975 mozilla::Telemetry::AccumulateTimeDelta(mozilla::Telemetry::COMPOSITE_TIME,
976 start);
979 void CompositorBridgeParent::ForceComposeToTarget(DrawTarget* aTarget,
980 const gfx::IntRect* aRect) {
981 AUTO_PROFILER_LABEL("CompositorBridgeParent::ForceComposeToTarget", GRAPHICS);
983 AutoRestore<bool> override(mOverrideComposeReadiness);
984 mOverrideComposeReadiness = true;
985 mCompositorScheduler->ForceComposeToTarget(aTarget, aRect);
988 PAPZCTreeManagerParent* CompositorBridgeParent::AllocPAPZCTreeManagerParent(
989 const LayersId& aLayersId) {
990 // This should only ever get called in the GPU process.
991 MOZ_ASSERT(XRE_IsGPUProcess());
992 // We should only ever get this if APZ is enabled in this compositor.
993 MOZ_ASSERT(mOptions.UseAPZ());
994 // The mApzcTreeManager and mApzUpdater should have been created via
995 // RecvInitialize()
996 MOZ_ASSERT(mApzcTreeManager);
997 MOZ_ASSERT(mApzUpdater);
998 // The main process should pass in 0 because we assume mRootLayerTreeID
999 MOZ_ASSERT(!aLayersId.IsValid());
1001 MonitorAutoLock lock(*sIndirectLayerTreesLock);
1002 CompositorBridgeParent::LayerTreeState& state =
1003 sIndirectLayerTrees[mRootLayerTreeID];
1004 MOZ_ASSERT(state.mParent.get() == this);
1005 MOZ_ASSERT(!state.mApzcTreeManagerParent);
1006 state.mApzcTreeManagerParent = new APZCTreeManagerParent(
1007 mRootLayerTreeID, mApzcTreeManager, mApzUpdater);
1009 return state.mApzcTreeManagerParent;
1012 bool CompositorBridgeParent::DeallocPAPZCTreeManagerParent(
1013 PAPZCTreeManagerParent* aActor) {
1014 delete aActor;
1015 return true;
1018 void CompositorBridgeParent::AllocateAPZCTreeManagerParent(
1019 const MonitorAutoLock& aProofOfLayerTreeStateLock,
1020 const LayersId& aLayersId, LayerTreeState& aState) {
1021 MOZ_ASSERT(aState.mParent == this);
1022 MOZ_ASSERT(mApzcTreeManager);
1023 MOZ_ASSERT(mApzUpdater);
1024 MOZ_ASSERT(!aState.mApzcTreeManagerParent);
1025 aState.mApzcTreeManagerParent =
1026 new APZCTreeManagerParent(aLayersId, mApzcTreeManager, mApzUpdater);
1029 PAPZParent* CompositorBridgeParent::AllocPAPZParent(const LayersId& aLayersId) {
1030 // This is the CompositorBridgeParent for a window, and so should only be
1031 // creating a PAPZ instance if it lives in the GPU process. Instances that
1032 // live in the UI process should going through SetControllerForLayerTree.
1033 MOZ_RELEASE_ASSERT(XRE_IsGPUProcess());
1035 // We should only ever get this if APZ is enabled on this compositor.
1036 MOZ_RELEASE_ASSERT(mOptions.UseAPZ());
1038 // The main process should pass in 0 because we assume mRootLayerTreeID
1039 MOZ_RELEASE_ASSERT(!aLayersId.IsValid());
1041 RemoteContentController* controller = new RemoteContentController();
1043 // Increment the controller's refcount before we return it. This will keep the
1044 // controller alive until it is released by IPDL in DeallocPAPZParent.
1045 controller->AddRef();
1047 MonitorAutoLock lock(*sIndirectLayerTreesLock);
1048 CompositorBridgeParent::LayerTreeState& state =
1049 sIndirectLayerTrees[mRootLayerTreeID];
1050 MOZ_RELEASE_ASSERT(!state.mController);
1051 state.mController = controller;
1053 return controller;
1056 bool CompositorBridgeParent::DeallocPAPZParent(PAPZParent* aActor) {
1057 RemoteContentController* controller =
1058 static_cast<RemoteContentController*>(aActor);
1059 controller->Release();
1060 return true;
1063 RefPtr<APZSampler> CompositorBridgeParent::GetAPZSampler() const {
1064 return mApzSampler;
1067 RefPtr<APZUpdater> CompositorBridgeParent::GetAPZUpdater() const {
1068 return mApzUpdater;
1071 RefPtr<OMTASampler> CompositorBridgeParent::GetOMTASampler() const {
1072 return mOMTASampler;
1075 CompositorBridgeParent*
1076 CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(
1077 const LayersId& aLayersId) {
1078 MonitorAutoLock lock(*sIndirectLayerTreesLock);
1079 return sIndirectLayerTrees[aLayersId].mParent;
1082 /*static*/
1083 RefPtr<CompositorBridgeParent>
1084 CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(
1085 const wr::WindowId& aWindowId) {
1086 MonitorAutoLock lock(*sIndirectLayerTreesLock);
1087 for (auto it = sIndirectLayerTrees.begin(); it != sIndirectLayerTrees.end();
1088 it++) {
1089 LayerTreeState* state = &it->second;
1090 if (!state->mWrBridge) {
1091 continue;
1093 // state->mWrBridge might be a root WebRenderBridgeParent or one of a
1094 // content process, but in either case the state->mParent will be the same.
1095 // So we don't need to distinguish between the two.
1096 if (RefPtr<wr::WebRenderAPI> api = state->mWrBridge->GetWebRenderAPI()) {
1097 if (api->GetId() == aWindowId) {
1098 return state->mParent;
1102 return nullptr;
1105 bool CompositorBridgeParent::CanComposite() {
1106 return mLayerManager && mLayerManager->GetRoot() && !mPaused;
1109 void CompositorBridgeParent::ScheduleRotationOnCompositorThread(
1110 const TargetConfig& aTargetConfig, bool aIsFirstPaint) {
1111 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1113 if (!aIsFirstPaint && !mCompositionManager->IsFirstPaint() &&
1114 mCompositionManager->RequiresReorientation(aTargetConfig.orientation())) {
1115 if (mForceCompositionTask != nullptr) {
1116 mForceCompositionTask->Cancel();
1118 RefPtr<CancelableRunnable> task = NewCancelableRunnableMethod(
1119 "layers::CompositorBridgeParent::ForceComposition", this,
1120 &CompositorBridgeParent::ForceComposition);
1121 mForceCompositionTask = task;
1122 if (StaticPrefs::layers_orientation_sync_timeout() == 0) {
1123 CompositorThread()->Dispatch(task.forget());
1124 } else {
1125 CompositorThread()->DelayedDispatch(
1126 task.forget(), StaticPrefs::layers_orientation_sync_timeout());
1131 void CompositorBridgeParent::ShadowLayersUpdated(
1132 LayerTransactionParent* aLayerTree, const TransactionInfo& aInfo,
1133 bool aHitTestUpdate) {
1134 const TargetConfig& targetConfig = aInfo.targetConfig();
1136 ScheduleRotationOnCompositorThread(targetConfig, aInfo.isFirstPaint());
1138 // Instruct the LayerManager to update its render bounds now. Since all the
1139 // orientation change, dimension change would be done at the stage, update the
1140 // size here is free of race condition.
1141 mLayerManager->UpdateRenderBounds(targetConfig.naturalBounds());
1142 mLayerManager->SetRegionToClear(targetConfig.clearRegion());
1143 if (mLayerManager->GetCompositor()) {
1144 mLayerManager->GetCompositor()->SetScreenRotation(targetConfig.rotation());
1147 mCompositionManager->Updated(aInfo.isFirstPaint(), targetConfig);
1148 Layer* root = aLayerTree->GetRoot();
1149 mLayerManager->SetRoot(root);
1151 if (mApzUpdater && !aInfo.isRepeatTransaction()) {
1152 mApzUpdater->UpdateFocusState(mRootLayerTreeID, mRootLayerTreeID,
1153 aInfo.focusTarget());
1155 if (aHitTestUpdate) {
1156 AutoResolveRefLayers resolve(mCompositionManager);
1158 mApzUpdater->UpdateHitTestingTree(root, aInfo.isFirstPaint(),
1159 mRootLayerTreeID,
1160 aInfo.paintSequenceNumber());
1164 // The transaction ID might get reset to 1 if the page gets reloaded, see
1165 // https://bugzilla.mozilla.org/show_bug.cgi?id=1145295#c41
1166 // Otherwise, it should be continually increasing.
1167 MOZ_ASSERT(aInfo.id() == TransactionId{1} ||
1168 aInfo.id() > mPendingTransaction);
1169 mPendingTransaction = aInfo.id();
1170 mRefreshStartTime = aInfo.refreshStart();
1171 mTxnStartTime = aInfo.transactionStart();
1172 mFwdTime = aInfo.fwdTime();
1173 RegisterPayloads(aLayerTree, aInfo.payload());
1175 if (root) {
1176 SetShadowProperties(root);
1178 if (aInfo.scheduleComposite()) {
1179 ScheduleComposition();
1180 if (mPaused) {
1181 TimeStamp now = TimeStamp::Now();
1182 DidComposite(VsyncId(), now, now);
1185 mLayerManager->NotifyShadowTreeTransaction();
1188 void CompositorBridgeParent::ScheduleComposite(
1189 LayerTransactionParent* aLayerTree) {
1190 ScheduleComposition();
1193 bool CompositorBridgeParent::SetTestSampleTime(const LayersId& aId,
1194 const TimeStamp& aTime) {
1195 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1197 if (aTime.IsNull()) {
1198 return false;
1201 mTestTime = Some(aTime);
1202 if (mApzcTreeManager) {
1203 mApzcTreeManager->SetTestSampleTime(mTestTime);
1206 if (mWrBridge) {
1207 mWrBridge->FlushRendering();
1208 return true;
1211 bool testComposite =
1212 mCompositionManager && mCompositorScheduler->NeedsComposite();
1214 // Update but only if we were already scheduled to animate
1215 if (testComposite) {
1216 AutoResolveRefLayers resolve(mCompositionManager);
1217 bool requestNextFrame = mCompositionManager->TransformShadowTree(
1218 SampleTime::FromTest(aTime), mVsyncRate);
1219 if (!requestNextFrame) {
1220 CancelCurrentCompositeTask();
1221 // Pretend we composited in case someone is wating for this event.
1222 TimeStamp now = TimeStamp::Now();
1223 DidComposite(VsyncId(), now, now);
1227 return true;
1230 void CompositorBridgeParent::LeaveTestMode(const LayersId& aId) {
1231 mTestTime = Nothing();
1232 if (mApzcTreeManager) {
1233 mApzcTreeManager->SetTestSampleTime(mTestTime);
1237 void CompositorBridgeParent::ApplyAsyncProperties(
1238 LayerTransactionParent* aLayerTree, TransformsToSkip aSkip) {
1239 // NOTE: This should only be used for testing. For example, when mTestTime is
1240 // non-empty, or when called from test-only methods like
1241 // LayerTransactionParent::RecvGetAnimationTransform.
1243 // Synchronously update the layer tree
1244 if (aLayerTree->GetRoot()) {
1245 AutoResolveRefLayers resolve(mCompositionManager);
1246 SetShadowProperties(mLayerManager->GetRoot());
1248 SampleTime time;
1249 if (mTestTime) {
1250 time = SampleTime::FromTest(*mTestTime);
1251 } else {
1252 time = mCompositorScheduler->GetLastComposeTime();
1254 bool requestNextFrame =
1255 mCompositionManager->TransformShadowTree(time, mVsyncRate, aSkip);
1256 if (!requestNextFrame) {
1257 CancelCurrentCompositeTask();
1258 // Pretend we composited in case someone is waiting for this event.
1259 TimeStamp now = TimeStamp::Now();
1260 DidComposite(VsyncId(), now, now);
1265 CompositorAnimationStorage* CompositorBridgeParent::GetAnimationStorage() {
1266 if (!mAnimationStorage) {
1267 mAnimationStorage = new CompositorAnimationStorage(this);
1269 return mAnimationStorage;
1272 void CompositorBridgeParent::NotifyJankedAnimations(
1273 const JankedAnimations& aJankedAnimations) {
1274 MOZ_ASSERT(!aJankedAnimations.empty());
1276 if (StaticPrefs::layout_animation_prerender_partial_jank()) {
1277 return;
1280 for (const auto& entry : aJankedAnimations) {
1281 const LayersId& layersId = entry.first;
1282 const nsTArray<uint64_t>& animations = entry.second;
1283 if (layersId == mRootLayerTreeID) {
1284 if (mLayerManager) {
1285 Unused << SendNotifyJankedAnimations(LayersId{0}, animations);
1287 // It unlikely happens multiple processes have janked animations at same
1288 // time, so it should be fine with enumerating sIndirectLayerTrees every
1289 // time.
1290 } else if (const LayerTreeState* state = GetIndirectShadowTree(layersId)) {
1291 if (ContentCompositorBridgeParent* cpcp =
1292 state->mContentCompositorBridgeParent) {
1293 Unused << cpcp->SendNotifyJankedAnimations(layersId, animations);
1299 void CompositorBridgeParent::SetTestAsyncScrollOffset(
1300 const LayersId& aLayersId, const ScrollableLayerGuid::ViewID& aScrollId,
1301 const CSSPoint& aPoint) {
1302 if (mApzUpdater) {
1303 MOZ_ASSERT(aLayersId.IsValid());
1304 mApzUpdater->SetTestAsyncScrollOffset(aLayersId, aScrollId, aPoint);
1308 void CompositorBridgeParent::SetTestAsyncZoom(
1309 const LayersId& aLayersId, const ScrollableLayerGuid::ViewID& aScrollId,
1310 const LayerToParentLayerScale& aZoom) {
1311 if (mApzUpdater) {
1312 MOZ_ASSERT(aLayersId.IsValid());
1313 mApzUpdater->SetTestAsyncZoom(aLayersId, aScrollId, aZoom);
1317 void CompositorBridgeParent::FlushApzRepaints(const LayersId& aLayersId) {
1318 MOZ_ASSERT(mApzUpdater);
1319 MOZ_ASSERT(aLayersId.IsValid());
1320 mApzUpdater->RunOnControllerThread(
1321 aLayersId, NS_NewRunnableFunction(
1322 "layers::CompositorBridgeParent::FlushApzRepaints",
1323 [=]() { APZCTreeManager::FlushApzRepaints(aLayersId); }));
1326 void CompositorBridgeParent::GetAPZTestData(const LayersId& aLayersId,
1327 APZTestData* aOutData) {
1328 if (mApzUpdater) {
1329 MOZ_ASSERT(aLayersId.IsValid());
1330 mApzUpdater->GetAPZTestData(aLayersId, aOutData);
1334 void CompositorBridgeParent::GetFrameUniformity(const LayersId& aLayersId,
1335 FrameUniformityData* aOutData) {
1336 if (mCompositionManager) {
1337 mCompositionManager->GetFrameUniformity(aOutData);
1341 void CompositorBridgeParent::SetConfirmedTargetAPZC(
1342 const LayersId& aLayersId, const uint64_t& aInputBlockId,
1343 nsTArray<ScrollableLayerGuid>&& aTargets) {
1344 if (!mApzcTreeManager || !mApzUpdater) {
1345 return;
1347 // Need to specifically bind this since it's overloaded.
1348 void (APZCTreeManager::*setTargetApzcFunc)(
1349 uint64_t, const nsTArray<ScrollableLayerGuid>&) =
1350 &APZCTreeManager::SetTargetAPZC;
1351 RefPtr<Runnable> task =
1352 NewRunnableMethod<uint64_t,
1353 StoreCopyPassByRRef<nsTArray<ScrollableLayerGuid>>>(
1354 "layers::CompositorBridgeParent::SetConfirmedTargetAPZC",
1355 mApzcTreeManager.get(), setTargetApzcFunc, aInputBlockId,
1356 std::move(aTargets));
1357 mApzUpdater->RunOnControllerThread(aLayersId, task.forget());
1360 void CompositorBridgeParent::SetFixedLayerMargins(ScreenIntCoord aTop,
1361 ScreenIntCoord aBottom) {
1362 if (AsyncCompositionManager* manager = GetCompositionManager(nullptr)) {
1363 manager->SetFixedLayerMargins(aTop, aBottom);
1366 if (mApzcTreeManager) {
1367 mApzcTreeManager->SetFixedLayerMargins(aTop, aBottom);
1370 Invalidate();
1371 ScheduleComposition();
1374 void CompositorBridgeParent::InitializeLayerManager(
1375 const nsTArray<LayersBackend>& aBackendHints) {
1376 NS_ASSERTION(!mLayerManager, "Already initialised mLayerManager");
1377 NS_ASSERTION(!mCompositor, "Already initialised mCompositor");
1379 mCompositor = NewCompositor(aBackendHints);
1380 if (!mCompositor) {
1381 return;
1383 #ifdef XP_WIN
1384 if (mCompositor->AsBasicCompositor() && XRE_IsGPUProcess()) {
1385 // BasicCompositor does not use CompositorWindow,
1386 // then if CompositorWindow exists, it needs to be destroyed.
1387 mWidget->AsWindows()->DestroyCompositorWindow();
1389 #endif
1390 mLayerManager = new LayerManagerComposite(mCompositor);
1391 mLayerManager->SetCompositorBridgeID(mCompositorBridgeID);
1393 MonitorAutoLock lock(*sIndirectLayerTreesLock);
1394 sIndirectLayerTrees[mRootLayerTreeID].mLayerManager = mLayerManager;
1397 RefPtr<Compositor> CompositorBridgeParent::NewCompositor(
1398 const nsTArray<LayersBackend>& aBackendHints) {
1399 for (size_t i = 0; i < aBackendHints.Length(); ++i) {
1400 RefPtr<Compositor> compositor;
1401 if (aBackendHints[i] == LayersBackend::LAYERS_OPENGL) {
1402 compositor =
1403 new CompositorOGL(this, mWidget, mEGLSurfaceSize.width,
1404 mEGLSurfaceSize.height, mUseExternalSurfaceSize);
1405 } else if (aBackendHints[i] == LayersBackend::LAYERS_BASIC) {
1406 #ifdef MOZ_WIDGET_GTK
1407 if (gfxVars::UseXRender()) {
1408 compositor = new X11BasicCompositor(this, mWidget);
1409 } else
1410 #endif
1412 compositor = new BasicCompositor(this, mWidget);
1414 #ifdef XP_WIN
1415 } else if (aBackendHints[i] == LayersBackend::LAYERS_D3D11) {
1416 compositor = new CompositorD3D11(this, mWidget);
1417 #endif
1419 nsCString failureReason;
1421 // Some software GPU emulation implementations will happily try to create
1422 // unreasonably big surfaces and then fail in awful ways.
1423 // Let's at least limit this to the default max texture size we use for
1424 // content, anything larger than that will fail to render on the content
1425 // side anyway. We can revisit this value and make it even tighter if need
1426 // be.
1427 const int max_fb_size = 32767;
1428 const LayoutDeviceIntSize size = mWidget->GetClientSize();
1429 if (size.width > max_fb_size || size.height > max_fb_size) {
1430 failureReason = "FEATURE_FAILURE_MAX_FRAMEBUFFER_SIZE";
1431 return nullptr;
1434 MOZ_ASSERT(!gfxVars::UseWebRender() ||
1435 aBackendHints[i] == LayersBackend::LAYERS_BASIC);
1436 if (compositor && compositor->Initialize(&failureReason)) {
1437 if (failureReason.IsEmpty()) {
1438 failureReason = "SUCCESS";
1441 // should only report success here
1442 if (aBackendHints[i] == LayersBackend::LAYERS_OPENGL) {
1443 Telemetry::Accumulate(Telemetry::OPENGL_COMPOSITING_FAILURE_ID,
1444 failureReason);
1446 #ifdef XP_WIN
1447 else if (aBackendHints[i] == LayersBackend::LAYERS_D3D11) {
1448 Telemetry::Accumulate(Telemetry::D3D11_COMPOSITING_FAILURE_ID,
1449 failureReason);
1451 #endif
1453 return compositor;
1456 // report any failure reasons here
1457 if (aBackendHints[i] == LayersBackend::LAYERS_OPENGL) {
1458 gfxCriticalNote << "[OPENGL] Failed to init compositor with reason: "
1459 << failureReason.get();
1460 Telemetry::Accumulate(Telemetry::OPENGL_COMPOSITING_FAILURE_ID,
1461 failureReason);
1463 #ifdef XP_WIN
1464 else if (aBackendHints[i] == LayersBackend::LAYERS_D3D11) {
1465 gfxCriticalNote << "[D3D11] Failed to init compositor with reason: "
1466 << failureReason.get();
1467 Telemetry::Accumulate(Telemetry::D3D11_COMPOSITING_FAILURE_ID,
1468 failureReason);
1470 #endif
1473 return nullptr;
1476 PLayerTransactionParent* CompositorBridgeParent::AllocPLayerTransactionParent(
1477 const nsTArray<LayersBackend>& aBackendHints, const LayersId& aId) {
1478 MOZ_ASSERT(!aId.IsValid());
1480 #ifdef XP_WIN
1481 // This is needed to avoid freezing the window on a device crash on double
1482 // buffering, see bug 1549674.
1483 if (gfxVars::UseDoubleBufferingWithCompositor() && XRE_IsGPUProcess() &&
1484 aBackendHints.Contains(LayersBackend::LAYERS_D3D11)) {
1485 mWidget->AsWindows()->EnsureCompositorWindow();
1487 #endif
1489 InitializeLayerManager(aBackendHints);
1491 if (!mLayerManager) {
1492 NS_WARNING("Failed to initialise Compositor");
1493 LayerTransactionParent* p = new LayerTransactionParent(
1494 /* aManager */ nullptr, this, /* aAnimStorage */ nullptr,
1495 mRootLayerTreeID, mVsyncRate);
1496 p->AddIPDLReference();
1497 return p;
1500 mCompositionManager = new AsyncCompositionManager(this, mLayerManager);
1502 LayerTransactionParent* p = new LayerTransactionParent(
1503 mLayerManager, this, GetAnimationStorage(), mRootLayerTreeID, mVsyncRate);
1504 p->AddIPDLReference();
1505 return p;
1508 bool CompositorBridgeParent::DeallocPLayerTransactionParent(
1509 PLayerTransactionParent* actor) {
1510 static_cast<LayerTransactionParent*>(actor)->ReleaseIPDLReference();
1511 return true;
1514 CompositorBridgeParent* CompositorBridgeParent::GetCompositorBridgeParent(
1515 uint64_t id) {
1516 AssertIsInCompositorThread();
1517 CompositorMap::iterator it = sCompositorMap->find(id);
1518 return it != sCompositorMap->end() ? it->second : nullptr;
1521 void CompositorBridgeParent::AddCompositor(CompositorBridgeParent* compositor,
1522 uint64_t* outID) {
1523 AssertIsInCompositorThread();
1525 static uint64_t sNextID = 1;
1527 ++sNextID;
1528 (*sCompositorMap)[sNextID] = compositor;
1529 *outID = sNextID;
1532 CompositorBridgeParent* CompositorBridgeParent::RemoveCompositor(uint64_t id) {
1533 AssertIsInCompositorThread();
1535 CompositorMap::iterator it = sCompositorMap->find(id);
1536 if (it == sCompositorMap->end()) {
1537 return nullptr;
1539 CompositorBridgeParent* retval = it->second;
1540 sCompositorMap->erase(it);
1541 return retval;
1544 void CompositorBridgeParent::NotifyVsync(const VsyncEvent& aVsync,
1545 const LayersId& aLayersId) {
1546 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
1547 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1549 MonitorAutoLock lock(*sIndirectLayerTreesLock);
1550 auto it = sIndirectLayerTrees.find(aLayersId);
1551 if (it == sIndirectLayerTrees.end()) return;
1553 CompositorBridgeParent* cbp = it->second.mParent;
1554 if (!cbp || !cbp->mWidget) return;
1556 RefPtr<VsyncObserver> obs = cbp->mWidget->GetVsyncObserver();
1557 if (!obs) return;
1559 obs->NotifyVsync(aVsync);
1562 /* static */
1563 void CompositorBridgeParent::ScheduleForcedComposition(
1564 const LayersId& aLayersId) {
1565 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
1566 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1568 MonitorAutoLock lock(*sIndirectLayerTreesLock);
1569 auto it = sIndirectLayerTrees.find(aLayersId);
1570 if (it == sIndirectLayerTrees.end()) {
1571 return;
1574 CompositorBridgeParent* cbp = it->second.mParent;
1575 if (!cbp || !cbp->mWidget) {
1576 return;
1579 if (cbp->mWrBridge) {
1580 cbp->mWrBridge->ScheduleForcedGenerateFrame();
1581 } else if (cbp->CanComposite()) {
1582 cbp->mCompositorScheduler->ScheduleComposition();
1586 mozilla::ipc::IPCResult CompositorBridgeParent::RecvNotifyChildCreated(
1587 const LayersId& child, CompositorOptions* aOptions) {
1588 MonitorAutoLock lock(*sIndirectLayerTreesLock);
1589 NotifyChildCreated(child);
1590 *aOptions = mOptions;
1591 return IPC_OK();
1594 mozilla::ipc::IPCResult CompositorBridgeParent::RecvNotifyChildRecreated(
1595 const LayersId& aChild, CompositorOptions* aOptions) {
1596 MonitorAutoLock lock(*sIndirectLayerTreesLock);
1598 if (sIndirectLayerTrees.find(aChild) != sIndirectLayerTrees.end()) {
1599 NS_WARNING("Invalid to register the same layer tree twice");
1600 return IPC_FAIL_NO_REASON(this);
1603 NotifyChildCreated(aChild);
1604 *aOptions = mOptions;
1605 return IPC_OK();
1608 void CompositorBridgeParent::NotifyChildCreated(LayersId aChild) {
1609 sIndirectLayerTreesLock->AssertCurrentThreadOwns();
1610 sIndirectLayerTrees[aChild].mParent = this;
1611 sIndirectLayerTrees[aChild].mLayerManager = mLayerManager;
1614 mozilla::ipc::IPCResult CompositorBridgeParent::RecvMapAndNotifyChildCreated(
1615 const LayersId& aChild, const base::ProcessId& aOwnerPid,
1616 CompositorOptions* aOptions) {
1617 // We only use this message when the remote compositor is in the GPU process.
1618 // It is harmless to call it, though.
1619 MOZ_ASSERT(XRE_IsGPUProcess());
1621 LayerTreeOwnerTracker::Get()->Map(aChild, aOwnerPid);
1623 MonitorAutoLock lock(*sIndirectLayerTreesLock);
1624 NotifyChildCreated(aChild);
1625 *aOptions = mOptions;
1626 return IPC_OK();
1629 enum class CompositorOptionsChangeKind {
1630 eSupported,
1631 eBestEffort,
1632 eUnsupported
1635 static CompositorOptionsChangeKind ClassifyCompositorOptionsChange(
1636 const CompositorOptions& aOld, const CompositorOptions& aNew) {
1637 if (aOld == aNew) {
1638 return CompositorOptionsChangeKind::eSupported;
1640 if (aOld.UseAdvancedLayers() == aNew.UseAdvancedLayers() &&
1641 aOld.UseWebRender() == aNew.UseWebRender() &&
1642 aOld.InitiallyPaused() == aNew.InitiallyPaused()) {
1643 // Only APZ enablement changed.
1644 return CompositorOptionsChangeKind::eBestEffort;
1646 return CompositorOptionsChangeKind::eUnsupported;
1649 mozilla::ipc::IPCResult CompositorBridgeParent::RecvAdoptChild(
1650 const LayersId& child) {
1651 RefPtr<APZUpdater> oldApzUpdater;
1652 APZCTreeManagerParent* parent;
1653 bool scheduleComposition = false;
1654 bool apzEnablementChanged = false;
1655 RefPtr<ContentCompositorBridgeParent> cpcp;
1656 RefPtr<WebRenderBridgeParent> childWrBridge;
1658 // Before adopting the child, save the old compositor's root content
1659 // controller. We may need this to clear old layer transforms associated
1660 // with the child.
1661 // This is outside the lock because GetGeckoContentControllerForRoot()
1662 // does its own locking.
1663 RefPtr<GeckoContentController> oldRootController =
1664 GetGeckoContentControllerForRoot(child);
1666 { // scope lock
1667 MonitorAutoLock lock(*sIndirectLayerTreesLock);
1668 // If child is already belong to this CompositorBridgeParent,
1669 // no need to handle adopting child.
1670 if (sIndirectLayerTrees[child].mParent == this) {
1671 return IPC_OK();
1674 if (sIndirectLayerTrees[child].mParent) {
1675 switch (ClassifyCompositorOptionsChange(
1676 sIndirectLayerTrees[child].mParent->mOptions, mOptions)) {
1677 case CompositorOptionsChangeKind::eUnsupported: {
1678 MOZ_ASSERT(false,
1679 "Moving tab between windows whose compositor options"
1680 "differ in unsupported ways. Things may break in "
1681 "unexpected ways");
1682 break;
1684 case CompositorOptionsChangeKind::eBestEffort: {
1685 NS_WARNING(
1686 "Moving tab between windows with different APZ enablement. "
1687 "This is supported on a best-effort basis, but some things may "
1688 "break.");
1689 apzEnablementChanged = true;
1690 break;
1692 case CompositorOptionsChangeKind::eSupported: {
1693 // The common case, no action required.
1694 break;
1697 oldApzUpdater = sIndirectLayerTrees[child].mParent->mApzUpdater;
1699 NotifyChildCreated(child);
1700 if (sIndirectLayerTrees[child].mLayerTree) {
1701 sIndirectLayerTrees[child].mLayerTree->SetLayerManager(
1702 mLayerManager, GetAnimationStorage());
1703 // Trigger composition to handle a case that mLayerTree was not composited
1704 // yet by previous CompositorBridgeParent, since nsRefreshDriver might
1705 // wait composition complete.
1706 scheduleComposition = true;
1708 if (mWrBridge) {
1709 childWrBridge = sIndirectLayerTrees[child].mWrBridge;
1710 cpcp = sIndirectLayerTrees[child].mContentCompositorBridgeParent;
1712 parent = sIndirectLayerTrees[child].mApzcTreeManagerParent;
1715 if (scheduleComposition) {
1716 ScheduleComposition();
1719 if (childWrBridge) {
1720 MOZ_ASSERT(mWrBridge);
1721 RefPtr<wr::WebRenderAPI> api = mWrBridge->GetWebRenderAPI();
1722 api = api->Clone();
1723 wr::Epoch newEpoch = childWrBridge->UpdateWebRender(
1724 mWrBridge->CompositorScheduler(), std::move(api),
1725 mWrBridge->AsyncImageManager(),
1726 mWrBridge->GetTextureFactoryIdentifier());
1727 // Pretend we composited, since parent CompositorBridgeParent was replaced.
1728 TimeStamp now = TimeStamp::Now();
1729 NotifyPipelineRendered(childWrBridge->PipelineId(), newEpoch, VsyncId(),
1730 now, now, now);
1733 if (oldApzUpdater) {
1734 // If we are moving a child from an APZ-enabled window to an APZ-disabled
1735 // window (which can happen if e.g. a WebExtension moves a tab into a
1736 // popup window), try to handle it gracefully by clearing the old layer
1737 // transforms associated with the child. (Since the new compositor is
1738 // APZ-disabled, there will be nothing to update the transforms going
1739 // forward.)
1740 if (!mApzUpdater && oldRootController) {
1741 // Tell the old APZCTreeManager not to send any more layer transforms
1742 // for this layers ids.
1743 oldApzUpdater->MarkAsDetached(child);
1745 // Clear the current transforms.
1746 nsTArray<MatrixMessage> clear;
1747 clear.AppendElement(MatrixMessage(Nothing(), ScreenRect(), child));
1748 oldRootController->NotifyLayerTransforms(std::move(clear));
1751 if (mApzUpdater) {
1752 if (parent) {
1753 MOZ_ASSERT(mApzcTreeManager);
1754 parent->ChildAdopted(mApzcTreeManager, mApzUpdater);
1756 mApzUpdater->NotifyLayerTreeAdopted(child, oldApzUpdater);
1758 if (apzEnablementChanged) {
1759 Unused << SendCompositorOptionsChanged(child, mOptions);
1761 return IPC_OK();
1764 PWebRenderBridgeParent* CompositorBridgeParent::AllocPWebRenderBridgeParent(
1765 const wr::PipelineId& aPipelineId, const LayoutDeviceIntSize& aSize,
1766 const WindowKind& aWindowKind) {
1767 MOZ_ASSERT(wr::AsLayersId(aPipelineId) == mRootLayerTreeID);
1768 MOZ_ASSERT(!mWrBridge);
1769 MOZ_ASSERT(!mCompositor);
1770 MOZ_ASSERT(!mCompositorScheduler);
1771 MOZ_ASSERT(mWidget);
1773 #ifdef XP_WIN
1774 if (mWidget && (DeviceManagerDx::Get()->CanUseDComp() ||
1775 gfxVars::UseWebRenderFlipSequentialWin())) {
1776 mWidget->AsWindows()->EnsureCompositorWindow();
1778 #endif
1780 RefPtr<widget::CompositorWidget> widget = mWidget;
1781 wr::WrWindowId windowId = wr::NewWindowId();
1782 if (mApzUpdater) {
1783 // If APZ is enabled, we need to register the APZ updater with the window id
1784 // before the updater thread is created in WebRenderAPI::Create, so
1785 // that the callback from the updater thread can find the right APZUpdater.
1786 mApzUpdater->SetWebRenderWindowId(windowId);
1788 if (mApzSampler) {
1789 // Same as for mApzUpdater, but for the sampler thread.
1790 mApzSampler->SetWebRenderWindowId(windowId);
1792 if (mOMTASampler) {
1793 // Same, but for the OMTA sampler.
1794 mOMTASampler->SetWebRenderWindowId(windowId);
1797 nsCString error("FEATURE_FAILURE_WEBRENDER_INITIALIZE_UNSPECIFIED");
1798 RefPtr<wr::WebRenderAPI> api = wr::WebRenderAPI::Create(
1799 this, std::move(widget), windowId, aSize, aWindowKind, error);
1800 if (!api) {
1801 mWrBridge =
1802 WebRenderBridgeParent::CreateDestroyed(aPipelineId, std::move(error));
1803 mWrBridge.get()->AddRef(); // IPDL reference
1804 return mWrBridge;
1807 wr::TransactionBuilder txn(api);
1808 txn.SetRootPipeline(aPipelineId);
1809 api->SendTransaction(txn);
1811 bool useCompositorWnd = false;
1812 #ifdef XP_WIN
1813 // Headless mode uses HeadlessWidget.
1814 if (mWidget->AsWindows()) {
1815 useCompositorWnd = !!mWidget->AsWindows()->GetCompositorHwnd();
1817 #endif
1818 mAsyncImageManager =
1819 new AsyncImagePipelineManager(api->Clone(), useCompositorWnd);
1820 RefPtr<AsyncImagePipelineManager> asyncMgr = mAsyncImageManager;
1821 mWrBridge = new WebRenderBridgeParent(this, aPipelineId, mWidget, nullptr,
1822 std::move(api), std::move(asyncMgr),
1823 mVsyncRate);
1824 mWrBridge.get()->AddRef(); // IPDL reference
1826 mCompositorScheduler = mWrBridge->CompositorScheduler();
1827 MOZ_ASSERT(mCompositorScheduler);
1828 { // scope lock
1829 MonitorAutoLock lock(*sIndirectLayerTreesLock);
1830 MOZ_ASSERT(sIndirectLayerTrees[mRootLayerTreeID].mWrBridge == nullptr);
1831 sIndirectLayerTrees[mRootLayerTreeID].mWrBridge = mWrBridge;
1833 return mWrBridge;
1836 bool CompositorBridgeParent::DeallocPWebRenderBridgeParent(
1837 PWebRenderBridgeParent* aActor) {
1838 WebRenderBridgeParent* parent = static_cast<WebRenderBridgeParent*>(aActor);
1840 MonitorAutoLock lock(*sIndirectLayerTreesLock);
1841 auto it = sIndirectLayerTrees.find(wr::AsLayersId(parent->PipelineId()));
1842 if (it != sIndirectLayerTrees.end()) {
1843 it->second.mWrBridge = nullptr;
1846 parent->Release(); // IPDL reference
1847 return true;
1850 webgpu::PWebGPUParent* CompositorBridgeParent::AllocPWebGPUParent() {
1851 MOZ_ASSERT(!mWebGPUBridge);
1852 mWebGPUBridge = new webgpu::WebGPUParent();
1853 mWebGPUBridge.get()->AddRef(); // IPDL reference
1854 return mWebGPUBridge;
1857 bool CompositorBridgeParent::DeallocPWebGPUParent(
1858 webgpu::PWebGPUParent* aActor) {
1859 webgpu::WebGPUParent* parent = static_cast<webgpu::WebGPUParent*>(aActor);
1860 MOZ_ASSERT(mWebGPUBridge == parent);
1861 parent->Release(); // IPDL reference
1862 mWebGPUBridge = nullptr;
1863 return true;
1866 void CompositorBridgeParent::NotifyMemoryPressure() {
1867 if (mWrBridge) {
1868 RefPtr<wr::WebRenderAPI> api = mWrBridge->GetWebRenderAPI();
1869 if (api) {
1870 api->NotifyMemoryPressure();
1875 void CompositorBridgeParent::AccumulateMemoryReport(wr::MemoryReport* aReport) {
1876 if (mWrBridge) {
1877 RefPtr<wr::WebRenderAPI> api = mWrBridge->GetWebRenderAPI();
1878 if (api) {
1879 api->AccumulateMemoryReport(aReport);
1884 /*static*/
1885 void CompositorBridgeParent::InitializeStatics() {
1886 gfxVars::SetForceSubpixelAAWherePossibleListener(&UpdateQualitySettings);
1887 gfxVars::SetWebRenderDebugFlagsListener(&UpdateDebugFlags);
1888 gfxVars::SetUseWebRenderMultithreadingListener(
1889 &UpdateWebRenderMultithreading);
1890 gfxVars::SetWebRenderBatchingLookbackListener(
1891 &UpdateWebRenderBatchingParameters);
1892 gfxVars::SetWebRenderProfilerUIListener(&UpdateWebRenderProfilerUI);
1895 /*static*/
1896 void CompositorBridgeParent::UpdateQualitySettings() {
1897 if (!CompositorThreadHolder::IsInCompositorThread()) {
1898 if (CompositorThread()) {
1899 CompositorThread()->Dispatch(
1900 NewRunnableFunction("CompositorBridgeParent::UpdateQualitySettings",
1901 &CompositorBridgeParent::UpdateQualitySettings));
1904 // If there is no compositor thread, e.g. due to shutdown, then we can
1905 // safefully just ignore this request.
1906 return;
1909 MonitorAutoLock lock(*sIndirectLayerTreesLock);
1910 ForEachWebRenderBridgeParent([&](WebRenderBridgeParent* wrBridge) -> void {
1911 wrBridge->UpdateQualitySettings();
1915 /*static*/
1916 void CompositorBridgeParent::UpdateDebugFlags() {
1917 if (!CompositorThreadHolder::IsInCompositorThread()) {
1918 if (CompositorThread()) {
1919 CompositorThread()->Dispatch(
1920 NewRunnableFunction("CompositorBridgeParent::UpdateDebugFlags",
1921 &CompositorBridgeParent::UpdateDebugFlags));
1924 // If there is no compositor thread, e.g. due to shutdown, then we can
1925 // safefully just ignore this request.
1926 return;
1929 MonitorAutoLock lock(*sIndirectLayerTreesLock);
1930 ForEachWebRenderBridgeParent([&](WebRenderBridgeParent* wrBridge) -> void {
1931 wrBridge->UpdateDebugFlags();
1935 /*static*/
1936 void CompositorBridgeParent::UpdateWebRenderMultithreading() {
1937 if (!CompositorThreadHolder::IsInCompositorThread()) {
1938 if (CompositorThread()) {
1939 CompositorThread()->Dispatch(NewRunnableFunction(
1940 "CompositorBridgeParent::UpdateWebRenderMultithreading",
1941 &CompositorBridgeParent::UpdateWebRenderMultithreading));
1944 return;
1947 MonitorAutoLock lock(*sIndirectLayerTreesLock);
1948 ForEachWebRenderBridgeParent([&](WebRenderBridgeParent* wrBridge) -> void {
1949 wrBridge->UpdateMultithreading();
1953 /*static*/
1954 void CompositorBridgeParent::UpdateWebRenderBatchingParameters() {
1955 if (!CompositorThreadHolder::IsInCompositorThread()) {
1956 if (CompositorThread()) {
1957 CompositorThread()->Dispatch(NewRunnableFunction(
1958 "CompositorBridgeParent::UpdateWebRenderBatchingParameters",
1959 &CompositorBridgeParent::UpdateWebRenderBatchingParameters));
1962 return;
1965 MonitorAutoLock lock(*sIndirectLayerTreesLock);
1966 ForEachWebRenderBridgeParent([&](WebRenderBridgeParent* wrBridge) -> void {
1967 wrBridge->UpdateBatchingParameters();
1971 /*static*/
1972 void CompositorBridgeParent::UpdateWebRenderProfilerUI() {
1973 if (!sIndirectLayerTreesLock) {
1974 return;
1976 MonitorAutoLock lock(*sIndirectLayerTreesLock);
1977 ForEachWebRenderBridgeParent([&](WebRenderBridgeParent* wrBridge) -> void {
1978 wrBridge->UpdateProfilerUI();
1982 RefPtr<WebRenderBridgeParent> CompositorBridgeParent::GetWebRenderBridgeParent()
1983 const {
1984 return mWrBridge;
1987 Maybe<TimeStamp> CompositorBridgeParent::GetTestingTimeStamp() const {
1988 return mTestTime;
1991 void EraseLayerState(LayersId aId) {
1992 RefPtr<APZUpdater> apz;
1994 { // scope lock
1995 MonitorAutoLock lock(*sIndirectLayerTreesLock);
1996 auto iter = sIndirectLayerTrees.find(aId);
1997 if (iter != sIndirectLayerTrees.end()) {
1998 CompositorBridgeParent* parent = iter->second.mParent;
1999 if (parent) {
2000 apz = parent->GetAPZUpdater();
2002 sIndirectLayerTrees.erase(iter);
2006 if (apz) {
2007 apz->NotifyLayerTreeRemoved(aId);
2011 /*static*/
2012 void CompositorBridgeParent::DeallocateLayerTreeId(LayersId aId) {
2013 MOZ_ASSERT(NS_IsMainThread());
2014 // Here main thread notifies compositor to remove an element from
2015 // sIndirectLayerTrees. This removed element might be queried soon.
2016 // Checking the elements of sIndirectLayerTrees exist or not before using.
2017 if (!CompositorThread()) {
2018 gfxCriticalError() << "Attempting to post to an invalid Compositor Thread";
2019 return;
2021 CompositorThread()->Dispatch(
2022 NewRunnableFunction("EraseLayerStateRunnable", &EraseLayerState, aId));
2025 static void UpdateControllerForLayersId(LayersId aLayersId,
2026 GeckoContentController* aController) {
2027 // Adopt ref given to us by SetControllerForLayerTree()
2028 MonitorAutoLock lock(*sIndirectLayerTreesLock);
2029 sIndirectLayerTrees[aLayersId].mController =
2030 already_AddRefed<GeckoContentController>(aController);
2033 ScopedLayerTreeRegistration::ScopedLayerTreeRegistration(
2034 APZCTreeManager* aApzctm, LayersId aLayersId, Layer* aRoot,
2035 GeckoContentController* aController)
2036 : mLayersId(aLayersId) {
2037 EnsureLayerTreeMapReady();
2038 MonitorAutoLock lock(*sIndirectLayerTreesLock);
2039 sIndirectLayerTrees[aLayersId].mRoot = aRoot;
2040 sIndirectLayerTrees[aLayersId].mController = aController;
2043 ScopedLayerTreeRegistration::~ScopedLayerTreeRegistration() {
2044 MonitorAutoLock lock(*sIndirectLayerTreesLock);
2045 sIndirectLayerTrees.erase(mLayersId);
2048 /*static*/
2049 void CompositorBridgeParent::SetControllerForLayerTree(
2050 LayersId aLayersId, GeckoContentController* aController) {
2051 // This ref is adopted by UpdateControllerForLayersId().
2052 aController->AddRef();
2053 CompositorThread()->Dispatch(NewRunnableFunction(
2054 "UpdateControllerForLayersIdRunnable", &UpdateControllerForLayersId,
2055 aLayersId, aController));
2058 /*static*/
2059 already_AddRefed<IAPZCTreeManager> CompositorBridgeParent::GetAPZCTreeManager(
2060 LayersId aLayersId) {
2061 EnsureLayerTreeMapReady();
2062 MonitorAutoLock lock(*sIndirectLayerTreesLock);
2063 LayerTreeMap::iterator cit = sIndirectLayerTrees.find(aLayersId);
2064 if (sIndirectLayerTrees.end() == cit) {
2065 return nullptr;
2067 LayerTreeState* lts = &cit->second;
2069 RefPtr<IAPZCTreeManager> apzctm =
2070 lts->mParent ? lts->mParent->mApzcTreeManager.get() : nullptr;
2071 return apzctm.forget();
2074 #if defined(MOZ_GECKO_PROFILER)
2075 static void InsertVsyncProfilerMarker(TimeStamp aVsyncTimestamp) {
2076 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
2077 if (profiler_thread_is_being_profiled()) {
2078 // Tracks when a vsync occurs according to the HardwareComposer.
2079 struct VsyncMarker {
2080 static constexpr mozilla::Span<const char> MarkerTypeName() {
2081 return mozilla::MakeStringSpan("VsyncTimestamp");
2083 static void StreamJSONMarkerData(
2084 baseprofiler::SpliceableJSONWriter& aWriter) {}
2085 static MarkerSchema MarkerTypeDisplay() {
2086 using MS = MarkerSchema;
2087 MS schema{MS::Location::markerChart, MS::Location::markerTable};
2088 // Nothing outside the defaults.
2089 return schema;
2092 profiler_add_marker("VsyncTimestamp", geckoprofiler::category::GRAPHICS,
2093 MarkerTiming::InstantAt(aVsyncTimestamp),
2094 VsyncMarker{});
2097 #endif
2099 /*static */
2100 void CompositorBridgeParent::PostInsertVsyncProfilerMarker(
2101 TimeStamp aVsyncTimestamp) {
2102 #if defined(MOZ_GECKO_PROFILER)
2103 // Called in the vsync thread
2104 if (profiler_is_active() && CompositorThreadHolder::IsActive()) {
2105 CompositorThread()->Dispatch(
2106 NewRunnableFunction("InsertVsyncProfilerMarkerRunnable",
2107 InsertVsyncProfilerMarker, aVsyncTimestamp));
2109 #endif
2112 widget::PCompositorWidgetParent*
2113 CompositorBridgeParent::AllocPCompositorWidgetParent(
2114 const CompositorWidgetInitData& aInitData) {
2115 #if defined(MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING)
2116 if (mWidget) {
2117 // Should not create two widgets on the same compositor.
2118 return nullptr;
2121 widget::CompositorWidgetParent* widget =
2122 new widget::CompositorWidgetParent(aInitData, mOptions);
2123 widget->AddRef();
2125 // Sending the constructor acts as initialization as well.
2126 mWidget = widget;
2127 return widget;
2128 #else
2129 return nullptr;
2130 #endif
2133 bool CompositorBridgeParent::DeallocPCompositorWidgetParent(
2134 PCompositorWidgetParent* aActor) {
2135 #if defined(MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING)
2136 static_cast<widget::CompositorWidgetParent*>(aActor)->Release();
2137 return true;
2138 #else
2139 return false;
2140 #endif
2143 bool CompositorBridgeParent::IsPendingComposite() {
2144 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
2145 if (!mCompositor) {
2146 return false;
2148 return mCompositor->IsPendingComposite();
2151 void CompositorBridgeParent::FinishPendingComposite() {
2152 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
2153 if (!mCompositor) {
2154 return;
2156 return mCompositor->FinishPendingComposite();
2159 CompositorController*
2160 CompositorBridgeParent::LayerTreeState::GetCompositorController() const {
2161 return mParent;
2164 MetricsSharingController*
2165 CompositorBridgeParent::LayerTreeState::CrossProcessSharingController() const {
2166 return mContentCompositorBridgeParent;
2169 MetricsSharingController*
2170 CompositorBridgeParent::LayerTreeState::InProcessSharingController() const {
2171 return mParent;
2174 void CompositorBridgeParent::DidComposite(const VsyncId& aId,
2175 TimeStamp& aCompositeStart,
2176 TimeStamp& aCompositeEnd) {
2177 if (mWrBridge) {
2178 MOZ_ASSERT(false); // This should never get called for a WR compositor
2179 } else {
2180 NotifyDidComposite(mPendingTransaction, aId, aCompositeStart,
2181 aCompositeEnd);
2182 #if defined(ENABLE_FRAME_LATENCY_LOG)
2183 if (mPendingTransaction.IsValid()) {
2184 if (mRefreshStartTime) {
2185 int32_t latencyMs =
2186 lround((aCompositeEnd - mRefreshStartTime).ToMilliseconds());
2187 printf_stderr(
2188 "From transaction start to end of generate frame latencyMs %d this "
2189 "%p\n",
2190 latencyMs, this);
2192 if (mFwdTime) {
2193 int32_t latencyMs = lround((aCompositeEnd - mFwdTime).ToMilliseconds());
2194 printf_stderr(
2195 "From forwarding transaction to end of generate frame latencyMs %d "
2196 "this %p\n",
2197 latencyMs, this);
2200 mRefreshStartTime = TimeStamp();
2201 mTxnStartTime = TimeStamp();
2202 mFwdTime = TimeStamp();
2203 #endif
2204 mPendingTransaction = TransactionId{0};
2208 void CompositorBridgeParent::NotifyDidSceneBuild(
2209 RefPtr<const wr::WebRenderPipelineInfo> aInfo) {
2210 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
2211 if (mPaused) {
2212 return;
2215 if (mWrBridge) {
2216 mWrBridge->NotifyDidSceneBuild(aInfo);
2217 } else {
2218 mCompositorScheduler->ScheduleComposition();
2222 void CompositorBridgeParent::NotifyDidRender(const VsyncId& aCompositeStartId,
2223 TimeStamp& aCompositeStart,
2224 TimeStamp& aRenderStart,
2225 TimeStamp& aCompositeEnd,
2226 wr::RendererStats* aStats) {
2227 if (!mWrBridge) {
2228 return;
2231 MOZ_RELEASE_ASSERT(mWrBridge->IsRootWebRenderBridgeParent());
2233 RefPtr<UiCompositorControllerParent> uiController =
2234 UiCompositorControllerParent::GetFromRootLayerTreeId(mRootLayerTreeID);
2236 if (uiController && mIsForcedFirstPaint) {
2237 uiController->NotifyFirstPaint();
2238 mIsForcedFirstPaint = false;
2241 nsTArray<CompositionPayload> payload =
2242 mWrBridge->TakePendingScrollPayload(aCompositeStartId);
2243 if (!payload.IsEmpty()) {
2244 RecordCompositionPayloadsPresented(aCompositeEnd, payload);
2247 nsTArray<ImageCompositeNotificationInfo> notifications;
2248 mWrBridge->ExtractImageCompositeNotifications(&notifications);
2249 if (!notifications.IsEmpty()) {
2250 Unused << ImageBridgeParent::NotifyImageComposites(notifications);
2254 void CompositorBridgeParent::NotifyPipelineRendered(
2255 const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch,
2256 const VsyncId& aCompositeStartId, TimeStamp& aCompositeStart,
2257 TimeStamp& aRenderStart, TimeStamp& aCompositeEnd,
2258 wr::RendererStats* aStats) {
2259 if (!mWrBridge || !mAsyncImageManager) {
2260 return;
2263 bool isRoot = mWrBridge->PipelineId() == aPipelineId;
2264 RefPtr<WebRenderBridgeParent> wrBridge =
2265 isRoot ? mWrBridge
2266 : RefPtr<WebRenderBridgeParent>(
2267 mAsyncImageManager->GetWrBridge(aPipelineId));
2268 if (!wrBridge) {
2269 return;
2272 CompositorBridgeParentBase* compBridge =
2273 isRoot ? this : wrBridge->GetCompositorBridge();
2274 if (!compBridge) {
2275 return;
2278 MOZ_RELEASE_ASSERT(isRoot == wrBridge->IsRootWebRenderBridgeParent());
2280 wrBridge->RemoveEpochDataPriorTo(aEpoch);
2282 nsTArray<FrameStats> stats;
2284 RefPtr<UiCompositorControllerParent> uiController =
2285 UiCompositorControllerParent::GetFromRootLayerTreeId(mRootLayerTreeID);
2287 Maybe<TransactionId> transactionId = wrBridge->FlushTransactionIdsForEpoch(
2288 aEpoch, aCompositeStartId, aCompositeStart, aRenderStart, aCompositeEnd,
2289 uiController, aStats, &stats);
2290 if (!transactionId) {
2291 MOZ_ASSERT(stats.IsEmpty());
2292 return;
2295 LayersId layersId = isRoot ? LayersId{0} : wrBridge->GetLayersId();
2296 Unused << compBridge->SendDidComposite(layersId, *transactionId,
2297 aCompositeStart, aCompositeEnd);
2299 if (!stats.IsEmpty()) {
2300 Unused << SendNotifyFrameStats(stats);
2304 RefPtr<AsyncImagePipelineManager>
2305 CompositorBridgeParent::GetAsyncImagePipelineManager() const {
2306 return mAsyncImageManager;
2309 void CompositorBridgeParent::NotifyDidComposite(TransactionId aTransactionId,
2310 VsyncId aId,
2311 TimeStamp& aCompositeStart,
2312 TimeStamp& aCompositeEnd) {
2313 MOZ_ASSERT(!mWrBridge,
2314 "We should be going through NotifyDidRender and "
2315 "NotifyPipelineRendered instead");
2317 Unused << SendDidComposite(LayersId{0}, aTransactionId, aCompositeStart,
2318 aCompositeEnd);
2320 if (mLayerManager) {
2321 nsTArray<ImageCompositeNotificationInfo> notifications;
2322 mLayerManager->ExtractImageCompositeNotifications(&notifications);
2323 if (!notifications.IsEmpty()) {
2324 Unused << ImageBridgeParent::NotifyImageComposites(notifications);
2328 MonitorAutoLock lock(*sIndirectLayerTreesLock);
2329 ForEachIndirectLayerTree([&](LayerTreeState* lts,
2330 const LayersId& aLayersId) -> void {
2331 if (lts->mContentCompositorBridgeParent && lts->mParent == this) {
2332 ContentCompositorBridgeParent* cpcp = lts->mContentCompositorBridgeParent;
2333 cpcp->DidCompositeLocked(aLayersId, aId, aCompositeStart, aCompositeEnd);
2338 void CompositorBridgeParent::InvalidateRemoteLayers() {
2339 MOZ_ASSERT(CompositorThread()->IsOnCurrentThread());
2341 Unused << PCompositorBridgeParent::SendInvalidateLayers(LayersId{0});
2343 MonitorAutoLock lock(*sIndirectLayerTreesLock);
2344 ForEachIndirectLayerTree([](LayerTreeState* lts,
2345 const LayersId& aLayersId) -> void {
2346 if (lts->mContentCompositorBridgeParent) {
2347 ContentCompositorBridgeParent* cpcp = lts->mContentCompositorBridgeParent;
2348 Unused << cpcp->SendInvalidateLayers(aLayersId);
2353 void UpdateIndirectTree(LayersId aId, Layer* aRoot,
2354 const TargetConfig& aTargetConfig) {
2355 MonitorAutoLock lock(*sIndirectLayerTreesLock);
2356 sIndirectLayerTrees[aId].mRoot = aRoot;
2357 sIndirectLayerTrees[aId].mTargetConfig = aTargetConfig;
2360 /* static */ CompositorBridgeParent::LayerTreeState*
2361 CompositorBridgeParent::GetIndirectShadowTree(LayersId aId) {
2362 // Only the compositor thread should use this method variant
2363 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
2365 MonitorAutoLock lock(*sIndirectLayerTreesLock);
2366 LayerTreeMap::iterator cit = sIndirectLayerTrees.find(aId);
2367 if (sIndirectLayerTrees.end() == cit) {
2368 return nullptr;
2370 return &cit->second;
2373 /* static */
2374 bool CompositorBridgeParent::CallWithIndirectShadowTree(
2375 LayersId aId,
2376 const std::function<void(CompositorBridgeParent::LayerTreeState&)>& aFunc) {
2377 if (!sIndirectLayerTreesLock) {
2378 // Can hapen during shutdown
2379 return false;
2381 // Note that this does not make things universally threadsafe just because the
2382 // sIndirectLayerTreesLock mutex is held. This is because the compositor
2383 // thread can mutate the LayerTreeState outside the lock. It does however
2384 // ensure that the *storage* for the LayerTreeState remains stable, since we
2385 // should always hold the lock when adding/removing entries to the map.
2386 MonitorAutoLock lock(*sIndirectLayerTreesLock);
2387 LayerTreeMap::iterator cit = sIndirectLayerTrees.find(aId);
2388 if (sIndirectLayerTrees.end() == cit) {
2389 return false;
2391 aFunc(cit->second);
2392 return true;
2395 static CompositorBridgeParent::LayerTreeState* GetStateForRoot(
2396 LayersId aContentLayersId, const MonitorAutoLock& aProofOfLock) {
2397 CompositorBridgeParent::LayerTreeState* state = nullptr;
2398 LayerTreeMap::iterator itr = sIndirectLayerTrees.find(aContentLayersId);
2399 if (sIndirectLayerTrees.end() != itr) {
2400 state = &itr->second;
2403 // |state| is the state for the content process, but we want the APZCTMParent
2404 // for the parent process owning that content process. So we have to jump to
2405 // the LayerTreeState for the root layer tree id for that layer tree, and use
2406 // the mApzcTreeManagerParent from that. This should also work with nested
2407 // content processes, because RootLayerTreeId() will bypass any intermediate
2408 // processes' ids and go straight to the root.
2409 if (state && state->mParent) {
2410 LayersId rootLayersId = state->mParent->RootLayerTreeId();
2411 itr = sIndirectLayerTrees.find(rootLayersId);
2412 state = (sIndirectLayerTrees.end() != itr) ? &itr->second : nullptr;
2415 return state;
2418 /* static */
2419 APZCTreeManagerParent* CompositorBridgeParent::GetApzcTreeManagerParentForRoot(
2420 LayersId aContentLayersId) {
2421 MonitorAutoLock lock(*sIndirectLayerTreesLock);
2422 CompositorBridgeParent::LayerTreeState* state =
2423 GetStateForRoot(aContentLayersId, lock);
2424 return state ? state->mApzcTreeManagerParent : nullptr;
2427 /* static */
2428 GeckoContentController*
2429 CompositorBridgeParent::GetGeckoContentControllerForRoot(
2430 LayersId aContentLayersId) {
2431 MonitorAutoLock lock(*sIndirectLayerTreesLock);
2432 CompositorBridgeParent::LayerTreeState* state =
2433 GetStateForRoot(aContentLayersId, lock);
2434 return state ? state->mController.get() : nullptr;
2437 PTextureParent* CompositorBridgeParent::AllocPTextureParent(
2438 const SurfaceDescriptor& aSharedData, const ReadLockDescriptor& aReadLock,
2439 const LayersBackend& aLayersBackend, const TextureFlags& aFlags,
2440 const LayersId& aId, const uint64_t& aSerial,
2441 const wr::MaybeExternalImageId& aExternalImageId) {
2442 return TextureHost::CreateIPDLActor(this, aSharedData, aReadLock,
2443 aLayersBackend, aFlags, aSerial,
2444 aExternalImageId);
2447 bool CompositorBridgeParent::DeallocPTextureParent(PTextureParent* actor) {
2448 return TextureHost::DestroyIPDLActor(actor);
2451 mozilla::ipc::IPCResult CompositorBridgeParent::RecvInitPCanvasParent(
2452 Endpoint<PCanvasParent>&& aEndpoint) {
2453 MOZ_CRASH("PCanvasParent shouldn't be created via CompositorBridgeParent.");
2456 mozilla::ipc::IPCResult CompositorBridgeParent::RecvReleasePCanvasParent() {
2457 MOZ_CRASH("PCanvasParent shouldn't be released via CompositorBridgeParent.");
2460 bool CompositorBridgeParent::IsSameProcess() const {
2461 return OtherPid() == base::GetCurrentProcId();
2464 void CompositorBridgeParent::NotifyWebRenderDisableNativeCompositor() {
2465 MOZ_ASSERT(CompositorThread()->IsOnCurrentThread());
2466 if (mWrBridge) {
2467 mWrBridge->DisableNativeCompositor();
2471 int32_t RecordContentFrameTime(
2472 const VsyncId& aTxnId, const TimeStamp& aVsyncStart,
2473 const TimeStamp& aTxnStart, const VsyncId& aCompositeId,
2474 const TimeStamp& aCompositeEnd, const TimeDuration& aFullPaintTime,
2475 const TimeDuration& aVsyncRate, bool aContainsSVGGroup,
2476 bool aRecordUploadStats, wr::RendererStats* aStats /* = nullptr */) {
2477 double latencyMs = (aCompositeEnd - aTxnStart).ToMilliseconds();
2478 double latencyNorm = latencyMs / aVsyncRate.ToMilliseconds();
2479 int32_t fracLatencyNorm = lround(latencyNorm * 100.0);
2481 #ifdef MOZ_GECKO_PROFILER
2482 if (profiler_can_accept_markers()) {
2483 struct ContentFrameMarker {
2484 static constexpr Span<const char> MarkerTypeName() {
2485 return MakeStringSpan("CONTENT_FRAME_TIME");
2487 static void StreamJSONMarkerData(
2488 baseprofiler::SpliceableJSONWriter& aWriter) {}
2489 static MarkerSchema MarkerTypeDisplay() {
2490 using MS = MarkerSchema;
2491 MS schema{MS::Location::markerChart, MS::Location::markerTable};
2492 // Nothing outside the defaults.
2493 return schema;
2497 profiler_add_marker("CONTENT_FRAME_TIME", geckoprofiler::category::GRAPHICS,
2498 MarkerTiming::Interval(aTxnStart, aCompositeEnd),
2499 ContentFrameMarker{});
2501 #endif
2503 Telemetry::Accumulate(Telemetry::CONTENT_FRAME_TIME, fracLatencyNorm);
2505 if (!(aTxnId == VsyncId()) && aVsyncStart) {
2506 latencyMs = (aCompositeEnd - aVsyncStart).ToMilliseconds();
2507 latencyNorm = latencyMs / aVsyncRate.ToMilliseconds();
2508 fracLatencyNorm = lround(latencyNorm * 100.0);
2509 int32_t result = fracLatencyNorm;
2510 Telemetry::Accumulate(Telemetry::CONTENT_FRAME_TIME_VSYNC, fracLatencyNorm);
2512 if (aContainsSVGGroup) {
2513 Telemetry::Accumulate(Telemetry::CONTENT_FRAME_TIME_WITH_SVG,
2514 fracLatencyNorm);
2517 // Record CONTENT_FRAME_TIME_REASON.
2519 // Note that deseralizing a layers update (RecvUpdate) can delay the receipt
2520 // of the composite vsync message
2521 // (CompositorBridgeParent::CompositeToTarget), since they're using the same
2522 // thread. This can mean that compositing might start significantly late,
2523 // but this code will still detect it as having successfully started on the
2524 // right vsync (which is somewhat correct). We'd now have reduced time left
2525 // in the vsync interval to finish compositing, so the chances of a missed
2526 // frame increases. This is effectively including the RecvUpdate work as
2527 // part of the 'compositing' phase for this metric, but it isn't included in
2528 // COMPOSITE_TIME, and *is* included in CONTENT_FULL_PAINT_TIME.
2530 // Also of note is that when the root WebRenderBridgeParent decides to
2531 // skip a composite (due to the Renderer being busy), that won't notify
2532 // child WebRenderBridgeParents. That failure will show up as the
2533 // composite starting late (since it did), but it's really a fault of a
2534 // slow composite on the previous frame, not a slow
2535 // CONTENT_FULL_PAINT_TIME. It would be nice to have a separate bucket for
2536 // this category (scene was ready on the next vsync, but we chose not to
2537 // composite), but I can't find a way to locate the right child
2538 // WebRenderBridgeParents from the root. WebRender notifies us of the
2539 // child pipelines contained within a render, after it finishes, but I
2540 // can't see how to query what child pipeline would have been rendered,
2541 // when we choose to not do it.
2542 if (fracLatencyNorm < 200) {
2543 // Success
2544 Telemetry::AccumulateCategorical(
2545 LABELS_CONTENT_FRAME_TIME_REASON::OnTime);
2546 } else {
2547 if (aCompositeId == VsyncId()) {
2548 // aCompositeId is 0, possibly something got trigged from
2549 // outside vsync?
2550 Telemetry::AccumulateCategorical(
2551 LABELS_CONTENT_FRAME_TIME_REASON::NoVsyncNoId);
2552 } else if (aTxnId >= aCompositeId) {
2553 // Vsync ids are nonsensical, maybe we're trying to catch up?
2554 Telemetry::AccumulateCategorical(
2555 LABELS_CONTENT_FRAME_TIME_REASON::NoVsync);
2556 } else if (aCompositeId - aTxnId > 1) {
2557 // Composite started late (and maybe took too long as well)
2558 if (aFullPaintTime >= TimeDuration::FromMilliseconds(20)) {
2559 Telemetry::AccumulateCategorical(
2560 LABELS_CONTENT_FRAME_TIME_REASON::MissedCompositeLong);
2561 } else if (aFullPaintTime >= TimeDuration::FromMilliseconds(10)) {
2562 Telemetry::AccumulateCategorical(
2563 LABELS_CONTENT_FRAME_TIME_REASON::MissedCompositeMid);
2564 } else if (aFullPaintTime >= TimeDuration::FromMilliseconds(5)) {
2565 Telemetry::AccumulateCategorical(
2566 LABELS_CONTENT_FRAME_TIME_REASON::MissedCompositeLow);
2567 } else {
2568 Telemetry::AccumulateCategorical(
2569 LABELS_CONTENT_FRAME_TIME_REASON::MissedComposite);
2571 } else {
2572 // Composite started on time, but must have taken too long.
2573 Telemetry::AccumulateCategorical(
2574 LABELS_CONTENT_FRAME_TIME_REASON::SlowComposite);
2578 if (aRecordUploadStats) {
2579 if (aStats) {
2580 latencyMs -= (double(aStats->resource_upload_time) / 1000000.0);
2581 latencyNorm = latencyMs / aVsyncRate.ToMilliseconds();
2582 fracLatencyNorm = lround(latencyNorm * 100.0);
2584 Telemetry::Accumulate(
2585 Telemetry::CONTENT_FRAME_TIME_WITHOUT_RESOURCE_UPLOAD,
2586 fracLatencyNorm);
2588 if (aStats) {
2589 latencyMs -= (double(aStats->gpu_cache_upload_time) / 1000000.0);
2590 latencyNorm = latencyMs / aVsyncRate.ToMilliseconds();
2591 fracLatencyNorm = lround(latencyNorm * 100.0);
2593 Telemetry::Accumulate(Telemetry::CONTENT_FRAME_TIME_WITHOUT_UPLOAD,
2594 fracLatencyNorm);
2596 return result;
2599 return 0;
2602 mozilla::ipc::IPCResult CompositorBridgeParent::RecvBeginRecording(
2603 const TimeStamp& aRecordingStart, BeginRecordingResolver&& aResolve) {
2604 if (mHaveCompositionRecorder) {
2605 aResolve(false);
2606 return IPC_OK();
2609 if (mLayerManager) {
2610 mLayerManager->SetCompositionRecorder(
2611 MakeUnique<CompositionRecorder>(aRecordingStart));
2612 } else if (mWrBridge) {
2613 mWrBridge->BeginRecording(aRecordingStart);
2616 mHaveCompositionRecorder = true;
2617 aResolve(true);
2619 return IPC_OK();
2622 mozilla::ipc::IPCResult CompositorBridgeParent::RecvEndRecordingToDisk(
2623 EndRecordingToDiskResolver&& aResolve) {
2624 if (!mHaveCompositionRecorder) {
2625 aResolve(false);
2626 return IPC_OK();
2629 if (mLayerManager) {
2630 mLayerManager->WriteCollectedFrames();
2631 aResolve(true);
2632 } else if (mWrBridge) {
2633 mWrBridge->WriteCollectedFrames()->Then(
2634 NS_GetCurrentThread(), __func__,
2635 [resolve{aResolve}](const bool success) { resolve(success); },
2636 [resolve{aResolve}]() { resolve(false); });
2637 } else {
2638 aResolve(false);
2641 mHaveCompositionRecorder = false;
2643 return IPC_OK();
2646 mozilla::ipc::IPCResult CompositorBridgeParent::RecvEndRecordingToMemory(
2647 EndRecordingToMemoryResolver&& aResolve) {
2648 if (!mHaveCompositionRecorder) {
2649 aResolve(Nothing());
2650 return IPC_OK();
2653 if (mLayerManager) {
2654 Maybe<CollectedFrames> frames = mLayerManager->GetCollectedFrames();
2655 if (frames) {
2656 aResolve(WrapCollectedFrames(std::move(*frames)));
2657 } else {
2658 aResolve(Nothing());
2660 } else if (mWrBridge) {
2661 RefPtr<CompositorBridgeParent> self = this;
2662 mWrBridge->GetCollectedFrames()->Then(
2663 NS_GetCurrentThread(), __func__,
2664 [self, resolve{aResolve}](CollectedFrames&& frames) {
2665 resolve(self->WrapCollectedFrames(std::move(frames)));
2667 [resolve{aResolve}]() { resolve(Nothing()); });
2670 mHaveCompositionRecorder = false;
2672 return IPC_OK();
2675 Maybe<CollectedFramesParams> CompositorBridgeParent::WrapCollectedFrames(
2676 CollectedFrames&& aFrames) {
2677 CollectedFramesParams ipcFrames;
2678 ipcFrames.recordingStart() = aFrames.mRecordingStart;
2680 size_t totalLength = 0;
2681 for (const CollectedFrame& frame : aFrames.mFrames) {
2682 totalLength += frame.mDataUri.Length();
2685 Shmem shmem;
2686 if (!AllocShmem(totalLength, SharedMemory::TYPE_BASIC, &shmem)) {
2687 return Nothing();
2691 char* raw = shmem.get<char>();
2692 for (CollectedFrame& frame : aFrames.mFrames) {
2693 size_t length = frame.mDataUri.Length();
2695 PodCopy(raw, frame.mDataUri.get(), length);
2696 raw += length;
2698 ipcFrames.frames().EmplaceBack(frame.mTimeOffset, length);
2701 ipcFrames.buffer() = std::move(shmem);
2703 return Some(std::move(ipcFrames));
2706 } // namespace layers
2707 } // namespace mozilla