1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "mozilla/layers/CompositorBridgeParent.h"
8 
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
13 
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
106 
107 #include "LayerScope.h"
108 
109 namespace mozilla {
110 
111 namespace layers {
112 
113 using namespace mozilla::ipc;
114 using namespace mozilla::gfx;
115 
116 using base::ProcessId;
117 
118 using mozilla::Telemetry::LABELS_CONTENT_FRAME_TIME_REASON;
119 
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.
AssertIsInCompositorThread()123 static void AssertIsInCompositorThread() {
124   MOZ_RELEASE_ASSERT(!CompositorThread() ||
125                      CompositorThreadHolder::IsInCompositorThread());
126 }
127 
CompositorBridgeParentBase(CompositorManagerParent * aManager)128 CompositorBridgeParentBase::CompositorBridgeParentBase(
129     CompositorManagerParent* aManager)
130     : mCanSend(true), mCompositorManager(aManager) {}
131 
132 CompositorBridgeParentBase::~CompositorBridgeParentBase() = default;
133 
GetChildProcessId()134 ProcessId CompositorBridgeParentBase::GetChildProcessId() { return OtherPid(); }
135 
NotifyNotUsed(PTextureParent * aTexture,uint64_t aTransactionId)136 void CompositorBridgeParentBase::NotifyNotUsed(PTextureParent* aTexture,
137                                                uint64_t aTransactionId) {
138   RefPtr<TextureHost> texture = TextureHost::AsTextureHost(aTexture);
139   if (!texture) {
140     return;
141   }
142 
143 #ifdef MOZ_WIDGET_ANDROID
144   if (texture->GetAndroidHardwareBuffer()) {
145     MOZ_ASSERT(texture->GetFlags() & TextureFlags::RECYCLE);
146     ImageBridgeParent::NotifyBufferNotUsedOfCompositorBridge(
147         GetChildProcessId(), texture, aTransactionId);
148   }
149 #endif
150 
151   if (!(texture->GetFlags() & TextureFlags::RECYCLE) &&
152       !(texture->GetFlags() & TextureFlags::WAIT_HOST_USAGE_END)) {
153     return;
154   }
155 
156   uint64_t textureId = TextureHost::GetTextureSerial(aTexture);
157   mPendingAsyncMessage.push_back(OpNotifyNotUsed(textureId, aTransactionId));
158 }
159 
SendAsyncMessage(const nsTArray<AsyncParentMessageData> & aMessage)160 void CompositorBridgeParentBase::SendAsyncMessage(
161     const nsTArray<AsyncParentMessageData>& aMessage) {
162   Unused << SendParentAsyncMessages(aMessage);
163 }
164 
AllocShmem(size_t aSize,ipc::SharedMemory::SharedMemoryType aType,ipc::Shmem * aShmem)165 bool CompositorBridgeParentBase::AllocShmem(
166     size_t aSize, ipc::SharedMemory::SharedMemoryType aType,
167     ipc::Shmem* aShmem) {
168   return PCompositorBridgeParent::AllocShmem(aSize, aType, aShmem);
169 }
170 
AllocUnsafeShmem(size_t aSize,ipc::SharedMemory::SharedMemoryType aType,ipc::Shmem * aShmem)171 bool CompositorBridgeParentBase::AllocUnsafeShmem(
172     size_t aSize, ipc::SharedMemory::SharedMemoryType aType,
173     ipc::Shmem* aShmem) {
174   return PCompositorBridgeParent::AllocUnsafeShmem(aSize, aType, aShmem);
175 }
176 
DeallocShmem(ipc::Shmem & aShmem)177 bool CompositorBridgeParentBase::DeallocShmem(ipc::Shmem& aShmem) {
178   return PCompositorBridgeParent::DeallocShmem(aShmem);
179 }
180 
RemotePid()181 base::ProcessId CompositorBridgeParentBase::RemotePid() { return OtherPid(); }
182 
StartSharingMetrics(ipc::SharedMemoryBasic::Handle aHandle,CrossProcessMutexHandle aMutexHandle,LayersId aLayersId,uint32_t aApzcId)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;
196   }
197 
198   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
199   if (!mCanSend) {
200     return false;
201   }
202   return PCompositorBridgeParent::SendSharedCompositorFrameMetrics(
203       aHandle, aMutexHandle, aLayersId, aApzcId);
204 }
205 
StopSharingMetrics(ScrollableLayerGuid::ViewID aScrollId,uint32_t 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;
216   }
217 
218   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
219   if (!mCanSend) {
220     return false;
221   }
222   return PCompositorBridgeParent::SendReleaseSharedCompositorFrameMetrics(
223       aScrollId, aApzcId);
224 }
225 
LayerTreeState()226 CompositorBridgeParent::LayerTreeState::LayerTreeState()
227     : mApzcTreeManagerParent(nullptr),
228       mParent(nullptr),
229       mLayerManager(nullptr),
230       mContentCompositorBridgeParent(nullptr),
231       mLayerTree(nullptr) {}
232 
~LayerTreeState()233 CompositorBridgeParent::LayerTreeState::~LayerTreeState() {
234   if (mController) {
235     mController->Destroy();
236   }
237 }
238 
239 typedef std::map<LayersId, CompositorBridgeParent::LayerTreeState> LayerTreeMap;
240 LayerTreeMap sIndirectLayerTrees;
241 StaticAutoPtr<mozilla::Monitor> sIndirectLayerTreesLock;
242 
EnsureLayerTreeMapReady()243 static void EnsureLayerTreeMapReady() {
244   MOZ_ASSERT(NS_IsMainThread());
245   if (!sIndirectLayerTreesLock) {
246     sIndirectLayerTreesLock = new Monitor("IndirectLayerTree");
247     mozilla::ClearOnShutdown(&sIndirectLayerTreesLock);
248   }
249 }
250 
251 template <typename Lambda>
ForEachIndirectLayerTree(const Lambda & aCallback)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);
260     }
261   }
262 }
263 
264 /*static*/ template <typename Lambda>
ForEachWebRenderBridgeParent(const Lambda & aCallback)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);
272     }
273   }
274 }
275 
276 /**
277  * A global map referencing each compositor by ID.
278  *
279  * This map is used by the ImageBridge protocol to trigger
280  * compositions without having to keep references to the
281  * compositor
282  */
283 typedef std::map<uint64_t, CompositorBridgeParent*> CompositorMap;
284 static StaticAutoPtr<CompositorMap> sCompositorMap;
285 
Setup()286 void CompositorBridgeParent::Setup() {
287   EnsureLayerTreeMapReady();
288 
289   MOZ_ASSERT(!sCompositorMap);
290   sCompositorMap = new CompositorMap;
291 }
292 
FinishShutdown()293 void CompositorBridgeParent::FinishShutdown() {
294   MOZ_ASSERT(NS_IsMainThread());
295 
296   if (sCompositorMap) {
297     MOZ_ASSERT(sCompositorMap->empty());
298     sCompositorMap = nullptr;
299   }
300 
301   // TODO: this should be empty by now...
302   sIndirectLayerTrees.clear();
303 }
304 
305 #ifdef COMPOSITOR_PERFORMANCE_WARNING
CalculateCompositionFrameRate()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;
320     }
321     return layoutFrameRatePref;
322   }
323   return compositionFrameRatePref;
324 }
325 #endif
326 
CompositorBridgeParent(CompositorManagerParent * aManager,CSSToLayoutDeviceScale aScale,const TimeDuration & aVsyncRate,const CompositorOptions & aOptions,bool aUseExternalSurfaceSize,const gfx::IntSize & aSurfaceSize)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       mPaused(false),
336       mHaveCompositionRecorder(false),
337       mIsForcedFirstPaint(false),
338       mUseExternalSurfaceSize(aUseExternalSurfaceSize),
339       mEGLSurfaceSize(aSurfaceSize),
340       mOptions(aOptions),
341       mPauseCompositionMonitor("PauseCompositionMonitor"),
342       mResumeCompositionMonitor("ResumeCompositionMonitor"),
343       mCompositorBridgeID(0),
344       mRootLayerTreeID{0},
345       mOverrideComposeReadiness(false),
346       mForceCompositionTask(nullptr),
347       mCompositorScheduler(nullptr),
348       mAnimationStorage(nullptr),
349       mPaintTime(TimeDuration::Forever()) {}
350 
InitSameProcess(widget::CompositorWidget * aWidget,const LayersId & aLayerTreeId)351 void CompositorBridgeParent::InitSameProcess(widget::CompositorWidget* aWidget,
352                                              const LayersId& aLayerTreeId) {
353   MOZ_ASSERT(XRE_IsParentProcess());
354   MOZ_ASSERT(NS_IsMainThread());
355 
356   mWidget = aWidget;
357   mRootLayerTreeID = aLayerTreeId;
358 
359   Initialize();
360 }
361 
RecvInitialize(const LayersId & aRootLayerTreeId)362 mozilla::ipc::IPCResult CompositorBridgeParent::RecvInitialize(
363     const LayersId& aRootLayerTreeId) {
364   MOZ_ASSERT(XRE_IsGPUProcess());
365 
366   mRootLayerTreeID = aRootLayerTreeId;
367 #ifdef XP_WIN
368   if (XRE_IsGPUProcess()) {
369     mWidget->AsWindows()->SetRootLayerTreeID(mRootLayerTreeID);
370   }
371 #endif
372 
373   Initialize();
374   return IPC_OK();
375 }
376 
Initialize()377 void CompositorBridgeParent::Initialize() {
378   MOZ_ASSERT(CompositorThread(),
379              "The compositor thread must be Initialized before instanciating a "
380              "CompositorBridgeParent.");
381 
382   if (mOptions.UseAPZ()) {
383     MOZ_ASSERT(!mApzcTreeManager);
384     MOZ_ASSERT(!mApzSampler);
385     MOZ_ASSERT(!mApzUpdater);
386     mApzcTreeManager =
387         new APZCTreeManager(mRootLayerTreeID, mOptions.UseWebRender());
388     mApzSampler = new APZSampler(mApzcTreeManager, mOptions.UseWebRender());
389     mApzUpdater = new APZUpdater(mApzcTreeManager, mOptions.UseWebRender());
390   }
391 
392   if (mOptions.UseWebRender()) {
393     CompositorAnimationStorage* animationStorage = GetAnimationStorage();
394     mOMTASampler = new OMTASampler(animationStorage, mRootLayerTreeID);
395   }
396 
397   mPaused = mOptions.InitiallyPaused();
398 
399   mCompositorBridgeID = 0;
400   // FIXME: This holds on the the fact that right now the only thing that
401   // can destroy this instance is initialized on the compositor thread after
402   // this task has been processed.
403   MOZ_ASSERT(CompositorThread());
404   CompositorThread()->Dispatch(NewRunnableFunction(
405       "AddCompositorRunnable", &AddCompositor, this, &mCompositorBridgeID));
406 
407   {  // scope lock
408     MonitorAutoLock lock(*sIndirectLayerTreesLock);
409     sIndirectLayerTrees[mRootLayerTreeID].mParent = this;
410   }
411 
412   LayerScope::SetPixelScale(mScale.scale);
413 
414   if (!mOptions.UseWebRender()) {
415     mCompositorScheduler = new CompositorVsyncScheduler(this, mWidget);
416   }
417 }
418 
RootLayerTreeId()419 LayersId CompositorBridgeParent::RootLayerTreeId() {
420   MOZ_ASSERT(mRootLayerTreeID.IsValid());
421   return mRootLayerTreeID;
422 }
423 
~CompositorBridgeParent()424 CompositorBridgeParent::~CompositorBridgeParent() {
425   MOZ_DIAGNOSTIC_ASSERT(
426       !mCanSend,
427       "ActorDestroy or RecvWillClose should have been called first.");
428   MOZ_DIAGNOSTIC_ASSERT(mRefCnt == 0,
429                         "ActorDealloc should have been called first.");
430   nsTArray<PTextureParent*> textures;
431   ManagedPTextureParent(textures);
432   // We expect all textures to be destroyed by now.
433   MOZ_DIAGNOSTIC_ASSERT(textures.Length() == 0);
434   for (unsigned int i = 0; i < textures.Length(); ++i) {
435     RefPtr<TextureHost> tex = TextureHost::AsTextureHost(textures[i]);
436     tex->DeallocateDeviceData();
437   }
438   // Check if WebRender/Compositor was shutdown.
439   if (mWrBridge || mCompositor) {
440     gfxCriticalNote << "CompositorBridgeParent destroyed without shutdown";
441   }
442 }
443 
ForceIsFirstPaint()444 void CompositorBridgeParent::ForceIsFirstPaint() {
445   if (mWrBridge) {
446     mIsForcedFirstPaint = true;
447   } else {
448     mCompositionManager->ForceIsFirstPaint();
449   }
450 }
451 
StopAndClearResources()452 void CompositorBridgeParent::StopAndClearResources() {
453   if (mForceCompositionTask) {
454     mForceCompositionTask->Cancel();
455     mForceCompositionTask = nullptr;
456   }
457 
458   mPaused = true;
459 
460   // We need to clear the APZ tree before we destroy the WebRender API below,
461   // because in the case of async scene building that will shut down the updater
462   // thread and we need to run the task before that happens.
463   MOZ_ASSERT((mApzSampler != nullptr) == (mApzcTreeManager != nullptr));
464   MOZ_ASSERT((mApzUpdater != nullptr) == (mApzcTreeManager != nullptr));
465   if (mApzUpdater) {
466     mApzSampler->Destroy();
467     mApzSampler = nullptr;
468     mApzUpdater->ClearTree(mRootLayerTreeID);
469     mApzUpdater = nullptr;
470     mApzcTreeManager = nullptr;
471   }
472 
473   // Ensure that the layer manager is destroyed before CompositorBridgeChild.
474   if (mLayerManager) {
475     MonitorAutoLock lock(*sIndirectLayerTreesLock);
476     ForEachIndirectLayerTree([this](LayerTreeState* lts, LayersId) -> void {
477       mLayerManager->ClearCachedResources(lts->mRoot);
478       lts->mLayerManager = nullptr;
479       lts->mParent = nullptr;
480     });
481     mLayerManager->Destroy();
482     mLayerManager = nullptr;
483     mCompositionManager = nullptr;
484   }
485 
486   if (mWrBridge) {
487     // Ensure we are not holding the sIndirectLayerTreesLock when destroying
488     // the WebRenderBridgeParent instances because it may block on WR.
489     std::vector<RefPtr<WebRenderBridgeParent>> indirectBridgeParents;
490     {  // scope lock
491       MonitorAutoLock lock(*sIndirectLayerTreesLock);
492       ForEachIndirectLayerTree([&](LayerTreeState* lts, LayersId) -> void {
493         if (lts->mWrBridge) {
494           indirectBridgeParents.emplace_back(lts->mWrBridge.forget());
495         }
496         lts->mParent = nullptr;
497       });
498     }
499     for (const RefPtr<WebRenderBridgeParent>& bridge : indirectBridgeParents) {
500       bridge->Destroy();
501     }
502     indirectBridgeParents.clear();
503 
504     RefPtr<wr::WebRenderAPI> api = mWrBridge->GetWebRenderAPI();
505     // Ensure we are not holding the sIndirectLayerTreesLock here because we
506     // are going to block on WR threads in order to shut it down properly.
507     mWrBridge->Destroy();
508     mWrBridge = nullptr;
509 
510     if (api) {
511       // Make extra sure we are done cleaning WebRender up before continuing.
512       // After that we wont have a way to talk to a lot of the webrender parts.
513       api->FlushSceneBuilder();
514       api = nullptr;
515     }
516 
517     if (mAsyncImageManager) {
518       mAsyncImageManager->Destroy();
519       // WebRenderAPI should be already destructed
520       mAsyncImageManager = nullptr;
521     }
522   }
523 
524   if (mCompositor) {
525     mCompositor->Destroy();
526     mCompositor = nullptr;
527   }
528 
529   // This must be destroyed now since it accesses the widget.
530   if (mCompositorScheduler) {
531     mCompositorScheduler->Destroy();
532     mCompositorScheduler = nullptr;
533   }
534 
535   if (mOMTASampler) {
536     mOMTASampler->Destroy();
537     mOMTASampler = nullptr;
538   }
539 
540   // After this point, it is no longer legal to access the widget.
541   mWidget = nullptr;
542 
543   // Clear mAnimationStorage here to ensure that the compositor thread
544   // still exists when we destroy it.
545   mAnimationStorage = nullptr;
546 }
547 
RecvWillClose()548 mozilla::ipc::IPCResult CompositorBridgeParent::RecvWillClose() {
549   StopAndClearResources();
550   // Once we get the WillClose message, the client side is going to go away
551   // soon and we can't be guaranteed that sending messages will work.
552   mCanSend = false;
553   return IPC_OK();
554 }
555 
DeferredDestroy()556 void CompositorBridgeParent::DeferredDestroy() {
557   MOZ_ASSERT(!NS_IsMainThread());
558   mSelfRef = nullptr;
559 }
560 
RecvPause()561 mozilla::ipc::IPCResult CompositorBridgeParent::RecvPause() {
562   PauseComposition();
563   return IPC_OK();
564 }
565 
RecvRequestFxrOutput()566 mozilla::ipc::IPCResult CompositorBridgeParent::RecvRequestFxrOutput() {
567 #ifdef XP_WIN
568   // Continue forwarding the request to the Widget + SwapChain
569   mWidget->AsWindows()->RequestFxrOutput();
570 #endif
571 
572   return IPC_OK();
573 }
574 
RecvResume()575 mozilla::ipc::IPCResult CompositorBridgeParent::RecvResume() {
576   ResumeComposition();
577   return IPC_OK();
578 }
579 
RecvResumeAsync()580 mozilla::ipc::IPCResult CompositorBridgeParent::RecvResumeAsync() {
581   ResumeComposition();
582   return IPC_OK();
583 }
584 
RecvMakeSnapshot(const SurfaceDescriptor & aInSnapshot,const gfx::IntRect & aRect)585 mozilla::ipc::IPCResult CompositorBridgeParent::RecvMakeSnapshot(
586     const SurfaceDescriptor& aInSnapshot, const gfx::IntRect& aRect) {
587   RefPtr<DrawTarget> target = GetDrawTargetForDescriptor(aInSnapshot);
588   MOZ_ASSERT(target);
589   if (!target) {
590     // We kill the content process rather than have it continue with an invalid
591     // snapshot, that may be too harsh and we could decide to return some sort
592     // of error to the child process and let it deal with it...
593     return IPC_FAIL_NO_REASON(this);
594   }
595   ForceComposeToTarget(target, &aRect);
596   return IPC_OK();
597 }
598 
599 mozilla::ipc::IPCResult
RecvWaitOnTransactionProcessed()600 CompositorBridgeParent::RecvWaitOnTransactionProcessed() {
601   return IPC_OK();
602 }
603 
RecvFlushRendering()604 mozilla::ipc::IPCResult CompositorBridgeParent::RecvFlushRendering() {
605   if (mWrBridge) {
606     mWrBridge->FlushRendering();
607     return IPC_OK();
608   }
609 
610   if (mCompositorScheduler->NeedsComposite()) {
611     CancelCurrentCompositeTask();
612     ForceComposeToTarget(nullptr);
613   }
614   return IPC_OK();
615 }
616 
RecvFlushRenderingAsync()617 mozilla::ipc::IPCResult CompositorBridgeParent::RecvFlushRenderingAsync() {
618   if (mWrBridge) {
619     mWrBridge->FlushRendering(false);
620     return IPC_OK();
621   }
622 
623   return RecvFlushRendering();
624 }
625 
RecvForcePresent()626 mozilla::ipc::IPCResult CompositorBridgeParent::RecvForcePresent() {
627   if (mWrBridge) {
628     mWrBridge->ScheduleForcedGenerateFrame();
629   }
630   // During the shutdown sequence mLayerManager may be null
631   if (mLayerManager) {
632     mLayerManager->ForcePresent();
633   }
634   return IPC_OK();
635 }
636 
RecvNotifyRegionInvalidated(const nsIntRegion & aRegion)637 mozilla::ipc::IPCResult CompositorBridgeParent::RecvNotifyRegionInvalidated(
638     const nsIntRegion& aRegion) {
639   if (mLayerManager) {
640     mLayerManager->AddInvalidRegion(aRegion);
641   }
642   return IPC_OK();
643 }
644 
Invalidate()645 void CompositorBridgeParent::Invalidate() {
646   if (mLayerManager) {
647     mLayerManager->InvalidateAll();
648   }
649 }
650 
RecvStartFrameTimeRecording(const int32_t & aBufferSize,uint32_t * aOutStartIndex)651 mozilla::ipc::IPCResult CompositorBridgeParent::RecvStartFrameTimeRecording(
652     const int32_t& aBufferSize, uint32_t* aOutStartIndex) {
653   if (mLayerManager) {
654     *aOutStartIndex = mLayerManager->StartFrameTimeRecording(aBufferSize);
655   } else if (mWrBridge) {
656     *aOutStartIndex = mWrBridge->StartFrameTimeRecording(aBufferSize);
657   } else {
658     *aOutStartIndex = 0;
659   }
660   return IPC_OK();
661 }
662 
RecvStopFrameTimeRecording(const uint32_t & aStartIndex,nsTArray<float> * intervals)663 mozilla::ipc::IPCResult CompositorBridgeParent::RecvStopFrameTimeRecording(
664     const uint32_t& aStartIndex, nsTArray<float>* intervals) {
665   if (mLayerManager) {
666     mLayerManager->StopFrameTimeRecording(aStartIndex, *intervals);
667   } else if (mWrBridge) {
668     mWrBridge->StopFrameTimeRecording(aStartIndex, *intervals);
669   }
670   return IPC_OK();
671 }
672 
ActorDestroy(ActorDestroyReason why)673 void CompositorBridgeParent::ActorDestroy(ActorDestroyReason why) {
674   mCanSend = false;
675 
676   StopAndClearResources();
677 
678   RemoveCompositor(mCompositorBridgeID);
679 
680   mCompositionManager = nullptr;
681 
682   {  // scope lock
683     MonitorAutoLock lock(*sIndirectLayerTreesLock);
684     sIndirectLayerTrees.erase(mRootLayerTreeID);
685   }
686 
687   // There are chances that the ref count reaches zero on the main thread
688   // shortly after this function returns while some ipdl code still needs to run
689   // on this thread. We must keep the compositor parent alive untill the code
690   // handling message reception is finished on this thread.
691   mSelfRef = this;
692   NS_GetCurrentThread()->Dispatch(
693       NewRunnableMethod("layers::CompositorBridgeParent::DeferredDestroy", this,
694                         &CompositorBridgeParent::DeferredDestroy));
695 }
696 
ScheduleRenderOnCompositorThread()697 void CompositorBridgeParent::ScheduleRenderOnCompositorThread() {
698   MOZ_ASSERT(CompositorThread());
699   CompositorThread()->Dispatch(
700       NewRunnableMethod("layers::CompositorBridgeParent::ScheduleComposition",
701                         this, &CompositorBridgeParent::ScheduleComposition));
702 }
703 
PauseComposition()704 void CompositorBridgeParent::PauseComposition() {
705   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread(),
706              "PauseComposition() can only be called on the compositor thread");
707 
708   MonitorAutoLock lock(mPauseCompositionMonitor);
709 
710   if (!mPaused) {
711     mPaused = true;
712 
713     TimeStamp now = TimeStamp::Now();
714     if (mCompositor) {
715       mCompositor->Pause();
716       DidComposite(VsyncId(), now, now);
717     } else if (mWrBridge) {
718       mWrBridge->Pause();
719       NotifyPipelineRendered(mWrBridge->PipelineId(),
720                              mWrBridge->GetCurrentEpoch(), VsyncId(), now, now,
721                              now);
722     }
723   }
724 
725   // if anyone's waiting to make sure that composition really got paused, tell
726   // them
727   lock.NotifyAll();
728 }
729 
ResumeComposition()730 void CompositorBridgeParent::ResumeComposition() {
731   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread(),
732              "ResumeComposition() can only be called on the compositor thread");
733 
734   MonitorAutoLock lock(mResumeCompositionMonitor);
735 
736   bool resumed =
737       mOptions.UseWebRender() ? mWrBridge->Resume() : mCompositor->Resume();
738   if (!resumed) {
739 #ifdef MOZ_WIDGET_ANDROID
740     // We can't get a surface. This could be because the activity changed
741     // between the time resume was scheduled and now.
742     __android_log_print(
743         ANDROID_LOG_INFO, "CompositorBridgeParent",
744         "Unable to renew compositor surface; remaining in paused state");
745 #endif
746     lock.NotifyAll();
747     return;
748   }
749 
750   mPaused = false;
751 
752   Invalidate();
753   mCompositorScheduler->ForceComposeToTarget(nullptr, nullptr);
754 
755   // if anyone's waiting to make sure that composition really got resumed, tell
756   // them
757   lock.NotifyAll();
758 }
759 
ForceComposition()760 void CompositorBridgeParent::ForceComposition() {
761   // Cancel the orientation changed state to force composition
762   mForceCompositionTask = nullptr;
763   ScheduleRenderOnCompositorThread();
764 }
765 
CancelCurrentCompositeTask()766 void CompositorBridgeParent::CancelCurrentCompositeTask() {
767   mCompositorScheduler->CancelCurrentCompositeTask();
768 }
769 
SetEGLSurfaceRect(int x,int y,int width,int height)770 void CompositorBridgeParent::SetEGLSurfaceRect(int x, int y, int width,
771                                                int height) {
772   NS_ASSERTION(mUseExternalSurfaceSize,
773                "Compositor created without UseExternalSurfaceSize provided");
774   mEGLSurfaceSize.SizeTo(width, height);
775   if (mCompositor) {
776     mCompositor->SetDestinationSurfaceSize(
777         gfx::IntSize(mEGLSurfaceSize.width, mEGLSurfaceSize.height));
778     if (mCompositor->AsCompositorOGL()) {
779       mCompositor->AsCompositorOGL()->SetSurfaceOrigin(ScreenIntPoint(x, y));
780     }
781   }
782 }
783 
ResumeCompositionAndResize(int x,int y,int width,int height)784 void CompositorBridgeParent::ResumeCompositionAndResize(int x, int y, int width,
785                                                         int height) {
786   SetEGLSurfaceRect(x, y, width, height);
787   ResumeComposition();
788 }
789 
UpdatePaintTime(LayerTransactionParent * aLayerTree,const TimeDuration & aPaintTime)790 void CompositorBridgeParent::UpdatePaintTime(LayerTransactionParent* aLayerTree,
791                                              const TimeDuration& aPaintTime) {
792   // We get a lot of paint timings for things with empty transactions.
793   if (!mLayerManager || aPaintTime.ToMilliseconds() < 1.0) {
794     return;
795   }
796 
797   mLayerManager->SetPaintTime(aPaintTime);
798 }
799 
RegisterPayloads(LayerTransactionParent * aLayerTree,const nsTArray<CompositionPayload> & aPayload)800 void CompositorBridgeParent::RegisterPayloads(
801     LayerTransactionParent* aLayerTree,
802     const nsTArray<CompositionPayload>& aPayload) {
803   // We get a lot of paint timings for things with empty transactions.
804   if (!mLayerManager) {
805     return;
806   }
807 
808   mLayerManager->RegisterPayloads(aPayload);
809 }
810 
NotifyShadowTreeTransaction(LayersId aId,bool aIsFirstPaint,const FocusTarget & aFocusTarget,bool aScheduleComposite,uint32_t aPaintSequenceNumber,bool aIsRepeatTransaction,bool aHitTestUpdate)811 void CompositorBridgeParent::NotifyShadowTreeTransaction(
812     LayersId aId, bool aIsFirstPaint, const FocusTarget& aFocusTarget,
813     bool aScheduleComposite, uint32_t aPaintSequenceNumber,
814     bool aIsRepeatTransaction, bool aHitTestUpdate) {
815   if (!aIsRepeatTransaction && mLayerManager && mLayerManager->GetRoot()) {
816     AutoResolveRefLayers resolve(mCompositionManager, this);
817 
818     if (mApzUpdater) {
819       mApzUpdater->UpdateFocusState(mRootLayerTreeID, aId, aFocusTarget);
820       if (aHitTestUpdate) {
821         mApzUpdater->UpdateHitTestingTree(
822             mLayerManager->GetRoot(), aIsFirstPaint, aId, aPaintSequenceNumber);
823       }
824     }
825 
826     mLayerManager->NotifyShadowTreeTransaction();
827   }
828   if (aScheduleComposite) {
829     ScheduleComposition();
830   }
831 }
832 
ScheduleComposition()833 void CompositorBridgeParent::ScheduleComposition() {
834   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
835   if (mPaused) {
836     return;
837   }
838 
839   if (mWrBridge) {
840     mWrBridge->ScheduleGenerateFrame();
841   } else {
842     mCompositorScheduler->ScheduleComposition();
843   }
844 }
845 
846 // Go down the composite layer tree, setting properties to match their
847 // content-side counterparts.
848 /* static */
SetShadowProperties(Layer * aLayer)849 void CompositorBridgeParent::SetShadowProperties(Layer* aLayer) {
850   ForEachNode<ForwardIterator>(aLayer, [](Layer* layer) {
851     if (Layer* maskLayer = layer->GetMaskLayer()) {
852       SetShadowProperties(maskLayer);
853     }
854     for (size_t i = 0; i < layer->GetAncestorMaskLayerCount(); i++) {
855       SetShadowProperties(layer->GetAncestorMaskLayerAt(i));
856     }
857 
858     // FIXME: Bug 717688 -- Do these updates in
859     // LayerTransactionParent::RecvUpdate.
860     HostLayer* layerCompositor = layer->AsHostLayer();
861     // Set the layerComposite's base transform to the layer's base transform.
862     const auto& animations = layer->GetPropertyAnimationGroups();
863     // If there is any animation, the animation value will override
864     // non-animated value later, so we don't need to set the non-animated
865     // value here.
866     if (animations.IsEmpty()) {
867       layerCompositor->SetShadowBaseTransform(layer->GetBaseTransform());
868       layerCompositor->SetShadowTransformSetByAnimation(false);
869       layerCompositor->SetShadowOpacity(layer->GetOpacity());
870       layerCompositor->SetShadowOpacitySetByAnimation(false);
871     }
872     layerCompositor->SetShadowVisibleRegion(layer->GetVisibleRegion());
873     layerCompositor->SetShadowClipRect(layer->GetClipRect());
874   });
875 }
876 
CompositeToTarget(VsyncId aId,DrawTarget * aTarget,const gfx::IntRect * aRect)877 void CompositorBridgeParent::CompositeToTarget(VsyncId aId, DrawTarget* aTarget,
878                                                const gfx::IntRect* aRect) {
879   AUTO_PROFILER_TRACING_MARKER("Paint", "Composite", GRAPHICS);
880   AUTO_PROFILER_LABEL("CompositorBridgeParent::CompositeToTarget", GRAPHICS);
881   PerfStats::AutoMetricRecording<PerfStats::Metric::Compositing> autoRecording;
882 
883   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread(),
884              "Composite can only be called on the compositor thread");
885   TimeStamp start = TimeStamp::Now();
886 
887   if (!CanComposite()) {
888     TimeStamp end = TimeStamp::Now();
889     DidComposite(aId, start, end);
890     return;
891   }
892 
893   AutoResolveRefLayers resolve(mCompositionManager, this);
894 
895   nsCString none;
896   if (aTarget) {
897     mLayerManager->BeginTransactionWithDrawTarget(aTarget, *aRect);
898   } else {
899     mLayerManager->BeginTransaction(none);
900   }
901 
902   SetShadowProperties(mLayerManager->GetRoot());
903 
904   if (mForceCompositionTask && !mOverrideComposeReadiness) {
905     if (mCompositionManager->ReadyForCompose()) {
906       mForceCompositionTask->Cancel();
907       mForceCompositionTask = nullptr;
908     } else {
909       return;
910     }
911   }
912 
913   mCompositionManager->ComputeRotation();
914 
915   SampleTime time = mTestTime ? SampleTime::FromTest(*mTestTime)
916                               : mCompositorScheduler->GetLastComposeTime();
917   bool requestNextFrame =
918       mCompositionManager->TransformShadowTree(time, mVsyncRate);
919 
920   if (requestNextFrame) {
921     ScheduleComposition();
922   }
923 
924   RenderTraceLayers(mLayerManager->GetRoot(), "0000");
925 
926   if (StaticPrefs::layers_dump_host_layers() || StaticPrefs::layers_dump()) {
927     printf_stderr("Painting --- compositing layer tree:\n");
928     mLayerManager->Dump(/* aSorted = */ true);
929   }
930   mLayerManager->SetDebugOverlayWantsNextFrame(false);
931   mLayerManager->EndTransaction(time.Time());
932 
933   if (!aTarget) {
934     TimeStamp end = TimeStamp::Now();
935     DidComposite(aId, start, end);
936   }
937 
938   // We're not really taking advantage of the stored composite-again-time here.
939   // We might be able to skip the next few composites altogether. However,
940   // that's a bit complex to implement and we'll get most of the advantage
941   // by skipping compositing when we detect there's nothing invalid. This is why
942   // we do "composite until" rather than "composite again at".
943   //
944   // TODO(bug 1328602) Figure out what we should do here with the render thread.
945   if (!mLayerManager->GetCompositeUntilTime().IsNull() ||
946       mLayerManager->DebugOverlayWantsNextFrame()) {
947     ScheduleComposition();
948   }
949 
950 #ifdef COMPOSITOR_PERFORMANCE_WARNING
951   TimeDuration executionTime =
952       TimeStamp::Now() - mCompositorScheduler->GetLastComposeTime().Time();
953   TimeDuration frameBudget = TimeDuration::FromMilliseconds(15);
954   int32_t frameRate = CalculateCompositionFrameRate();
955   if (frameRate > 0) {
956     frameBudget = TimeDuration::FromSeconds(1.0 / frameRate);
957   }
958   if (executionTime > frameBudget) {
959     printf_stderr("Compositor: Composite execution took %4.1f ms\n",
960                   executionTime.ToMilliseconds());
961   }
962 #endif
963 
964   // 0 -> Full-tilt composite
965   if (StaticPrefs::layers_offmainthreadcomposition_frame_rate() == 0 ||
966       mLayerManager->AlwaysScheduleComposite()) {
967     // Special full-tilt composite mode for performance testing
968     ScheduleComposition();
969   }
970 
971   // TODO(bug 1328602) Need an equivalent that works with the rende thread.
972   mLayerManager->SetCompositionTime(TimeStamp());
973 
974   mozilla::Telemetry::AccumulateTimeDelta(mozilla::Telemetry::COMPOSITE_TIME,
975                                           start);
976 }
977 
ForceComposeToTarget(DrawTarget * aTarget,const gfx::IntRect * aRect)978 void CompositorBridgeParent::ForceComposeToTarget(DrawTarget* aTarget,
979                                                   const gfx::IntRect* aRect) {
980   AUTO_PROFILER_LABEL("CompositorBridgeParent::ForceComposeToTarget", GRAPHICS);
981 
982   AutoRestore<bool> override(mOverrideComposeReadiness);
983   mOverrideComposeReadiness = true;
984   mCompositorScheduler->ForceComposeToTarget(aTarget, aRect);
985 }
986 
AllocPAPZCTreeManagerParent(const LayersId & aLayersId)987 PAPZCTreeManagerParent* CompositorBridgeParent::AllocPAPZCTreeManagerParent(
988     const LayersId& aLayersId) {
989   // This should only ever get called in the GPU process.
990   MOZ_ASSERT(XRE_IsGPUProcess());
991   // We should only ever get this if APZ is enabled in this compositor.
992   MOZ_ASSERT(mOptions.UseAPZ());
993   // The mApzcTreeManager and mApzUpdater should have been created via
994   // RecvInitialize()
995   MOZ_ASSERT(mApzcTreeManager);
996   MOZ_ASSERT(mApzUpdater);
997   // The main process should pass in 0 because we assume mRootLayerTreeID
998   MOZ_ASSERT(!aLayersId.IsValid());
999 
1000   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1001   CompositorBridgeParent::LayerTreeState& state =
1002       sIndirectLayerTrees[mRootLayerTreeID];
1003   MOZ_ASSERT(state.mParent.get() == this);
1004   MOZ_ASSERT(!state.mApzcTreeManagerParent);
1005   state.mApzcTreeManagerParent = new APZCTreeManagerParent(
1006       mRootLayerTreeID, mApzcTreeManager, mApzUpdater);
1007 
1008   return state.mApzcTreeManagerParent;
1009 }
1010 
DeallocPAPZCTreeManagerParent(PAPZCTreeManagerParent * aActor)1011 bool CompositorBridgeParent::DeallocPAPZCTreeManagerParent(
1012     PAPZCTreeManagerParent* aActor) {
1013   delete aActor;
1014   return true;
1015 }
1016 
AllocateAPZCTreeManagerParent(const MonitorAutoLock & aProofOfLayerTreeStateLock,const LayersId & aLayersId,LayerTreeState & aState)1017 void CompositorBridgeParent::AllocateAPZCTreeManagerParent(
1018     const MonitorAutoLock& aProofOfLayerTreeStateLock,
1019     const LayersId& aLayersId, LayerTreeState& aState) {
1020   MOZ_ASSERT(aState.mParent == this);
1021   MOZ_ASSERT(mApzcTreeManager);
1022   MOZ_ASSERT(mApzUpdater);
1023   MOZ_ASSERT(!aState.mApzcTreeManagerParent);
1024   aState.mApzcTreeManagerParent =
1025       new APZCTreeManagerParent(aLayersId, mApzcTreeManager, mApzUpdater);
1026 }
1027 
AllocPAPZParent(const LayersId & aLayersId)1028 PAPZParent* CompositorBridgeParent::AllocPAPZParent(const LayersId& aLayersId) {
1029   // This is the CompositorBridgeParent for a window, and so should only be
1030   // creating a PAPZ instance if it lives in the GPU process. Instances that
1031   // live in the UI process should going through SetControllerForLayerTree.
1032   MOZ_RELEASE_ASSERT(XRE_IsGPUProcess());
1033 
1034   // We should only ever get this if APZ is enabled on this compositor.
1035   MOZ_RELEASE_ASSERT(mOptions.UseAPZ());
1036 
1037   // The main process should pass in 0 because we assume mRootLayerTreeID
1038   MOZ_RELEASE_ASSERT(!aLayersId.IsValid());
1039 
1040   RemoteContentController* controller = new RemoteContentController();
1041 
1042   // Increment the controller's refcount before we return it. This will keep the
1043   // controller alive until it is released by IPDL in DeallocPAPZParent.
1044   controller->AddRef();
1045 
1046   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1047   CompositorBridgeParent::LayerTreeState& state =
1048       sIndirectLayerTrees[mRootLayerTreeID];
1049   MOZ_RELEASE_ASSERT(!state.mController);
1050   state.mController = controller;
1051 
1052   return controller;
1053 }
1054 
DeallocPAPZParent(PAPZParent * aActor)1055 bool CompositorBridgeParent::DeallocPAPZParent(PAPZParent* aActor) {
1056   RemoteContentController* controller =
1057       static_cast<RemoteContentController*>(aActor);
1058   controller->Release();
1059   return true;
1060 }
1061 
GetAPZSampler() const1062 RefPtr<APZSampler> CompositorBridgeParent::GetAPZSampler() const {
1063   return mApzSampler;
1064 }
1065 
GetAPZUpdater() const1066 RefPtr<APZUpdater> CompositorBridgeParent::GetAPZUpdater() const {
1067   return mApzUpdater;
1068 }
1069 
GetOMTASampler() const1070 RefPtr<OMTASampler> CompositorBridgeParent::GetOMTASampler() const {
1071   return mOMTASampler;
1072 }
1073 
1074 CompositorBridgeParent*
GetCompositorBridgeParentFromLayersId(const LayersId & aLayersId)1075 CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(
1076     const LayersId& aLayersId) {
1077   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1078   return sIndirectLayerTrees[aLayersId].mParent;
1079 }
1080 
1081 /*static*/
1082 RefPtr<CompositorBridgeParent>
GetCompositorBridgeParentFromWindowId(const wr::WindowId & aWindowId)1083 CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(
1084     const wr::WindowId& aWindowId) {
1085   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1086   for (auto it = sIndirectLayerTrees.begin(); it != sIndirectLayerTrees.end();
1087        it++) {
1088     LayerTreeState* state = &it->second;
1089     if (!state->mWrBridge) {
1090       continue;
1091     }
1092     // state->mWrBridge might be a root WebRenderBridgeParent or one of a
1093     // content process, but in either case the state->mParent will be the same.
1094     // So we don't need to distinguish between the two.
1095     if (RefPtr<wr::WebRenderAPI> api = state->mWrBridge->GetWebRenderAPI()) {
1096       if (api->GetId() == aWindowId) {
1097         return state->mParent;
1098       }
1099     }
1100   }
1101   return nullptr;
1102 }
1103 
CanComposite()1104 bool CompositorBridgeParent::CanComposite() {
1105   return mLayerManager && mLayerManager->GetRoot() && !mPaused;
1106 }
1107 
ScheduleRotationOnCompositorThread(const TargetConfig & aTargetConfig,bool aIsFirstPaint)1108 void CompositorBridgeParent::ScheduleRotationOnCompositorThread(
1109     const TargetConfig& aTargetConfig, bool aIsFirstPaint) {
1110   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1111 
1112   if (!aIsFirstPaint && !mCompositionManager->IsFirstPaint() &&
1113       mCompositionManager->RequiresReorientation(aTargetConfig.orientation())) {
1114     if (mForceCompositionTask != nullptr) {
1115       mForceCompositionTask->Cancel();
1116     }
1117     RefPtr<CancelableRunnable> task = NewCancelableRunnableMethod(
1118         "layers::CompositorBridgeParent::ForceComposition", this,
1119         &CompositorBridgeParent::ForceComposition);
1120     mForceCompositionTask = task;
1121     if (StaticPrefs::layers_orientation_sync_timeout() == 0) {
1122       CompositorThread()->Dispatch(task.forget());
1123     } else {
1124       CompositorThread()->DelayedDispatch(
1125           task.forget(), StaticPrefs::layers_orientation_sync_timeout());
1126     }
1127   }
1128 }
1129 
ShadowLayersUpdated(LayerTransactionParent * aLayerTree,const TransactionInfo & aInfo,bool aHitTestUpdate)1130 void CompositorBridgeParent::ShadowLayersUpdated(
1131     LayerTransactionParent* aLayerTree, const TransactionInfo& aInfo,
1132     bool aHitTestUpdate) {
1133   const TargetConfig& targetConfig = aInfo.targetConfig();
1134 
1135   ScheduleRotationOnCompositorThread(targetConfig, aInfo.isFirstPaint());
1136 
1137   // Instruct the LayerManager to update its render bounds now. Since all the
1138   // orientation change, dimension change would be done at the stage, update the
1139   // size here is free of race condition.
1140   mLayerManager->UpdateRenderBounds(targetConfig.naturalBounds());
1141   mLayerManager->SetRegionToClear(targetConfig.clearRegion());
1142   if (mLayerManager->GetCompositor()) {
1143     mLayerManager->GetCompositor()->SetScreenRotation(targetConfig.rotation());
1144   }
1145 
1146   mCompositionManager->Updated(aInfo.isFirstPaint(), targetConfig);
1147   Layer* root = aLayerTree->GetRoot();
1148   mLayerManager->SetRoot(root);
1149 
1150   if (mApzUpdater && !aInfo.isRepeatTransaction()) {
1151     mApzUpdater->UpdateFocusState(mRootLayerTreeID, mRootLayerTreeID,
1152                                   aInfo.focusTarget());
1153 
1154     if (aHitTestUpdate) {
1155       AutoResolveRefLayers resolve(mCompositionManager);
1156 
1157       mApzUpdater->UpdateHitTestingTree(root, aInfo.isFirstPaint(),
1158                                         mRootLayerTreeID,
1159                                         aInfo.paintSequenceNumber());
1160     }
1161   }
1162 
1163   // The transaction ID might get reset to 1 if the page gets reloaded, see
1164   // https://bugzilla.mozilla.org/show_bug.cgi?id=1145295#c41
1165   // Otherwise, it should be continually increasing.
1166   MOZ_ASSERT(aInfo.id() == TransactionId{1} || mPendingTransactions.IsEmpty() ||
1167              aInfo.id() > mPendingTransactions.LastElement());
1168   mPendingTransactions.AppendElement(aInfo.id());
1169   mRefreshStartTime = aInfo.refreshStart();
1170   mTxnStartTime = aInfo.transactionStart();
1171   mFwdTime = aInfo.fwdTime();
1172   RegisterPayloads(aLayerTree, aInfo.payload());
1173 
1174   if (root) {
1175     SetShadowProperties(root);
1176   }
1177   if (aInfo.scheduleComposite()) {
1178     ScheduleComposition();
1179     if (mPaused) {
1180       TimeStamp now = TimeStamp::Now();
1181       DidComposite(VsyncId(), now, now);
1182     }
1183   }
1184   mLayerManager->NotifyShadowTreeTransaction();
1185 }
1186 
ScheduleComposite(LayerTransactionParent * aLayerTree)1187 void CompositorBridgeParent::ScheduleComposite(
1188     LayerTransactionParent* aLayerTree) {
1189   ScheduleComposition();
1190 }
1191 
SetTestSampleTime(const LayersId & aId,const TimeStamp & aTime)1192 bool CompositorBridgeParent::SetTestSampleTime(const LayersId& aId,
1193                                                const TimeStamp& aTime) {
1194   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1195 
1196   if (aTime.IsNull()) {
1197     return false;
1198   }
1199 
1200   mTestTime = Some(aTime);
1201   if (mApzcTreeManager) {
1202     mApzcTreeManager->SetTestSampleTime(mTestTime);
1203   }
1204 
1205   if (mWrBridge) {
1206     mWrBridge->FlushRendering();
1207     return true;
1208   }
1209 
1210   bool testComposite =
1211       mCompositionManager && mCompositorScheduler->NeedsComposite();
1212 
1213   // Update but only if we were already scheduled to animate
1214   if (testComposite) {
1215     AutoResolveRefLayers resolve(mCompositionManager);
1216     bool requestNextFrame = mCompositionManager->TransformShadowTree(
1217         SampleTime::FromTest(aTime), mVsyncRate);
1218     if (!requestNextFrame) {
1219       CancelCurrentCompositeTask();
1220       // Pretend we composited in case someone is wating for this event.
1221       TimeStamp now = TimeStamp::Now();
1222       DidComposite(VsyncId(), now, now);
1223     }
1224   }
1225 
1226   return true;
1227 }
1228 
LeaveTestMode(const LayersId & aId)1229 void CompositorBridgeParent::LeaveTestMode(const LayersId& aId) {
1230   mTestTime = Nothing();
1231   if (mApzcTreeManager) {
1232     mApzcTreeManager->SetTestSampleTime(mTestTime);
1233   }
1234 }
1235 
ApplyAsyncProperties(LayerTransactionParent * aLayerTree,TransformsToSkip aSkip)1236 void CompositorBridgeParent::ApplyAsyncProperties(
1237     LayerTransactionParent* aLayerTree, TransformsToSkip aSkip) {
1238   // NOTE: This should only be used for testing. For example, when mTestTime is
1239   // non-empty, or when called from test-only methods like
1240   // LayerTransactionParent::RecvGetAnimationTransform.
1241 
1242   // Synchronously update the layer tree
1243   if (aLayerTree->GetRoot()) {
1244     AutoResolveRefLayers resolve(mCompositionManager);
1245     SetShadowProperties(mLayerManager->GetRoot());
1246 
1247     SampleTime time;
1248     if (mTestTime) {
1249       time = SampleTime::FromTest(*mTestTime);
1250     } else {
1251       time = mCompositorScheduler->GetLastComposeTime();
1252     }
1253     bool requestNextFrame =
1254         mCompositionManager->TransformShadowTree(time, mVsyncRate, aSkip);
1255     if (!requestNextFrame) {
1256       CancelCurrentCompositeTask();
1257       // Pretend we composited in case someone is waiting for this event.
1258       TimeStamp now = TimeStamp::Now();
1259       DidComposite(VsyncId(), now, now);
1260     }
1261   }
1262 }
1263 
GetAnimationStorage()1264 CompositorAnimationStorage* CompositorBridgeParent::GetAnimationStorage() {
1265   if (!mAnimationStorage) {
1266     mAnimationStorage = new CompositorAnimationStorage(this);
1267   }
1268   return mAnimationStorage;
1269 }
1270 
NotifyJankedAnimations(const JankedAnimations & aJankedAnimations)1271 void CompositorBridgeParent::NotifyJankedAnimations(
1272     const JankedAnimations& aJankedAnimations) {
1273   MOZ_ASSERT(!aJankedAnimations.empty());
1274 
1275   if (StaticPrefs::layout_animation_prerender_partial_jank()) {
1276     return;
1277   }
1278 
1279   for (const auto& entry : aJankedAnimations) {
1280     const LayersId& layersId = entry.first;
1281     const nsTArray<uint64_t>& animations = entry.second;
1282     if (layersId == mRootLayerTreeID) {
1283       if (mLayerManager || mWrBridge) {
1284         Unused << SendNotifyJankedAnimations(LayersId{0}, animations);
1285       }
1286       // It unlikely happens multiple processes have janked animations at same
1287       // time, so it should be fine with enumerating sIndirectLayerTrees every
1288       // time.
1289     } else if (const LayerTreeState* state = GetIndirectShadowTree(layersId)) {
1290       if (ContentCompositorBridgeParent* cpcp =
1291               state->mContentCompositorBridgeParent) {
1292         Unused << cpcp->SendNotifyJankedAnimations(layersId, animations);
1293       }
1294     }
1295   }
1296 }
1297 
SetTestAsyncScrollOffset(const LayersId & aLayersId,const ScrollableLayerGuid::ViewID & aScrollId,const CSSPoint & aPoint)1298 void CompositorBridgeParent::SetTestAsyncScrollOffset(
1299     const LayersId& aLayersId, const ScrollableLayerGuid::ViewID& aScrollId,
1300     const CSSPoint& aPoint) {
1301   if (mApzUpdater) {
1302     MOZ_ASSERT(aLayersId.IsValid());
1303     mApzUpdater->SetTestAsyncScrollOffset(aLayersId, aScrollId, aPoint);
1304   }
1305 }
1306 
SetTestAsyncZoom(const LayersId & aLayersId,const ScrollableLayerGuid::ViewID & aScrollId,const LayerToParentLayerScale & aZoom)1307 void CompositorBridgeParent::SetTestAsyncZoom(
1308     const LayersId& aLayersId, const ScrollableLayerGuid::ViewID& aScrollId,
1309     const LayerToParentLayerScale& aZoom) {
1310   if (mApzUpdater) {
1311     MOZ_ASSERT(aLayersId.IsValid());
1312     mApzUpdater->SetTestAsyncZoom(aLayersId, aScrollId, aZoom);
1313   }
1314 }
1315 
FlushApzRepaints(const LayersId & aLayersId)1316 void CompositorBridgeParent::FlushApzRepaints(const LayersId& aLayersId) {
1317   MOZ_ASSERT(mApzUpdater);
1318   MOZ_ASSERT(aLayersId.IsValid());
1319   mApzUpdater->RunOnControllerThread(
1320       aLayersId, NS_NewRunnableFunction(
1321                      "layers::CompositorBridgeParent::FlushApzRepaints",
1322                      [=]() { APZCTreeManager::FlushApzRepaints(aLayersId); }));
1323 }
1324 
GetAPZTestData(const LayersId & aLayersId,APZTestData * aOutData)1325 void CompositorBridgeParent::GetAPZTestData(const LayersId& aLayersId,
1326                                             APZTestData* aOutData) {
1327   if (mApzUpdater) {
1328     MOZ_ASSERT(aLayersId.IsValid());
1329     mApzUpdater->GetAPZTestData(aLayersId, aOutData);
1330   }
1331 }
1332 
GetFrameUniformity(const LayersId & aLayersId,FrameUniformityData * aOutData)1333 void CompositorBridgeParent::GetFrameUniformity(const LayersId& aLayersId,
1334                                                 FrameUniformityData* aOutData) {
1335   if (mCompositionManager) {
1336     mCompositionManager->GetFrameUniformity(aOutData);
1337   }
1338 }
1339 
SetConfirmedTargetAPZC(const LayersId & aLayersId,const uint64_t & aInputBlockId,nsTArray<ScrollableLayerGuid> && aTargets)1340 void CompositorBridgeParent::SetConfirmedTargetAPZC(
1341     const LayersId& aLayersId, const uint64_t& aInputBlockId,
1342     nsTArray<ScrollableLayerGuid>&& aTargets) {
1343   if (!mApzcTreeManager || !mApzUpdater) {
1344     return;
1345   }
1346   // Need to specifically bind this since it's overloaded.
1347   void (APZCTreeManager::*setTargetApzcFunc)(
1348       uint64_t, const nsTArray<ScrollableLayerGuid>&) =
1349       &APZCTreeManager::SetTargetAPZC;
1350   RefPtr<Runnable> task =
1351       NewRunnableMethod<uint64_t,
1352                         StoreCopyPassByRRef<nsTArray<ScrollableLayerGuid>>>(
1353           "layers::CompositorBridgeParent::SetConfirmedTargetAPZC",
1354           mApzcTreeManager.get(), setTargetApzcFunc, aInputBlockId,
1355           std::move(aTargets));
1356   mApzUpdater->RunOnControllerThread(aLayersId, task.forget());
1357 }
1358 
SetFixedLayerMargins(ScreenIntCoord aTop,ScreenIntCoord aBottom)1359 void CompositorBridgeParent::SetFixedLayerMargins(ScreenIntCoord aTop,
1360                                                   ScreenIntCoord aBottom) {
1361   if (AsyncCompositionManager* manager = GetCompositionManager(nullptr)) {
1362     manager->SetFixedLayerMargins(aTop, aBottom);
1363   }
1364 
1365   if (mApzcTreeManager) {
1366     mApzcTreeManager->SetFixedLayerMargins(aTop, aBottom);
1367   }
1368 
1369   Invalidate();
1370   ScheduleComposition();
1371 }
1372 
InitializeLayerManager(const nsTArray<LayersBackend> & aBackendHints)1373 void CompositorBridgeParent::InitializeLayerManager(
1374     const nsTArray<LayersBackend>& aBackendHints) {
1375   NS_ASSERTION(!mLayerManager, "Already initialised mLayerManager");
1376   NS_ASSERTION(!mCompositor, "Already initialised mCompositor");
1377 
1378   mCompositor = NewCompositor(aBackendHints);
1379   if (!mCompositor) {
1380     return;
1381   }
1382 #ifdef XP_WIN
1383   if (mCompositor->AsBasicCompositor() && XRE_IsGPUProcess()) {
1384     // BasicCompositor does not use CompositorWindow,
1385     // then if CompositorWindow exists, it needs to be destroyed.
1386     mWidget->AsWindows()->DestroyCompositorWindow();
1387   }
1388 #endif
1389   mLayerManager = new LayerManagerComposite(mCompositor);
1390   mLayerManager->SetCompositorBridgeID(mCompositorBridgeID);
1391 
1392   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1393   sIndirectLayerTrees[mRootLayerTreeID].mLayerManager = mLayerManager;
1394 }
1395 
NewCompositor(const nsTArray<LayersBackend> & aBackendHints)1396 RefPtr<Compositor> CompositorBridgeParent::NewCompositor(
1397     const nsTArray<LayersBackend>& aBackendHints) {
1398   for (size_t i = 0; i < aBackendHints.Length(); ++i) {
1399     RefPtr<Compositor> compositor;
1400     if (aBackendHints[i] == LayersBackend::LAYERS_OPENGL) {
1401       compositor =
1402           new CompositorOGL(this, mWidget, mEGLSurfaceSize.width,
1403                             mEGLSurfaceSize.height, mUseExternalSurfaceSize);
1404     } else if (aBackendHints[i] == LayersBackend::LAYERS_BASIC) {
1405 #ifdef MOZ_WIDGET_GTK
1406       if (gfxVars::UseXRender()) {
1407         compositor = new X11BasicCompositor(this, mWidget);
1408       } else
1409 #endif
1410       {
1411         compositor = new BasicCompositor(this, mWidget);
1412       }
1413 #ifdef XP_WIN
1414     } else if (aBackendHints[i] == LayersBackend::LAYERS_D3D11) {
1415       compositor = new CompositorD3D11(this, mWidget);
1416 #endif
1417     }
1418     nsCString failureReason;
1419 
1420     // Some software GPU emulation implementations will happily try to create
1421     // unreasonably big surfaces and then fail in awful ways.
1422     // Let's at least limit this to the default max texture size we use for
1423     // content, anything larger than that will fail to render on the content
1424     // side anyway. We can revisit this value and make it even tighter if need
1425     // be.
1426     const int max_fb_size = 32767;
1427     const LayoutDeviceIntSize size = mWidget->GetClientSize();
1428     if (size.width > max_fb_size || size.height > max_fb_size) {
1429       failureReason = "FEATURE_FAILURE_MAX_FRAMEBUFFER_SIZE";
1430       return nullptr;
1431     }
1432 
1433     MOZ_ASSERT(!gfxVars::UseWebRender() ||
1434                aBackendHints[i] == LayersBackend::LAYERS_BASIC);
1435     if (compositor && compositor->Initialize(&failureReason)) {
1436       if (failureReason.IsEmpty()) {
1437         failureReason = "SUCCESS";
1438       }
1439 
1440       // should only report success here
1441       if (aBackendHints[i] == LayersBackend::LAYERS_OPENGL) {
1442         Telemetry::Accumulate(Telemetry::OPENGL_COMPOSITING_FAILURE_ID,
1443                               failureReason);
1444       }
1445 #ifdef XP_WIN
1446       else if (aBackendHints[i] == LayersBackend::LAYERS_D3D11) {
1447         Telemetry::Accumulate(Telemetry::D3D11_COMPOSITING_FAILURE_ID,
1448                               failureReason);
1449       }
1450 #endif
1451 
1452       return compositor;
1453     }
1454 
1455     // report any failure reasons here
1456     if (aBackendHints[i] == LayersBackend::LAYERS_OPENGL) {
1457       gfxCriticalNote << "[OPENGL] Failed to init compositor with reason: "
1458                       << failureReason.get();
1459       Telemetry::Accumulate(Telemetry::OPENGL_COMPOSITING_FAILURE_ID,
1460                             failureReason);
1461     }
1462 #ifdef XP_WIN
1463     else if (aBackendHints[i] == LayersBackend::LAYERS_D3D11) {
1464       gfxCriticalNote << "[D3D11] Failed to init compositor with reason: "
1465                       << failureReason.get();
1466       Telemetry::Accumulate(Telemetry::D3D11_COMPOSITING_FAILURE_ID,
1467                             failureReason);
1468     }
1469 #endif
1470   }
1471 
1472   return nullptr;
1473 }
1474 
AllocPLayerTransactionParent(const nsTArray<LayersBackend> & aBackendHints,const LayersId & aId)1475 PLayerTransactionParent* CompositorBridgeParent::AllocPLayerTransactionParent(
1476     const nsTArray<LayersBackend>& aBackendHints, const LayersId& aId) {
1477   MOZ_ASSERT(!aId.IsValid());
1478 
1479 #ifdef XP_WIN
1480   // This is needed to avoid freezing the window on a device crash on double
1481   // buffering, see bug 1549674.
1482   if (gfxVars::UseDoubleBufferingWithCompositor() && XRE_IsGPUProcess() &&
1483       aBackendHints.Contains(LayersBackend::LAYERS_D3D11)) {
1484     mWidget->AsWindows()->EnsureCompositorWindow();
1485   }
1486 #endif
1487 
1488   InitializeLayerManager(aBackendHints);
1489 
1490   if (!mLayerManager) {
1491     NS_WARNING("Failed to initialise Compositor");
1492     LayerTransactionParent* p = new LayerTransactionParent(
1493         /* aManager */ nullptr, this, /* aAnimStorage */ nullptr,
1494         mRootLayerTreeID, mVsyncRate);
1495     p->AddIPDLReference();
1496     return p;
1497   }
1498 
1499   mCompositionManager = new AsyncCompositionManager(this, mLayerManager);
1500 
1501   LayerTransactionParent* p = new LayerTransactionParent(
1502       mLayerManager, this, GetAnimationStorage(), mRootLayerTreeID, mVsyncRate);
1503   p->AddIPDLReference();
1504   return p;
1505 }
1506 
DeallocPLayerTransactionParent(PLayerTransactionParent * actor)1507 bool CompositorBridgeParent::DeallocPLayerTransactionParent(
1508     PLayerTransactionParent* actor) {
1509   static_cast<LayerTransactionParent*>(actor)->ReleaseIPDLReference();
1510   return true;
1511 }
1512 
GetCompositorBridgeParent(uint64_t id)1513 CompositorBridgeParent* CompositorBridgeParent::GetCompositorBridgeParent(
1514     uint64_t id) {
1515   AssertIsInCompositorThread();
1516   CompositorMap::iterator it = sCompositorMap->find(id);
1517   return it != sCompositorMap->end() ? it->second : nullptr;
1518 }
1519 
AddCompositor(CompositorBridgeParent * compositor,uint64_t * outID)1520 void CompositorBridgeParent::AddCompositor(CompositorBridgeParent* compositor,
1521                                            uint64_t* outID) {
1522   AssertIsInCompositorThread();
1523 
1524   static uint64_t sNextID = 1;
1525 
1526   ++sNextID;
1527   (*sCompositorMap)[sNextID] = compositor;
1528   *outID = sNextID;
1529 }
1530 
RemoveCompositor(uint64_t id)1531 CompositorBridgeParent* CompositorBridgeParent::RemoveCompositor(uint64_t id) {
1532   AssertIsInCompositorThread();
1533 
1534   CompositorMap::iterator it = sCompositorMap->find(id);
1535   if (it == sCompositorMap->end()) {
1536     return nullptr;
1537   }
1538   CompositorBridgeParent* retval = it->second;
1539   sCompositorMap->erase(it);
1540   return retval;
1541 }
1542 
NotifyVsync(const VsyncEvent & aVsync,const LayersId & aLayersId)1543 void CompositorBridgeParent::NotifyVsync(const VsyncEvent& aVsync,
1544                                          const LayersId& aLayersId) {
1545   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
1546   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1547 
1548   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1549   auto it = sIndirectLayerTrees.find(aLayersId);
1550   if (it == sIndirectLayerTrees.end()) return;
1551 
1552   CompositorBridgeParent* cbp = it->second.mParent;
1553   if (!cbp || !cbp->mWidget) return;
1554 
1555   RefPtr<VsyncObserver> obs = cbp->mWidget->GetVsyncObserver();
1556   if (!obs) return;
1557 
1558   obs->NotifyVsync(aVsync);
1559 }
1560 
1561 /* static */
ScheduleForcedComposition(const LayersId & aLayersId)1562 void CompositorBridgeParent::ScheduleForcedComposition(
1563     const LayersId& aLayersId) {
1564   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
1565   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1566 
1567   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1568   auto it = sIndirectLayerTrees.find(aLayersId);
1569   if (it == sIndirectLayerTrees.end()) {
1570     return;
1571   }
1572 
1573   CompositorBridgeParent* cbp = it->second.mParent;
1574   if (!cbp || !cbp->mWidget) {
1575     return;
1576   }
1577 
1578   if (cbp->mWrBridge) {
1579     cbp->mWrBridge->ScheduleForcedGenerateFrame();
1580   } else if (cbp->CanComposite()) {
1581     cbp->mCompositorScheduler->ScheduleComposition();
1582   }
1583 }
1584 
RecvNotifyChildCreated(const LayersId & child,CompositorOptions * aOptions)1585 mozilla::ipc::IPCResult CompositorBridgeParent::RecvNotifyChildCreated(
1586     const LayersId& child, CompositorOptions* aOptions) {
1587   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1588   NotifyChildCreated(child);
1589   *aOptions = mOptions;
1590   return IPC_OK();
1591 }
1592 
RecvNotifyChildRecreated(const LayersId & aChild,CompositorOptions * aOptions)1593 mozilla::ipc::IPCResult CompositorBridgeParent::RecvNotifyChildRecreated(
1594     const LayersId& aChild, CompositorOptions* aOptions) {
1595   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1596 
1597   if (sIndirectLayerTrees.find(aChild) != sIndirectLayerTrees.end()) {
1598     NS_WARNING("Invalid to register the same layer tree twice");
1599     return IPC_FAIL_NO_REASON(this);
1600   }
1601 
1602   NotifyChildCreated(aChild);
1603   *aOptions = mOptions;
1604   return IPC_OK();
1605 }
1606 
NotifyChildCreated(LayersId aChild)1607 void CompositorBridgeParent::NotifyChildCreated(LayersId aChild) {
1608   sIndirectLayerTreesLock->AssertCurrentThreadOwns();
1609   sIndirectLayerTrees[aChild].mParent = this;
1610   sIndirectLayerTrees[aChild].mLayerManager = mLayerManager;
1611 }
1612 
RecvMapAndNotifyChildCreated(const LayersId & aChild,const base::ProcessId & aOwnerPid,CompositorOptions * aOptions)1613 mozilla::ipc::IPCResult CompositorBridgeParent::RecvMapAndNotifyChildCreated(
1614     const LayersId& aChild, const base::ProcessId& aOwnerPid,
1615     CompositorOptions* aOptions) {
1616   // We only use this message when the remote compositor is in the GPU process.
1617   // It is harmless to call it, though.
1618   MOZ_ASSERT(XRE_IsGPUProcess());
1619 
1620   LayerTreeOwnerTracker::Get()->Map(aChild, aOwnerPid);
1621 
1622   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1623   NotifyChildCreated(aChild);
1624   *aOptions = mOptions;
1625   return IPC_OK();
1626 }
1627 
1628 enum class CompositorOptionsChangeKind {
1629   eSupported,
1630   eBestEffort,
1631   eUnsupported
1632 };
1633 
ClassifyCompositorOptionsChange(const CompositorOptions & aOld,const CompositorOptions & aNew)1634 static CompositorOptionsChangeKind ClassifyCompositorOptionsChange(
1635     const CompositorOptions& aOld, const CompositorOptions& aNew) {
1636   if (aOld == aNew) {
1637     return CompositorOptionsChangeKind::eSupported;
1638   }
1639   if (aOld.UseAdvancedLayers() == aNew.UseAdvancedLayers() &&
1640       aOld.UseWebRender() == aNew.UseWebRender() &&
1641       aOld.InitiallyPaused() == aNew.InitiallyPaused()) {
1642     // Only APZ enablement changed.
1643     return CompositorOptionsChangeKind::eBestEffort;
1644   }
1645   return CompositorOptionsChangeKind::eUnsupported;
1646 }
1647 
RecvAdoptChild(const LayersId & child)1648 mozilla::ipc::IPCResult CompositorBridgeParent::RecvAdoptChild(
1649     const LayersId& child) {
1650   RefPtr<APZUpdater> oldApzUpdater;
1651   APZCTreeManagerParent* parent;
1652   bool scheduleComposition = false;
1653   bool apzEnablementChanged = false;
1654   RefPtr<WebRenderBridgeParent> childWrBridge;
1655 
1656   // Before adopting the child, save the old compositor's root content
1657   // controller. We may need this to clear old layer transforms associated
1658   // with the child.
1659   // This is outside the lock because GetGeckoContentControllerForRoot()
1660   // does its own locking.
1661   RefPtr<GeckoContentController> oldRootController =
1662       GetGeckoContentControllerForRoot(child);
1663 
1664   {  // scope lock
1665     MonitorAutoLock lock(*sIndirectLayerTreesLock);
1666     // If child is already belong to this CompositorBridgeParent,
1667     // no need to handle adopting child.
1668     if (sIndirectLayerTrees[child].mParent == this) {
1669       return IPC_OK();
1670     }
1671 
1672     if (sIndirectLayerTrees[child].mParent) {
1673       switch (ClassifyCompositorOptionsChange(
1674           sIndirectLayerTrees[child].mParent->mOptions, mOptions)) {
1675         case CompositorOptionsChangeKind::eUnsupported: {
1676           MOZ_ASSERT(false,
1677                      "Moving tab between windows whose compositor options"
1678                      "differ in unsupported ways. Things may break in "
1679                      "unexpected ways");
1680           break;
1681         }
1682         case CompositorOptionsChangeKind::eBestEffort: {
1683           NS_WARNING(
1684               "Moving tab between windows with different APZ enablement. "
1685               "This is supported on a best-effort basis, but some things may "
1686               "break.");
1687           apzEnablementChanged = true;
1688           break;
1689         }
1690         case CompositorOptionsChangeKind::eSupported: {
1691           // The common case, no action required.
1692           break;
1693         }
1694       }
1695       oldApzUpdater = sIndirectLayerTrees[child].mParent->mApzUpdater;
1696     }
1697     NotifyChildCreated(child);
1698     if (sIndirectLayerTrees[child].mLayerTree) {
1699       sIndirectLayerTrees[child].mLayerTree->SetLayerManager(
1700           mLayerManager, GetAnimationStorage());
1701       // Trigger composition to handle a case that mLayerTree was not composited
1702       // yet by previous CompositorBridgeParent, since nsRefreshDriver might
1703       // wait composition complete.
1704       scheduleComposition = true;
1705     }
1706     if (mWrBridge) {
1707       childWrBridge = sIndirectLayerTrees[child].mWrBridge;
1708     }
1709     parent = sIndirectLayerTrees[child].mApzcTreeManagerParent;
1710   }
1711 
1712   if (scheduleComposition) {
1713     ScheduleComposition();
1714   }
1715 
1716   if (childWrBridge) {
1717     MOZ_ASSERT(mWrBridge);
1718     RefPtr<wr::WebRenderAPI> api = mWrBridge->GetWebRenderAPI();
1719     api = api->Clone();
1720     wr::Epoch newEpoch = childWrBridge->UpdateWebRender(
1721         mWrBridge->CompositorScheduler(), std::move(api),
1722         mWrBridge->AsyncImageManager(),
1723         mWrBridge->GetTextureFactoryIdentifier());
1724     // Pretend we composited, since parent CompositorBridgeParent was replaced.
1725     TimeStamp now = TimeStamp::Now();
1726     NotifyPipelineRendered(childWrBridge->PipelineId(), newEpoch, VsyncId(),
1727                            now, now, now);
1728   }
1729 
1730   if (oldApzUpdater) {
1731     // If we are moving a child from an APZ-enabled window to an APZ-disabled
1732     // window (which can happen if e.g. a WebExtension moves a tab into a
1733     // popup window), try to handle it gracefully by clearing the old layer
1734     // transforms associated with the child. (Since the new compositor is
1735     // APZ-disabled, there will be nothing to update the transforms going
1736     // forward.)
1737     if (!mApzUpdater && oldRootController) {
1738       // Tell the old APZCTreeManager not to send any more layer transforms
1739       // for this layers ids.
1740       oldApzUpdater->MarkAsDetached(child);
1741 
1742       // Clear the current transforms.
1743       nsTArray<MatrixMessage> clear;
1744       clear.AppendElement(MatrixMessage(Nothing(), ScreenRect(), child));
1745       oldRootController->NotifyLayerTransforms(std::move(clear));
1746     }
1747   }
1748   if (mApzUpdater) {
1749     if (parent) {
1750       MOZ_ASSERT(mApzcTreeManager);
1751       parent->ChildAdopted(mApzcTreeManager, mApzUpdater);
1752     }
1753     mApzUpdater->NotifyLayerTreeAdopted(child, oldApzUpdater);
1754   }
1755   if (apzEnablementChanged) {
1756     Unused << SendCompositorOptionsChanged(child, mOptions);
1757   }
1758   return IPC_OK();
1759 }
1760 
AllocPWebRenderBridgeParent(const wr::PipelineId & aPipelineId,const LayoutDeviceIntSize & aSize,const WindowKind & aWindowKind)1761 PWebRenderBridgeParent* CompositorBridgeParent::AllocPWebRenderBridgeParent(
1762     const wr::PipelineId& aPipelineId, const LayoutDeviceIntSize& aSize,
1763     const WindowKind& aWindowKind) {
1764   MOZ_ASSERT(wr::AsLayersId(aPipelineId) == mRootLayerTreeID);
1765   MOZ_ASSERT(!mWrBridge);
1766   MOZ_ASSERT(!mCompositor);
1767   MOZ_ASSERT(!mCompositorScheduler);
1768   MOZ_ASSERT(mWidget);
1769 
1770 #ifdef XP_WIN
1771   if (mWidget && mWidget->AsWindows()) {
1772     const auto options = mWidget->GetCompositorOptions();
1773     if (!options.UseSoftwareWebRender() &&
1774         (DeviceManagerDx::Get()->CanUseDComp() ||
1775          gfxVars::UseWebRenderFlipSequentialWin())) {
1776       mWidget->AsWindows()->EnsureCompositorWindow();
1777     } else if (options.UseSoftwareWebRender() &&
1778                mWidget->AsWindows()->GetCompositorHwnd()) {
1779       mWidget->AsWindows()->DestroyCompositorWindow();
1780     }
1781   }
1782 #endif
1783 
1784   RefPtr<widget::CompositorWidget> widget = mWidget;
1785   wr::WrWindowId windowId = wr::NewWindowId();
1786   if (mApzUpdater) {
1787     // If APZ is enabled, we need to register the APZ updater with the window id
1788     // before the updater thread is created in WebRenderAPI::Create, so
1789     // that the callback from the updater thread can find the right APZUpdater.
1790     mApzUpdater->SetWebRenderWindowId(windowId);
1791   }
1792   if (mApzSampler) {
1793     // Same as for mApzUpdater, but for the sampler thread.
1794     mApzSampler->SetWebRenderWindowId(windowId);
1795   }
1796   if (mOMTASampler) {
1797     // Same, but for the OMTA sampler.
1798     mOMTASampler->SetWebRenderWindowId(windowId);
1799   }
1800 
1801   nsCString error("FEATURE_FAILURE_WEBRENDER_INITIALIZE_UNSPECIFIED");
1802   RefPtr<wr::WebRenderAPI> api = wr::WebRenderAPI::Create(
1803       this, std::move(widget), windowId, aSize, aWindowKind, error);
1804   if (!api) {
1805     mWrBridge =
1806         WebRenderBridgeParent::CreateDestroyed(aPipelineId, std::move(error));
1807     mWrBridge.get()->AddRef();  // IPDL reference
1808     return mWrBridge;
1809   }
1810 
1811 #ifdef MOZ_WIDGET_ANDROID
1812   // On Android, WebRenderAPI::Resume() call is triggered from Java side. But
1813   // Java side does not know about fallback to RenderCompositorOGLSWGL. In this
1814   // fallback case, RenderCompositor::Resume() needs to be called from gfx code.
1815   if (!mPaused && mWidget->GetCompositorOptions().UseSoftwareWebRender() &&
1816       mWidget->GetCompositorOptions().AllowSoftwareWebRenderOGL()) {
1817     api->Resume();
1818   }
1819 #endif
1820 
1821   wr::TransactionBuilder txn(api);
1822   txn.SetRootPipeline(aPipelineId);
1823   api->SendTransaction(txn);
1824 
1825   bool useCompositorWnd = false;
1826 #ifdef XP_WIN
1827   // Headless mode uses HeadlessWidget.
1828   if (mWidget->AsWindows()) {
1829     useCompositorWnd = !!mWidget->AsWindows()->GetCompositorHwnd();
1830   }
1831 #endif
1832   mAsyncImageManager =
1833       new AsyncImagePipelineManager(api->Clone(), useCompositorWnd);
1834   RefPtr<AsyncImagePipelineManager> asyncMgr = mAsyncImageManager;
1835   mWrBridge = new WebRenderBridgeParent(this, aPipelineId, mWidget, nullptr,
1836                                         std::move(api), std::move(asyncMgr),
1837                                         mVsyncRate);
1838   mWrBridge.get()->AddRef();  // IPDL reference
1839 
1840   mCompositorScheduler = mWrBridge->CompositorScheduler();
1841   MOZ_ASSERT(mCompositorScheduler);
1842   {  // scope lock
1843     MonitorAutoLock lock(*sIndirectLayerTreesLock);
1844     MOZ_ASSERT(sIndirectLayerTrees[mRootLayerTreeID].mWrBridge == nullptr);
1845     sIndirectLayerTrees[mRootLayerTreeID].mWrBridge = mWrBridge;
1846   }
1847   return mWrBridge;
1848 }
1849 
DeallocPWebRenderBridgeParent(PWebRenderBridgeParent * aActor)1850 bool CompositorBridgeParent::DeallocPWebRenderBridgeParent(
1851     PWebRenderBridgeParent* aActor) {
1852   WebRenderBridgeParent* parent = static_cast<WebRenderBridgeParent*>(aActor);
1853   {
1854     MonitorAutoLock lock(*sIndirectLayerTreesLock);
1855     auto it = sIndirectLayerTrees.find(wr::AsLayersId(parent->PipelineId()));
1856     if (it != sIndirectLayerTrees.end()) {
1857       it->second.mWrBridge = nullptr;
1858     }
1859   }
1860   parent->Release();  // IPDL reference
1861   return true;
1862 }
1863 
AllocPWebGPUParent()1864 webgpu::PWebGPUParent* CompositorBridgeParent::AllocPWebGPUParent() {
1865   // This should only ever get called in the GPU process.
1866   MOZ_ASSERT(XRE_IsGPUProcess());
1867   // Shouldn't re-initialize
1868   MOZ_ASSERT(!mWebGPUBridge);
1869   // We should only ever get this if WebGPU is enabled in this compositor.
1870   MOZ_RELEASE_ASSERT(mOptions.UseWebGPU());
1871 
1872   mWebGPUBridge = new webgpu::WebGPUParent();
1873   mWebGPUBridge.get()->AddRef();  // IPDL reference
1874   return mWebGPUBridge;
1875 }
1876 
DeallocPWebGPUParent(webgpu::PWebGPUParent * aActor)1877 bool CompositorBridgeParent::DeallocPWebGPUParent(
1878     webgpu::PWebGPUParent* aActor) {
1879   webgpu::WebGPUParent* parent = static_cast<webgpu::WebGPUParent*>(aActor);
1880   MOZ_ASSERT(mWebGPUBridge == parent);
1881   parent->Release();  // IPDL reference
1882   mWebGPUBridge = nullptr;
1883   return true;
1884 }
1885 
NotifyMemoryPressure()1886 void CompositorBridgeParent::NotifyMemoryPressure() {
1887   if (mWrBridge) {
1888     RefPtr<wr::WebRenderAPI> api = mWrBridge->GetWebRenderAPI();
1889     if (api) {
1890       api->NotifyMemoryPressure();
1891     }
1892   }
1893 }
1894 
AccumulateMemoryReport(wr::MemoryReport * aReport)1895 void CompositorBridgeParent::AccumulateMemoryReport(wr::MemoryReport* aReport) {
1896   if (mWrBridge) {
1897     RefPtr<wr::WebRenderAPI> api = mWrBridge->GetWebRenderAPI();
1898     if (api) {
1899       api->AccumulateMemoryReport(aReport);
1900     }
1901   }
1902 }
1903 
1904 /*static*/
InitializeStatics()1905 void CompositorBridgeParent::InitializeStatics() {
1906   gfxVars::SetForceSubpixelAAWherePossibleListener(&UpdateQualitySettings);
1907   gfxVars::SetWebRenderDebugFlagsListener(&UpdateDebugFlags);
1908   gfxVars::SetUseWebRenderMultithreadingListener(
1909       &UpdateWebRenderMultithreading);
1910   gfxVars::SetWebRenderBatchingLookbackListener(
1911       &UpdateWebRenderBatchingParameters);
1912   gfxVars::SetWebRenderProfilerUIListener(&UpdateWebRenderProfilerUI);
1913 }
1914 
1915 /*static*/
UpdateQualitySettings()1916 void CompositorBridgeParent::UpdateQualitySettings() {
1917   if (!CompositorThreadHolder::IsInCompositorThread()) {
1918     if (CompositorThread()) {
1919       CompositorThread()->Dispatch(
1920           NewRunnableFunction("CompositorBridgeParent::UpdateQualitySettings",
1921                               &CompositorBridgeParent::UpdateQualitySettings));
1922     }
1923 
1924     // If there is no compositor thread, e.g. due to shutdown, then we can
1925     // safefully just ignore this request.
1926     return;
1927   }
1928 
1929   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1930   ForEachWebRenderBridgeParent([&](WebRenderBridgeParent* wrBridge) -> void {
1931     wrBridge->UpdateQualitySettings();
1932   });
1933 }
1934 
1935 /*static*/
UpdateDebugFlags()1936 void CompositorBridgeParent::UpdateDebugFlags() {
1937   if (!CompositorThreadHolder::IsInCompositorThread()) {
1938     if (CompositorThread()) {
1939       CompositorThread()->Dispatch(
1940           NewRunnableFunction("CompositorBridgeParent::UpdateDebugFlags",
1941                               &CompositorBridgeParent::UpdateDebugFlags));
1942     }
1943 
1944     // If there is no compositor thread, e.g. due to shutdown, then we can
1945     // safefully just ignore this request.
1946     return;
1947   }
1948 
1949   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1950   ForEachWebRenderBridgeParent([&](WebRenderBridgeParent* wrBridge) -> void {
1951     wrBridge->UpdateDebugFlags();
1952   });
1953 }
1954 
1955 /*static*/
UpdateWebRenderMultithreading()1956 void CompositorBridgeParent::UpdateWebRenderMultithreading() {
1957   if (!CompositorThreadHolder::IsInCompositorThread()) {
1958     if (CompositorThread()) {
1959       CompositorThread()->Dispatch(NewRunnableFunction(
1960           "CompositorBridgeParent::UpdateWebRenderMultithreading",
1961           &CompositorBridgeParent::UpdateWebRenderMultithreading));
1962     }
1963 
1964     return;
1965   }
1966 
1967   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1968   ForEachWebRenderBridgeParent([&](WebRenderBridgeParent* wrBridge) -> void {
1969     wrBridge->UpdateMultithreading();
1970   });
1971 }
1972 
1973 /*static*/
UpdateWebRenderBatchingParameters()1974 void CompositorBridgeParent::UpdateWebRenderBatchingParameters() {
1975   if (!CompositorThreadHolder::IsInCompositorThread()) {
1976     if (CompositorThread()) {
1977       CompositorThread()->Dispatch(NewRunnableFunction(
1978           "CompositorBridgeParent::UpdateWebRenderBatchingParameters",
1979           &CompositorBridgeParent::UpdateWebRenderBatchingParameters));
1980     }
1981 
1982     return;
1983   }
1984 
1985   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1986   ForEachWebRenderBridgeParent([&](WebRenderBridgeParent* wrBridge) -> void {
1987     wrBridge->UpdateBatchingParameters();
1988   });
1989 }
1990 
1991 /*static*/
UpdateWebRenderProfilerUI()1992 void CompositorBridgeParent::UpdateWebRenderProfilerUI() {
1993   if (!sIndirectLayerTreesLock) {
1994     return;
1995   }
1996   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1997   ForEachWebRenderBridgeParent([&](WebRenderBridgeParent* wrBridge) -> void {
1998     wrBridge->UpdateProfilerUI();
1999   });
2000 }
2001 
GetWebRenderBridgeParent() const2002 RefPtr<WebRenderBridgeParent> CompositorBridgeParent::GetWebRenderBridgeParent()
2003     const {
2004   return mWrBridge;
2005 }
2006 
GetTestingTimeStamp() const2007 Maybe<TimeStamp> CompositorBridgeParent::GetTestingTimeStamp() const {
2008   return mTestTime;
2009 }
2010 
EraseLayerState(LayersId aId)2011 void EraseLayerState(LayersId aId) {
2012   RefPtr<APZUpdater> apz;
2013   RefPtr<WebRenderBridgeParent> wrBridge;
2014 
2015   {  // scope lock
2016     MonitorAutoLock lock(*sIndirectLayerTreesLock);
2017     auto iter = sIndirectLayerTrees.find(aId);
2018     if (iter != sIndirectLayerTrees.end()) {
2019       CompositorBridgeParent* parent = iter->second.mParent;
2020       if (parent) {
2021         apz = parent->GetAPZUpdater();
2022       }
2023       wrBridge = iter->second.mWrBridge;
2024       sIndirectLayerTrees.erase(iter);
2025     }
2026   }
2027 
2028   if (apz) {
2029     apz->NotifyLayerTreeRemoved(aId);
2030   }
2031 
2032   if (wrBridge) {
2033     wrBridge->Destroy();
2034   }
2035 }
2036 
2037 /*static*/
DeallocateLayerTreeId(LayersId aId)2038 void CompositorBridgeParent::DeallocateLayerTreeId(LayersId aId) {
2039   MOZ_ASSERT(NS_IsMainThread());
2040   // Here main thread notifies compositor to remove an element from
2041   // sIndirectLayerTrees. This removed element might be queried soon.
2042   // Checking the elements of sIndirectLayerTrees exist or not before using.
2043   if (!CompositorThread()) {
2044     gfxCriticalError() << "Attempting to post to an invalid Compositor Thread";
2045     return;
2046   }
2047   CompositorThread()->Dispatch(
2048       NewRunnableFunction("EraseLayerStateRunnable", &EraseLayerState, aId));
2049 }
2050 
UpdateControllerForLayersId(LayersId aLayersId,GeckoContentController * aController)2051 static void UpdateControllerForLayersId(LayersId aLayersId,
2052                                         GeckoContentController* aController) {
2053   // Adopt ref given to us by SetControllerForLayerTree()
2054   MonitorAutoLock lock(*sIndirectLayerTreesLock);
2055   sIndirectLayerTrees[aLayersId].mController =
2056       already_AddRefed<GeckoContentController>(aController);
2057 }
2058 
ScopedLayerTreeRegistration(LayersId aLayersId,Layer * aRoot,GeckoContentController * aController)2059 ScopedLayerTreeRegistration::ScopedLayerTreeRegistration(
2060     LayersId aLayersId, Layer* aRoot, GeckoContentController* aController)
2061     : mLayersId(aLayersId) {
2062   EnsureLayerTreeMapReady();
2063   MonitorAutoLock lock(*sIndirectLayerTreesLock);
2064   sIndirectLayerTrees[aLayersId].mRoot = aRoot;
2065   sIndirectLayerTrees[aLayersId].mController = aController;
2066 }
2067 
ScopedLayerTreeRegistration(LayersId aLayersId,GeckoContentController * aController)2068 ScopedLayerTreeRegistration::ScopedLayerTreeRegistration(
2069     LayersId aLayersId, GeckoContentController* aController)
2070     : mLayersId(aLayersId) {
2071   EnsureLayerTreeMapReady();
2072   MonitorAutoLock lock(*sIndirectLayerTreesLock);
2073   sIndirectLayerTrees[aLayersId].mRoot = nullptr;
2074   sIndirectLayerTrees[aLayersId].mController = aController;
2075 }
2076 
~ScopedLayerTreeRegistration()2077 ScopedLayerTreeRegistration::~ScopedLayerTreeRegistration() {
2078   MonitorAutoLock lock(*sIndirectLayerTreesLock);
2079   sIndirectLayerTrees.erase(mLayersId);
2080 }
2081 
2082 /*static*/
SetControllerForLayerTree(LayersId aLayersId,GeckoContentController * aController)2083 void CompositorBridgeParent::SetControllerForLayerTree(
2084     LayersId aLayersId, GeckoContentController* aController) {
2085   // This ref is adopted by UpdateControllerForLayersId().
2086   aController->AddRef();
2087   CompositorThread()->Dispatch(NewRunnableFunction(
2088       "UpdateControllerForLayersIdRunnable", &UpdateControllerForLayersId,
2089       aLayersId, aController));
2090 }
2091 
2092 /*static*/
GetAPZCTreeManager(LayersId aLayersId)2093 already_AddRefed<IAPZCTreeManager> CompositorBridgeParent::GetAPZCTreeManager(
2094     LayersId aLayersId) {
2095   EnsureLayerTreeMapReady();
2096   MonitorAutoLock lock(*sIndirectLayerTreesLock);
2097   LayerTreeMap::iterator cit = sIndirectLayerTrees.find(aLayersId);
2098   if (sIndirectLayerTrees.end() == cit) {
2099     return nullptr;
2100   }
2101   LayerTreeState* lts = &cit->second;
2102 
2103   RefPtr<IAPZCTreeManager> apzctm =
2104       lts->mParent ? lts->mParent->mApzcTreeManager.get() : nullptr;
2105   return apzctm.forget();
2106 }
2107 
InsertVsyncProfilerMarker(TimeStamp aVsyncTimestamp)2108 static void InsertVsyncProfilerMarker(TimeStamp aVsyncTimestamp) {
2109   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
2110   if (profiler_thread_is_being_profiled()) {
2111     // Tracks when a vsync occurs according to the HardwareComposer.
2112     struct VsyncMarker {
2113       static constexpr mozilla::Span<const char> MarkerTypeName() {
2114         return mozilla::MakeStringSpan("VsyncTimestamp");
2115       }
2116       static void StreamJSONMarkerData(
2117           baseprofiler::SpliceableJSONWriter& aWriter) {}
2118       static MarkerSchema MarkerTypeDisplay() {
2119         using MS = MarkerSchema;
2120         MS schema{MS::Location::markerChart, MS::Location::markerTable};
2121         // Nothing outside the defaults.
2122         return schema;
2123       }
2124     };
2125     profiler_add_marker("VsyncTimestamp", geckoprofiler::category::GRAPHICS,
2126                         MarkerTiming::InstantAt(aVsyncTimestamp),
2127                         VsyncMarker{});
2128   }
2129 }
2130 
2131 /*static */
PostInsertVsyncProfilerMarker(TimeStamp aVsyncTimestamp)2132 void CompositorBridgeParent::PostInsertVsyncProfilerMarker(
2133     TimeStamp aVsyncTimestamp) {
2134   // Called in the vsync thread
2135   if (profiler_is_active() && CompositorThreadHolder::IsActive()) {
2136     CompositorThread()->Dispatch(
2137         NewRunnableFunction("InsertVsyncProfilerMarkerRunnable",
2138                             InsertVsyncProfilerMarker, aVsyncTimestamp));
2139   }
2140 }
2141 
2142 widget::PCompositorWidgetParent*
AllocPCompositorWidgetParent(const CompositorWidgetInitData & aInitData)2143 CompositorBridgeParent::AllocPCompositorWidgetParent(
2144     const CompositorWidgetInitData& aInitData) {
2145 #if defined(MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING)
2146   if (mWidget) {
2147     // Should not create two widgets on the same compositor.
2148     return nullptr;
2149   }
2150 
2151   widget::CompositorWidgetParent* widget =
2152       new widget::CompositorWidgetParent(aInitData, mOptions);
2153   widget->AddRef();
2154 
2155   // Sending the constructor acts as initialization as well.
2156   mWidget = widget;
2157   return widget;
2158 #else
2159   return nullptr;
2160 #endif
2161 }
2162 
DeallocPCompositorWidgetParent(PCompositorWidgetParent * aActor)2163 bool CompositorBridgeParent::DeallocPCompositorWidgetParent(
2164     PCompositorWidgetParent* aActor) {
2165 #if defined(MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING)
2166   static_cast<widget::CompositorWidgetParent*>(aActor)->Release();
2167   return true;
2168 #else
2169   return false;
2170 #endif
2171 }
2172 
IsPendingComposite()2173 bool CompositorBridgeParent::IsPendingComposite() {
2174   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
2175   if (!mCompositor) {
2176     return false;
2177   }
2178   return mCompositor->IsPendingComposite();
2179 }
2180 
FinishPendingComposite()2181 void CompositorBridgeParent::FinishPendingComposite() {
2182   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
2183   if (!mCompositor) {
2184     return;
2185   }
2186   return mCompositor->FinishPendingComposite();
2187 }
2188 
2189 CompositorController*
GetCompositorController() const2190 CompositorBridgeParent::LayerTreeState::GetCompositorController() const {
2191   return mParent;
2192 }
2193 
2194 MetricsSharingController*
CrossProcessSharingController() const2195 CompositorBridgeParent::LayerTreeState::CrossProcessSharingController() const {
2196   return mContentCompositorBridgeParent;
2197 }
2198 
2199 MetricsSharingController*
InProcessSharingController() const2200 CompositorBridgeParent::LayerTreeState::InProcessSharingController() const {
2201   return mParent;
2202 }
2203 
DidComposite(const VsyncId & aId,TimeStamp & aCompositeStart,TimeStamp & aCompositeEnd)2204 void CompositorBridgeParent::DidComposite(const VsyncId& aId,
2205                                           TimeStamp& aCompositeStart,
2206                                           TimeStamp& aCompositeEnd) {
2207   if (mWrBridge) {
2208     MOZ_ASSERT(false);  // This should never get called for a WR compositor
2209   } else {
2210     NotifyDidComposite(mPendingTransactions, aId, aCompositeStart,
2211                        aCompositeEnd);
2212 #if defined(ENABLE_FRAME_LATENCY_LOG)
2213     if (!mPendingTransactions.IsEmpty()) {
2214       if (mRefreshStartTime) {
2215         int32_t latencyMs =
2216             lround((aCompositeEnd - mRefreshStartTime).ToMilliseconds());
2217         printf_stderr(
2218             "From transaction start to end of generate frame latencyMs %d this "
2219             "%p\n",
2220             latencyMs, this);
2221       }
2222       if (mFwdTime) {
2223         int32_t latencyMs = lround((aCompositeEnd - mFwdTime).ToMilliseconds());
2224         printf_stderr(
2225             "From forwarding transaction to end of generate frame latencyMs %d "
2226             "this %p\n",
2227             latencyMs, this);
2228       }
2229     }
2230     mRefreshStartTime = TimeStamp();
2231     mTxnStartTime = TimeStamp();
2232     mFwdTime = TimeStamp();
2233 #endif
2234     mPendingTransactions.Clear();
2235   }
2236 }
2237 
NotifyDidSceneBuild(RefPtr<const wr::WebRenderPipelineInfo> aInfo)2238 void CompositorBridgeParent::NotifyDidSceneBuild(
2239     RefPtr<const wr::WebRenderPipelineInfo> aInfo) {
2240   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
2241   if (mPaused) {
2242     return;
2243   }
2244 
2245   if (mWrBridge) {
2246     mWrBridge->NotifyDidSceneBuild(aInfo);
2247   } else {
2248     mCompositorScheduler->ScheduleComposition();
2249   }
2250 }
2251 
NotifyDidRender(const VsyncId & aCompositeStartId,TimeStamp & aCompositeStart,TimeStamp & aRenderStart,TimeStamp & aCompositeEnd,wr::RendererStats * aStats)2252 void CompositorBridgeParent::NotifyDidRender(const VsyncId& aCompositeStartId,
2253                                              TimeStamp& aCompositeStart,
2254                                              TimeStamp& aRenderStart,
2255                                              TimeStamp& aCompositeEnd,
2256                                              wr::RendererStats* aStats) {
2257   if (!mWrBridge) {
2258     return;
2259   }
2260 
2261   MOZ_RELEASE_ASSERT(mWrBridge->IsRootWebRenderBridgeParent());
2262 
2263   RefPtr<UiCompositorControllerParent> uiController =
2264       UiCompositorControllerParent::GetFromRootLayerTreeId(mRootLayerTreeID);
2265 
2266   if (uiController && mIsForcedFirstPaint) {
2267     uiController->NotifyFirstPaint();
2268     mIsForcedFirstPaint = false;
2269   }
2270 
2271   nsTArray<CompositionPayload> payload =
2272       mWrBridge->TakePendingScrollPayload(aCompositeStartId);
2273   if (!payload.IsEmpty()) {
2274     RecordCompositionPayloadsPresented(aCompositeEnd, payload);
2275   }
2276 
2277   nsTArray<ImageCompositeNotificationInfo> notifications;
2278   mWrBridge->ExtractImageCompositeNotifications(&notifications);
2279   if (!notifications.IsEmpty()) {
2280     Unused << ImageBridgeParent::NotifyImageComposites(notifications);
2281   }
2282 }
2283 
MaybeDeclareStable()2284 void CompositorBridgeParent::MaybeDeclareStable() {
2285   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
2286 
2287   static bool sStable = false;
2288   if (!XRE_IsGPUProcess() || sStable) {
2289     return;
2290   }
2291 
2292   // Once we render as many frames as the threshold, we declare this instance of
2293   // the GPU process 'stable'. This causes the parent process to always respawn
2294   // the GPU process if it crashes.
2295   static uint32_t sFramesComposited = 0;
2296 
2297   if (++sFramesComposited >=
2298       StaticPrefs::layers_gpu_process_stable_frame_threshold()) {
2299     sStable = true;
2300 
2301     NS_DispatchToMainThread(NS_NewRunnableFunction(
2302         "gfx::GPUParent::SendDeclareStable", []() -> void {
2303           Unused << GPUParent::GetSingleton()->SendDeclareStable();
2304         }));
2305   }
2306 }
2307 
NotifyPipelineRendered(const wr::PipelineId & aPipelineId,const wr::Epoch & aEpoch,const VsyncId & aCompositeStartId,TimeStamp & aCompositeStart,TimeStamp & aRenderStart,TimeStamp & aCompositeEnd,wr::RendererStats * aStats)2308 void CompositorBridgeParent::NotifyPipelineRendered(
2309     const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch,
2310     const VsyncId& aCompositeStartId, TimeStamp& aCompositeStart,
2311     TimeStamp& aRenderStart, TimeStamp& aCompositeEnd,
2312     wr::RendererStats* aStats) {
2313   if (!mWrBridge || !mAsyncImageManager) {
2314     return;
2315   }
2316 
2317   bool isRoot = mWrBridge->PipelineId() == aPipelineId;
2318   RefPtr<WebRenderBridgeParent> wrBridge =
2319       isRoot ? mWrBridge
2320              : RefPtr<WebRenderBridgeParent>(
2321                    mAsyncImageManager->GetWrBridge(aPipelineId));
2322   if (!wrBridge) {
2323     return;
2324   }
2325 
2326   CompositorBridgeParentBase* compBridge =
2327       isRoot ? this : wrBridge->GetCompositorBridge();
2328   if (!compBridge) {
2329     return;
2330   }
2331 
2332   MOZ_RELEASE_ASSERT(isRoot == wrBridge->IsRootWebRenderBridgeParent());
2333 
2334   wrBridge->RemoveEpochDataPriorTo(aEpoch);
2335 
2336   nsTArray<FrameStats> stats;
2337   nsTArray<TransactionId> transactions;
2338 
2339   RefPtr<UiCompositorControllerParent> uiController =
2340       UiCompositorControllerParent::GetFromRootLayerTreeId(mRootLayerTreeID);
2341 
2342   wrBridge->FlushTransactionIdsForEpoch(
2343       aEpoch, aCompositeStartId, aCompositeStart, aRenderStart, aCompositeEnd,
2344       uiController, aStats, stats, transactions);
2345   if (transactions.IsEmpty()) {
2346     MOZ_ASSERT(stats.IsEmpty());
2347     return;
2348   }
2349 
2350   MaybeDeclareStable();
2351 
2352   LayersId layersId = isRoot ? LayersId{0} : wrBridge->GetLayersId();
2353   Unused << compBridge->SendDidComposite(layersId, transactions,
2354                                          aCompositeStart, aCompositeEnd);
2355 
2356   if (!stats.IsEmpty()) {
2357     Unused << SendNotifyFrameStats(stats);
2358   }
2359 }
2360 
2361 RefPtr<AsyncImagePipelineManager>
GetAsyncImagePipelineManager() const2362 CompositorBridgeParent::GetAsyncImagePipelineManager() const {
2363   return mAsyncImageManager;
2364 }
2365 
NotifyDidComposite(const nsTArray<TransactionId> & aTransactionIds,VsyncId aId,TimeStamp & aCompositeStart,TimeStamp & aCompositeEnd)2366 void CompositorBridgeParent::NotifyDidComposite(
2367     const nsTArray<TransactionId>& aTransactionIds, VsyncId aId,
2368     TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd) {
2369   MOZ_ASSERT(!mWrBridge,
2370              "We should be going through NotifyDidRender and "
2371              "NotifyPipelineRendered instead");
2372 
2373   MaybeDeclareStable();
2374   Unused << SendDidComposite(LayersId{0}, aTransactionIds, aCompositeStart,
2375                              aCompositeEnd);
2376 
2377   if (mLayerManager) {
2378     nsTArray<ImageCompositeNotificationInfo> notifications;
2379     mLayerManager->ExtractImageCompositeNotifications(&notifications);
2380     if (!notifications.IsEmpty()) {
2381       Unused << ImageBridgeParent::NotifyImageComposites(notifications);
2382     }
2383   }
2384 
2385   MonitorAutoLock lock(*sIndirectLayerTreesLock);
2386   ForEachIndirectLayerTree([&](LayerTreeState* lts,
2387                                const LayersId& aLayersId) -> void {
2388     if (lts->mContentCompositorBridgeParent && lts->mParent == this) {
2389       ContentCompositorBridgeParent* cpcp = lts->mContentCompositorBridgeParent;
2390       cpcp->DidCompositeLocked(aLayersId, aId, aCompositeStart, aCompositeEnd);
2391     }
2392   });
2393 }
2394 
InvalidateRemoteLayers()2395 void CompositorBridgeParent::InvalidateRemoteLayers() {
2396   MOZ_ASSERT(CompositorThread()->IsOnCurrentThread());
2397 
2398   Unused << PCompositorBridgeParent::SendInvalidateLayers(LayersId{0});
2399 
2400   MonitorAutoLock lock(*sIndirectLayerTreesLock);
2401   ForEachIndirectLayerTree([](LayerTreeState* lts,
2402                               const LayersId& aLayersId) -> void {
2403     if (lts->mContentCompositorBridgeParent) {
2404       ContentCompositorBridgeParent* cpcp = lts->mContentCompositorBridgeParent;
2405       Unused << cpcp->SendInvalidateLayers(aLayersId);
2406     }
2407   });
2408 }
2409 
UpdateIndirectTree(LayersId aId,Layer * aRoot,const TargetConfig & aTargetConfig)2410 void UpdateIndirectTree(LayersId aId, Layer* aRoot,
2411                         const TargetConfig& aTargetConfig) {
2412   MonitorAutoLock lock(*sIndirectLayerTreesLock);
2413   sIndirectLayerTrees[aId].mRoot = aRoot;
2414   sIndirectLayerTrees[aId].mTargetConfig = aTargetConfig;
2415 }
2416 
2417 /* static */ CompositorBridgeParent::LayerTreeState*
GetIndirectShadowTree(LayersId aId)2418 CompositorBridgeParent::GetIndirectShadowTree(LayersId aId) {
2419   // Only the compositor thread should use this method variant
2420   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
2421 
2422   MonitorAutoLock lock(*sIndirectLayerTreesLock);
2423   LayerTreeMap::iterator cit = sIndirectLayerTrees.find(aId);
2424   if (sIndirectLayerTrees.end() == cit) {
2425     return nullptr;
2426   }
2427   return &cit->second;
2428 }
2429 
2430 /* static */
CallWithIndirectShadowTree(LayersId aId,const std::function<void (CompositorBridgeParent::LayerTreeState &)> & aFunc)2431 bool CompositorBridgeParent::CallWithIndirectShadowTree(
2432     LayersId aId,
2433     const std::function<void(CompositorBridgeParent::LayerTreeState&)>& aFunc) {
2434   if (!sIndirectLayerTreesLock) {
2435     // Can hapen during shutdown
2436     return false;
2437   }
2438   // Note that this does not make things universally threadsafe just because the
2439   // sIndirectLayerTreesLock mutex is held. This is because the compositor
2440   // thread can mutate the LayerTreeState outside the lock. It does however
2441   // ensure that the *storage* for the LayerTreeState remains stable, since we
2442   // should always hold the lock when adding/removing entries to the map.
2443   MonitorAutoLock lock(*sIndirectLayerTreesLock);
2444   LayerTreeMap::iterator cit = sIndirectLayerTrees.find(aId);
2445   if (sIndirectLayerTrees.end() == cit) {
2446     return false;
2447   }
2448   aFunc(cit->second);
2449   return true;
2450 }
2451 
GetStateForRoot(LayersId aContentLayersId,const MonitorAutoLock & aProofOfLock)2452 static CompositorBridgeParent::LayerTreeState* GetStateForRoot(
2453     LayersId aContentLayersId, const MonitorAutoLock& aProofOfLock) {
2454   CompositorBridgeParent::LayerTreeState* state = nullptr;
2455   LayerTreeMap::iterator itr = sIndirectLayerTrees.find(aContentLayersId);
2456   if (sIndirectLayerTrees.end() != itr) {
2457     state = &itr->second;
2458   }
2459 
2460   // |state| is the state for the content process, but we want the APZCTMParent
2461   // for the parent process owning that content process. So we have to jump to
2462   // the LayerTreeState for the root layer tree id for that layer tree, and use
2463   // the mApzcTreeManagerParent from that. This should also work with nested
2464   // content processes, because RootLayerTreeId() will bypass any intermediate
2465   // processes' ids and go straight to the root.
2466   if (state && state->mParent) {
2467     LayersId rootLayersId = state->mParent->RootLayerTreeId();
2468     itr = sIndirectLayerTrees.find(rootLayersId);
2469     state = (sIndirectLayerTrees.end() != itr) ? &itr->second : nullptr;
2470   }
2471 
2472   return state;
2473 }
2474 
2475 /* static */
GetApzcTreeManagerParentForRoot(LayersId aContentLayersId)2476 APZCTreeManagerParent* CompositorBridgeParent::GetApzcTreeManagerParentForRoot(
2477     LayersId aContentLayersId) {
2478   MonitorAutoLock lock(*sIndirectLayerTreesLock);
2479   CompositorBridgeParent::LayerTreeState* state =
2480       GetStateForRoot(aContentLayersId, lock);
2481   return state ? state->mApzcTreeManagerParent : nullptr;
2482 }
2483 
2484 /* static */
2485 GeckoContentController*
GetGeckoContentControllerForRoot(LayersId aContentLayersId)2486 CompositorBridgeParent::GetGeckoContentControllerForRoot(
2487     LayersId aContentLayersId) {
2488   MonitorAutoLock lock(*sIndirectLayerTreesLock);
2489   CompositorBridgeParent::LayerTreeState* state =
2490       GetStateForRoot(aContentLayersId, lock);
2491   return state ? state->mController.get() : nullptr;
2492 }
2493 
AllocPTextureParent(const SurfaceDescriptor & aSharedData,const ReadLockDescriptor & aReadLock,const LayersBackend & aLayersBackend,const TextureFlags & aFlags,const LayersId & aId,const uint64_t & aSerial,const wr::MaybeExternalImageId & aExternalImageId)2494 PTextureParent* CompositorBridgeParent::AllocPTextureParent(
2495     const SurfaceDescriptor& aSharedData, const ReadLockDescriptor& aReadLock,
2496     const LayersBackend& aLayersBackend, const TextureFlags& aFlags,
2497     const LayersId& aId, const uint64_t& aSerial,
2498     const wr::MaybeExternalImageId& aExternalImageId) {
2499   return TextureHost::CreateIPDLActor(this, aSharedData, aReadLock,
2500                                       aLayersBackend, aFlags, aSerial,
2501                                       aExternalImageId);
2502 }
2503 
DeallocPTextureParent(PTextureParent * actor)2504 bool CompositorBridgeParent::DeallocPTextureParent(PTextureParent* actor) {
2505   return TextureHost::DestroyIPDLActor(actor);
2506 }
2507 
RecvInitPCanvasParent(Endpoint<PCanvasParent> && aEndpoint)2508 mozilla::ipc::IPCResult CompositorBridgeParent::RecvInitPCanvasParent(
2509     Endpoint<PCanvasParent>&& aEndpoint) {
2510   MOZ_CRASH("PCanvasParent shouldn't be created via CompositorBridgeParent.");
2511 }
2512 
RecvReleasePCanvasParent()2513 mozilla::ipc::IPCResult CompositorBridgeParent::RecvReleasePCanvasParent() {
2514   MOZ_CRASH("PCanvasParent shouldn't be released via CompositorBridgeParent.");
2515 }
2516 
IsSameProcess() const2517 bool CompositorBridgeParent::IsSameProcess() const {
2518   return OtherPid() == base::GetCurrentProcId();
2519 }
2520 
NotifyWebRenderDisableNativeCompositor()2521 void CompositorBridgeParent::NotifyWebRenderDisableNativeCompositor() {
2522   MOZ_ASSERT(CompositorThread()->IsOnCurrentThread());
2523   if (mWrBridge) {
2524     mWrBridge->DisableNativeCompositor();
2525   }
2526 }
2527 
RecordContentFrameTime(const VsyncId & aTxnId,const TimeStamp & aVsyncStart,const TimeStamp & aTxnStart,const VsyncId & aCompositeId,const TimeStamp & aCompositeEnd,const TimeDuration & aFullPaintTime,const TimeDuration & aVsyncRate,bool aContainsSVGGroup,bool aRecordUploadStats,wr::RendererStats * aStats)2528 int32_t RecordContentFrameTime(
2529     const VsyncId& aTxnId, const TimeStamp& aVsyncStart,
2530     const TimeStamp& aTxnStart, const VsyncId& aCompositeId,
2531     const TimeStamp& aCompositeEnd, const TimeDuration& aFullPaintTime,
2532     const TimeDuration& aVsyncRate, bool aContainsSVGGroup,
2533     bool aRecordUploadStats, wr::RendererStats* aStats /* = nullptr */) {
2534   double latencyMs = (aCompositeEnd - aTxnStart).ToMilliseconds();
2535   double latencyNorm = latencyMs / aVsyncRate.ToMilliseconds();
2536   int32_t fracLatencyNorm = lround(latencyNorm * 100.0);
2537 
2538   if (profiler_can_accept_markers()) {
2539     struct ContentFrameMarker {
2540       static constexpr Span<const char> MarkerTypeName() {
2541         return MakeStringSpan("CONTENT_FRAME_TIME");
2542       }
2543       static void StreamJSONMarkerData(
2544           baseprofiler::SpliceableJSONWriter& aWriter) {}
2545       static MarkerSchema MarkerTypeDisplay() {
2546         using MS = MarkerSchema;
2547         MS schema{MS::Location::markerChart, MS::Location::markerTable};
2548         // Nothing outside the defaults.
2549         return schema;
2550       }
2551     };
2552 
2553     profiler_add_marker("CONTENT_FRAME_TIME", geckoprofiler::category::GRAPHICS,
2554                         MarkerTiming::Interval(aTxnStart, aCompositeEnd),
2555                         ContentFrameMarker{});
2556   }
2557 
2558   Telemetry::Accumulate(Telemetry::CONTENT_FRAME_TIME, fracLatencyNorm);
2559 
2560   if (!(aTxnId == VsyncId()) && aVsyncStart) {
2561     latencyMs = (aCompositeEnd - aVsyncStart).ToMilliseconds();
2562     latencyNorm = latencyMs / aVsyncRate.ToMilliseconds();
2563     fracLatencyNorm = lround(latencyNorm * 100.0);
2564     int32_t result = fracLatencyNorm;
2565     Telemetry::Accumulate(Telemetry::CONTENT_FRAME_TIME_VSYNC, fracLatencyNorm);
2566 
2567     if (aContainsSVGGroup) {
2568       Telemetry::Accumulate(Telemetry::CONTENT_FRAME_TIME_WITH_SVG,
2569                             fracLatencyNorm);
2570     }
2571 
2572     // Record CONTENT_FRAME_TIME_REASON.
2573     //
2574     // Note that deseralizing a layers update (RecvUpdate) can delay the receipt
2575     // of the composite vsync message
2576     // (CompositorBridgeParent::CompositeToTarget), since they're using the same
2577     // thread. This can mean that compositing might start significantly late,
2578     // but this code will still detect it as having successfully started on the
2579     // right vsync (which is somewhat correct). We'd now have reduced time left
2580     // in the vsync interval to finish compositing, so the chances of a missed
2581     // frame increases. This is effectively including the RecvUpdate work as
2582     // part of the 'compositing' phase for this metric, but it isn't included in
2583     // COMPOSITE_TIME, and *is* included in CONTENT_FULL_PAINT_TIME.
2584     //
2585     // Also of note is that when the root WebRenderBridgeParent decides to
2586     // skip a composite (due to the Renderer being busy), that won't notify
2587     // child WebRenderBridgeParents. That failure will show up as the
2588     // composite starting late (since it did), but it's really a fault of a
2589     // slow composite on the previous frame, not a slow
2590     // CONTENT_FULL_PAINT_TIME. It would be nice to have a separate bucket for
2591     // this category (scene was ready on the next vsync, but we chose not to
2592     // composite), but I can't find a way to locate the right child
2593     // WebRenderBridgeParents from the root. WebRender notifies us of the
2594     // child pipelines contained within a render, after it finishes, but I
2595     // can't see how to query what child pipeline would have been rendered,
2596     // when we choose to not do it.
2597     if (fracLatencyNorm < 200) {
2598       // Success
2599       Telemetry::AccumulateCategorical(
2600           LABELS_CONTENT_FRAME_TIME_REASON::OnTime);
2601     } else {
2602       if (aCompositeId == VsyncId()) {
2603         // aCompositeId is 0, possibly something got trigged from
2604         // outside vsync?
2605         Telemetry::AccumulateCategorical(
2606             LABELS_CONTENT_FRAME_TIME_REASON::NoVsyncNoId);
2607       } else if (aTxnId >= aCompositeId) {
2608         // Vsync ids are nonsensical, maybe we're trying to catch up?
2609         Telemetry::AccumulateCategorical(
2610             LABELS_CONTENT_FRAME_TIME_REASON::NoVsync);
2611       } else if (aCompositeId - aTxnId > 1) {
2612         // Composite started late (and maybe took too long as well)
2613         if (aFullPaintTime >= TimeDuration::FromMilliseconds(20)) {
2614           Telemetry::AccumulateCategorical(
2615               LABELS_CONTENT_FRAME_TIME_REASON::MissedCompositeLong);
2616         } else if (aFullPaintTime >= TimeDuration::FromMilliseconds(10)) {
2617           Telemetry::AccumulateCategorical(
2618               LABELS_CONTENT_FRAME_TIME_REASON::MissedCompositeMid);
2619         } else if (aFullPaintTime >= TimeDuration::FromMilliseconds(5)) {
2620           Telemetry::AccumulateCategorical(
2621               LABELS_CONTENT_FRAME_TIME_REASON::MissedCompositeLow);
2622         } else {
2623           Telemetry::AccumulateCategorical(
2624               LABELS_CONTENT_FRAME_TIME_REASON::MissedComposite);
2625         }
2626       } else {
2627         // Composite started on time, but must have taken too long.
2628         Telemetry::AccumulateCategorical(
2629             LABELS_CONTENT_FRAME_TIME_REASON::SlowComposite);
2630       }
2631     }
2632 
2633     if (aRecordUploadStats) {
2634       if (aStats) {
2635         latencyMs -= (double(aStats->resource_upload_time) / 1000000.0);
2636         latencyNorm = latencyMs / aVsyncRate.ToMilliseconds();
2637         fracLatencyNorm = lround(latencyNorm * 100.0);
2638       }
2639       Telemetry::Accumulate(
2640           Telemetry::CONTENT_FRAME_TIME_WITHOUT_RESOURCE_UPLOAD,
2641           fracLatencyNorm);
2642 
2643       if (aStats) {
2644         latencyMs -= (double(aStats->gpu_cache_upload_time) / 1000000.0);
2645         latencyNorm = latencyMs / aVsyncRate.ToMilliseconds();
2646         fracLatencyNorm = lround(latencyNorm * 100.0);
2647       }
2648       Telemetry::Accumulate(Telemetry::CONTENT_FRAME_TIME_WITHOUT_UPLOAD,
2649                             fracLatencyNorm);
2650     }
2651     return result;
2652   }
2653 
2654   return 0;
2655 }
2656 
RecvBeginRecording(const TimeStamp & aRecordingStart,BeginRecordingResolver && aResolve)2657 mozilla::ipc::IPCResult CompositorBridgeParent::RecvBeginRecording(
2658     const TimeStamp& aRecordingStart, BeginRecordingResolver&& aResolve) {
2659   if (mHaveCompositionRecorder) {
2660     aResolve(false);
2661     return IPC_OK();
2662   }
2663 
2664   if (mLayerManager) {
2665     mLayerManager->SetCompositionRecorder(
2666         MakeUnique<CompositionRecorder>(aRecordingStart));
2667   } else if (mWrBridge) {
2668     mWrBridge->BeginRecording(aRecordingStart);
2669   }
2670 
2671   mHaveCompositionRecorder = true;
2672   aResolve(true);
2673 
2674   return IPC_OK();
2675 }
2676 
RecvEndRecordingToDisk(EndRecordingToDiskResolver && aResolve)2677 mozilla::ipc::IPCResult CompositorBridgeParent::RecvEndRecordingToDisk(
2678     EndRecordingToDiskResolver&& aResolve) {
2679   if (!mHaveCompositionRecorder) {
2680     aResolve(false);
2681     return IPC_OK();
2682   }
2683 
2684   if (mLayerManager) {
2685     mLayerManager->WriteCollectedFrames();
2686     aResolve(true);
2687   } else if (mWrBridge) {
2688     mWrBridge->WriteCollectedFrames()->Then(
2689         NS_GetCurrentThread(), __func__,
2690         [resolve{aResolve}](const bool success) { resolve(success); },
2691         [resolve{aResolve}]() { resolve(false); });
2692   } else {
2693     aResolve(false);
2694   }
2695 
2696   mHaveCompositionRecorder = false;
2697 
2698   return IPC_OK();
2699 }
2700 
RecvEndRecordingToMemory(EndRecordingToMemoryResolver && aResolve)2701 mozilla::ipc::IPCResult CompositorBridgeParent::RecvEndRecordingToMemory(
2702     EndRecordingToMemoryResolver&& aResolve) {
2703   if (!mHaveCompositionRecorder) {
2704     aResolve(Nothing());
2705     return IPC_OK();
2706   }
2707 
2708   if (mLayerManager) {
2709     Maybe<CollectedFrames> frames = mLayerManager->GetCollectedFrames();
2710     if (frames) {
2711       aResolve(WrapCollectedFrames(std::move(*frames)));
2712     } else {
2713       aResolve(Nothing());
2714     }
2715   } else if (mWrBridge) {
2716     RefPtr<CompositorBridgeParent> self = this;
2717     mWrBridge->GetCollectedFrames()->Then(
2718         NS_GetCurrentThread(), __func__,
2719         [self, resolve{aResolve}](CollectedFrames&& frames) {
2720           resolve(self->WrapCollectedFrames(std::move(frames)));
2721         },
2722         [resolve{aResolve}]() { resolve(Nothing()); });
2723   }
2724 
2725   mHaveCompositionRecorder = false;
2726 
2727   return IPC_OK();
2728 }
2729 
WrapCollectedFrames(CollectedFrames && aFrames)2730 Maybe<CollectedFramesParams> CompositorBridgeParent::WrapCollectedFrames(
2731     CollectedFrames&& aFrames) {
2732   CollectedFramesParams ipcFrames;
2733   ipcFrames.recordingStart() = aFrames.mRecordingStart;
2734 
2735   size_t totalLength = 0;
2736   for (const CollectedFrame& frame : aFrames.mFrames) {
2737     totalLength += frame.mDataUri.Length();
2738   }
2739 
2740   Shmem shmem;
2741   if (!AllocShmem(totalLength, SharedMemory::TYPE_BASIC, &shmem)) {
2742     return Nothing();
2743   }
2744 
2745   {
2746     char* raw = shmem.get<char>();
2747     for (CollectedFrame& frame : aFrames.mFrames) {
2748       size_t length = frame.mDataUri.Length();
2749 
2750       PodCopy(raw, frame.mDataUri.get(), length);
2751       raw += length;
2752 
2753       ipcFrames.frames().EmplaceBack(frame.mTimeOffset, length);
2754     }
2755   }
2756   ipcFrames.buffer() = std::move(shmem);
2757 
2758   return Some(std::move(ipcFrames));
2759 }
2760 
2761 }  // namespace layers
2762 }  // namespace mozilla
2763