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 "base/process.h"             // for ProcessId
16 #include "gfxContext.h"               // for gfxContext
17 #include "gfxPlatform.h"              // for gfxPlatform
18 #include "TreeTraversal.h"            // for ForEachNode
19 #ifdef MOZ_WIDGET_GTK
20 #  include "gfxPlatformGtk.h"  // for gfxPlatform
21 #endif
22 #include "mozilla/AutoRestore.h"      // for AutoRestore
23 #include "mozilla/ClearOnShutdown.h"  // for ClearOnShutdown
24 #include "mozilla/DebugOnly.h"        // for DebugOnly
25 #include "mozilla/StaticPrefs_gfx.h"
26 #include "mozilla/StaticPrefs_layers.h"
27 #include "mozilla/StaticPrefs_layout.h"
28 #include "mozilla/dom/BrowserParent.h"
29 #include "mozilla/gfx/2D.h"       // for DrawTarget
30 #include "mozilla/gfx/Point.h"    // for IntSize
31 #include "mozilla/gfx/Rect.h"     // for IntSize
32 #include "mozilla/gfx/gfxVars.h"  // for gfxVars
33 #include "mozilla/gfx/GPUParent.h"
34 #include "mozilla/layers/APZCTreeManagerParent.h"  // for APZCTreeManagerParent
35 #include "mozilla/layers/APZSampler.h"             // for APZSampler
36 #include "mozilla/layers/APZThreadUtils.h"         // for APZThreadUtils
37 #include "mozilla/layers/APZUpdater.h"             // for APZUpdater
38 #include "mozilla/layers/CompositionRecorder.h"    // for CompositionRecorder
39 #include "mozilla/layers/Compositor.h"             // for Compositor
40 #include "mozilla/layers/CompositorAnimationStorage.h"  // for CompositorAnimationStorage
41 #include "mozilla/layers/CompositorManagerParent.h"  // for CompositorManagerParent
42 #include "mozilla/layers/CompositorOGL.h"            // for CompositorOGL
43 #include "mozilla/layers/CompositorThread.h"
44 #include "mozilla/layers/CompositorTypes.h"
45 #include "mozilla/layers/CompositorVsyncScheduler.h"
46 #include "mozilla/layers/ContentCompositorBridgeParent.h"
47 #include "mozilla/layers/FrameUniformityData.h"
48 #include "mozilla/layers/GeckoContentController.h"
49 #include "mozilla/layers/ImageBridgeParent.h"
50 #include "mozilla/layers/LayerTreeOwnerTracker.h"
51 #include "mozilla/layers/LayersTypes.h"
52 #include "mozilla/layers/OMTASampler.h"
53 #include "mozilla/layers/RemoteContentController.h"
54 #include "mozilla/layers/UiCompositorControllerParent.h"
55 #include "mozilla/layers/WebRenderBridgeParent.h"
56 #include "mozilla/layers/AsyncImagePipelineManager.h"
57 #include "mozilla/webrender/WebRenderAPI.h"
58 #include "mozilla/webrender/RenderThread.h"
59 #include "mozilla/media/MediaSystemResourceService.h"  // for MediaSystemResourceService
60 #include "mozilla/mozalloc.h"                          // for operator new, etc
61 #include "mozilla/PerfStats.h"
62 #include "mozilla/PodOperations.h"
63 #include "mozilla/ProfilerLabels.h"
64 #include "mozilla/ProfilerMarkers.h"
65 #include "mozilla/Telemetry.h"
66 #include "nsCOMPtr.h"         // for already_AddRefed
67 #include "nsDebug.h"          // for NS_ASSERTION, etc
68 #include "nsISupportsImpl.h"  // for MOZ_COUNT_CTOR, etc
69 #include "nsIWidget.h"        // for nsIWidget
70 #include "nsTArray.h"         // for nsTArray
71 #include "nsThreadUtils.h"    // for NS_IsMainThread
72 #ifdef XP_WIN
73 #  include "mozilla/layers/CompositorD3D11.h"
74 #  include "mozilla/widget/WinCompositorWidget.h"
75 #  include "mozilla/WindowsVersion.h"
76 #endif
77 #include "mozilla/ipc/ProtocolTypes.h"
78 #include "mozilla/Unused.h"
79 #include "mozilla/Hal.h"
80 #include "mozilla/HalTypes.h"
81 #include "mozilla/StaticPtr.h"
82 #include "mozilla/Telemetry.h"
83 #include "mozilla/VsyncDispatcher.h"
84 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
85 #  include "VsyncSource.h"
86 #endif
87 #include "mozilla/widget/CompositorWidget.h"
88 #ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING
89 #  include "mozilla/widget/CompositorWidgetParent.h"
90 #endif
91 #ifdef XP_WIN
92 #  include "mozilla/gfx/DeviceManagerDx.h"
93 #endif
94 
95 namespace mozilla {
96 
97 namespace layers {
98 
99 using namespace mozilla::ipc;
100 using namespace mozilla::gfx;
101 
102 using base::ProcessId;
103 
104 using mozilla::Telemetry::LABELS_CONTENT_FRAME_TIME_REASON;
105 
106 /// Equivalent to asserting CompositorThreadHolder::IsInCompositorThread with
107 /// the addition that it doesn't assert if the compositor thread holder is
108 /// already gone during late shutdown.
AssertIsInCompositorThread()109 static void AssertIsInCompositorThread() {
110   MOZ_RELEASE_ASSERT(!CompositorThread() ||
111                      CompositorThreadHolder::IsInCompositorThread());
112 }
113 
CompositorBridgeParentBase(CompositorManagerParent * aManager)114 CompositorBridgeParentBase::CompositorBridgeParentBase(
115     CompositorManagerParent* aManager)
116     : mCanSend(true), mCompositorManager(aManager) {}
117 
118 CompositorBridgeParentBase::~CompositorBridgeParentBase() = default;
119 
GetChildProcessId()120 ProcessId CompositorBridgeParentBase::GetChildProcessId() { return OtherPid(); }
121 
NotifyNotUsed(PTextureParent * aTexture,uint64_t aTransactionId)122 void CompositorBridgeParentBase::NotifyNotUsed(PTextureParent* aTexture,
123                                                uint64_t aTransactionId) {
124   RefPtr<TextureHost> texture = TextureHost::AsTextureHost(aTexture);
125   if (!texture) {
126     return;
127   }
128 
129 #ifdef MOZ_WIDGET_ANDROID
130   if (texture->GetAndroidHardwareBuffer()) {
131     MOZ_ASSERT(texture->GetFlags() & TextureFlags::RECYCLE);
132     ImageBridgeParent::NotifyBufferNotUsedOfCompositorBridge(
133         GetChildProcessId(), texture, aTransactionId);
134   }
135 #endif
136 
137   if (!(texture->GetFlags() & TextureFlags::RECYCLE) &&
138       !(texture->GetFlags() & TextureFlags::WAIT_HOST_USAGE_END)) {
139     return;
140   }
141 
142   uint64_t textureId = TextureHost::GetTextureSerial(aTexture);
143   mPendingAsyncMessage.push_back(OpNotifyNotUsed(textureId, aTransactionId));
144 }
145 
SendAsyncMessage(const nsTArray<AsyncParentMessageData> & aMessage)146 void CompositorBridgeParentBase::SendAsyncMessage(
147     const nsTArray<AsyncParentMessageData>& aMessage) {
148   Unused << SendParentAsyncMessages(aMessage);
149 }
150 
AllocShmem(size_t aSize,ipc::SharedMemory::SharedMemoryType aType,ipc::Shmem * aShmem)151 bool CompositorBridgeParentBase::AllocShmem(
152     size_t aSize, ipc::SharedMemory::SharedMemoryType aType,
153     ipc::Shmem* aShmem) {
154   return PCompositorBridgeParent::AllocShmem(aSize, aType, aShmem);
155 }
156 
AllocUnsafeShmem(size_t aSize,ipc::SharedMemory::SharedMemoryType aType,ipc::Shmem * aShmem)157 bool CompositorBridgeParentBase::AllocUnsafeShmem(
158     size_t aSize, ipc::SharedMemory::SharedMemoryType aType,
159     ipc::Shmem* aShmem) {
160   return PCompositorBridgeParent::AllocUnsafeShmem(aSize, aType, aShmem);
161 }
162 
DeallocShmem(ipc::Shmem & aShmem)163 bool CompositorBridgeParentBase::DeallocShmem(ipc::Shmem& aShmem) {
164   return PCompositorBridgeParent::DeallocShmem(aShmem);
165 }
166 
LayerTreeState()167 CompositorBridgeParent::LayerTreeState::LayerTreeState()
168     : mApzcTreeManagerParent(nullptr),
169       mParent(nullptr),
170       mContentCompositorBridgeParent(nullptr) {}
171 
~LayerTreeState()172 CompositorBridgeParent::LayerTreeState::~LayerTreeState() {
173   if (mController) {
174     mController->Destroy();
175   }
176 }
177 
178 typedef std::map<LayersId, CompositorBridgeParent::LayerTreeState> LayerTreeMap;
179 LayerTreeMap sIndirectLayerTrees;
180 StaticAutoPtr<mozilla::Monitor> sIndirectLayerTreesLock;
181 
EnsureLayerTreeMapReady()182 static void EnsureLayerTreeMapReady() {
183   MOZ_ASSERT(NS_IsMainThread());
184   if (!sIndirectLayerTreesLock) {
185     sIndirectLayerTreesLock = new Monitor("IndirectLayerTree");
186     mozilla::ClearOnShutdown(&sIndirectLayerTreesLock);
187   }
188 }
189 
190 template <typename Lambda>
ForEachIndirectLayerTree(const Lambda & aCallback)191 inline void CompositorBridgeParent::ForEachIndirectLayerTree(
192     const Lambda& aCallback) {
193   sIndirectLayerTreesLock->AssertCurrentThreadOwns();
194   for (auto it = sIndirectLayerTrees.begin(); it != sIndirectLayerTrees.end();
195        it++) {
196     LayerTreeState* state = &it->second;
197     if (state->mParent == this) {
198       aCallback(state, it->first);
199     }
200   }
201 }
202 
203 /*static*/ template <typename Lambda>
ForEachWebRenderBridgeParent(const Lambda & aCallback)204 inline void CompositorBridgeParent::ForEachWebRenderBridgeParent(
205     const Lambda& aCallback) {
206   sIndirectLayerTreesLock->AssertCurrentThreadOwns();
207   for (auto& it : sIndirectLayerTrees) {
208     LayerTreeState* state = &it.second;
209     if (state->mWrBridge) {
210       aCallback(state->mWrBridge);
211     }
212   }
213 }
214 
215 /**
216  * A global map referencing each compositor by ID.
217  *
218  * This map is used by the ImageBridge protocol to trigger
219  * compositions without having to keep references to the
220  * compositor
221  */
222 typedef std::map<uint64_t, CompositorBridgeParent*> CompositorMap;
223 static StaticAutoPtr<CompositorMap> sCompositorMap;
224 
Setup()225 void CompositorBridgeParent::Setup() {
226   EnsureLayerTreeMapReady();
227 
228   MOZ_ASSERT(!sCompositorMap);
229   sCompositorMap = new CompositorMap;
230 }
231 
FinishShutdown()232 void CompositorBridgeParent::FinishShutdown() {
233   MOZ_ASSERT(NS_IsMainThread());
234 
235   if (sCompositorMap) {
236     MOZ_ASSERT(sCompositorMap->empty());
237     sCompositorMap = nullptr;
238   }
239 
240   // TODO: this should be empty by now...
241   MonitorAutoLock lock(*sIndirectLayerTreesLock);
242   sIndirectLayerTrees.clear();
243 }
244 
245 #ifdef COMPOSITOR_PERFORMANCE_WARNING
CalculateCompositionFrameRate()246 static int32_t CalculateCompositionFrameRate() {
247   // Used when layout.frame_rate is -1. Needs to be kept in sync with
248   // DEFAULT_FRAME_RATE in nsRefreshDriver.cpp.
249   // TODO: This should actually return the vsync rate.
250   const int32_t defaultFrameRate = 60;
251   int32_t compositionFrameRatePref =
252       StaticPrefs::layers_offmainthreadcomposition_frame_rate();
253   if (compositionFrameRatePref < 0) {
254     // Use the same frame rate for composition as for layout.
255     int32_t layoutFrameRatePref = StaticPrefs::layout_frame_rate();
256     if (layoutFrameRatePref < 0) {
257       // TODO: The main thread frame scheduling code consults the actual
258       // monitor refresh rate in this case. We should do the same.
259       return defaultFrameRate;
260     }
261     return layoutFrameRatePref;
262   }
263   return compositionFrameRatePref;
264 }
265 #endif
266 
CompositorBridgeParent(CompositorManagerParent * aManager,CSSToLayoutDeviceScale aScale,const TimeDuration & aVsyncRate,const CompositorOptions & aOptions,bool aUseExternalSurfaceSize,const gfx::IntSize & aSurfaceSize)267 CompositorBridgeParent::CompositorBridgeParent(
268     CompositorManagerParent* aManager, CSSToLayoutDeviceScale aScale,
269     const TimeDuration& aVsyncRate, const CompositorOptions& aOptions,
270     bool aUseExternalSurfaceSize, const gfx::IntSize& aSurfaceSize)
271     : CompositorBridgeParentBase(aManager),
272       mWidget(nullptr),
273       mScale(aScale),
274       mVsyncRate(aVsyncRate),
275       mPaused(false),
276       mHaveCompositionRecorder(false),
277       mIsForcedFirstPaint(false),
278       mUseExternalSurfaceSize(aUseExternalSurfaceSize),
279       mEGLSurfaceSize(aSurfaceSize),
280       mOptions(aOptions),
281       mPauseCompositionMonitor("PauseCompositionMonitor"),
282       mResumeCompositionMonitor("ResumeCompositionMonitor"),
283       mCompositorBridgeID(0),
284       mRootLayerTreeID{0},
285       mOverrideComposeReadiness(false),
286       mForceCompositionTask(nullptr),
287       mCompositorScheduler(nullptr),
288       mAnimationStorage(nullptr),
289       mPaintTime(TimeDuration::Forever()) {}
290 
InitSameProcess(widget::CompositorWidget * aWidget,const LayersId & aLayerTreeId)291 void CompositorBridgeParent::InitSameProcess(widget::CompositorWidget* aWidget,
292                                              const LayersId& aLayerTreeId) {
293   MOZ_ASSERT(XRE_IsParentProcess());
294   MOZ_ASSERT(NS_IsMainThread());
295 
296   mWidget = aWidget;
297   mRootLayerTreeID = aLayerTreeId;
298 
299   Initialize();
300 }
301 
RecvInitialize(const LayersId & aRootLayerTreeId)302 mozilla::ipc::IPCResult CompositorBridgeParent::RecvInitialize(
303     const LayersId& aRootLayerTreeId) {
304   MOZ_ASSERT(XRE_IsGPUProcess());
305 
306   mRootLayerTreeID = aRootLayerTreeId;
307 #ifdef XP_WIN
308   if (XRE_IsGPUProcess()) {
309     mWidget->AsWindows()->SetRootLayerTreeID(mRootLayerTreeID);
310   }
311 #endif
312 
313   Initialize();
314   return IPC_OK();
315 }
316 
Initialize()317 void CompositorBridgeParent::Initialize() {
318   MOZ_ASSERT(CompositorThread(),
319              "The compositor thread must be Initialized before instanciating a "
320              "CompositorBridgeParent.");
321 
322   if (mOptions.UseAPZ()) {
323     MOZ_ASSERT(!mApzcTreeManager);
324     MOZ_ASSERT(!mApzSampler);
325     MOZ_ASSERT(!mApzUpdater);
326     mApzcTreeManager = new APZCTreeManager(mRootLayerTreeID);
327     mApzSampler = new APZSampler(mApzcTreeManager, true);
328     mApzUpdater = new APZUpdater(mApzcTreeManager, true);
329   }
330 
331   CompositorAnimationStorage* animationStorage = GetAnimationStorage();
332   mOMTASampler = new OMTASampler(animationStorage, mRootLayerTreeID);
333 
334   mPaused = mOptions.InitiallyPaused();
335 
336   mCompositorBridgeID = 0;
337   // FIXME: This holds on the the fact that right now the only thing that
338   // can destroy this instance is initialized on the compositor thread after
339   // this task has been processed.
340   MOZ_ASSERT(CompositorThread());
341   CompositorThread()->Dispatch(NewRunnableFunction(
342       "AddCompositorRunnable", &AddCompositor, this, &mCompositorBridgeID));
343 
344   {  // scope lock
345     MonitorAutoLock lock(*sIndirectLayerTreesLock);
346     sIndirectLayerTrees[mRootLayerTreeID].mParent = this;
347   }
348 }
349 
RootLayerTreeId()350 LayersId CompositorBridgeParent::RootLayerTreeId() {
351   MOZ_ASSERT(mRootLayerTreeID.IsValid());
352   return mRootLayerTreeID;
353 }
354 
~CompositorBridgeParent()355 CompositorBridgeParent::~CompositorBridgeParent() {
356   MOZ_DIAGNOSTIC_ASSERT(
357       !mCanSend,
358       "ActorDestroy or RecvWillClose should have been called first.");
359   MOZ_DIAGNOSTIC_ASSERT(mRefCnt == 0,
360                         "ActorDealloc should have been called first.");
361   nsTArray<PTextureParent*> textures;
362   ManagedPTextureParent(textures);
363   // We expect all textures to be destroyed by now.
364   MOZ_DIAGNOSTIC_ASSERT(textures.Length() == 0);
365   for (unsigned int i = 0; i < textures.Length(); ++i) {
366     RefPtr<TextureHost> tex = TextureHost::AsTextureHost(textures[i]);
367     tex->DeallocateDeviceData();
368   }
369   // Check if WebRender/Compositor was shutdown.
370   if (mWrBridge || mCompositor) {
371     gfxCriticalNote << "CompositorBridgeParent destroyed without shutdown";
372   }
373 }
374 
ForceIsFirstPaint()375 void CompositorBridgeParent::ForceIsFirstPaint() {
376   if (mWrBridge) {
377     mIsForcedFirstPaint = true;
378   }
379 }
380 
StopAndClearResources()381 void CompositorBridgeParent::StopAndClearResources() {
382   if (mForceCompositionTask) {
383     mForceCompositionTask->Cancel();
384     mForceCompositionTask = nullptr;
385   }
386 
387   mPaused = true;
388 
389   // We need to clear the APZ tree before we destroy the WebRender API below,
390   // because in the case of async scene building that will shut down the updater
391   // thread and we need to run the task before that happens.
392   MOZ_ASSERT((mApzSampler != nullptr) == (mApzcTreeManager != nullptr));
393   MOZ_ASSERT((mApzUpdater != nullptr) == (mApzcTreeManager != nullptr));
394   if (mApzUpdater) {
395     mApzSampler->Destroy();
396     mApzSampler = nullptr;
397     mApzUpdater->ClearTree(mRootLayerTreeID);
398     mApzUpdater = nullptr;
399     mApzcTreeManager = nullptr;
400   }
401 
402   if (mWrBridge) {
403     // Ensure we are not holding the sIndirectLayerTreesLock when destroying
404     // the WebRenderBridgeParent instances because it may block on WR.
405     std::vector<RefPtr<WebRenderBridgeParent>> indirectBridgeParents;
406     {  // scope lock
407       MonitorAutoLock lock(*sIndirectLayerTreesLock);
408       ForEachIndirectLayerTree([&](LayerTreeState* lts, LayersId) -> void {
409         if (lts->mWrBridge) {
410           indirectBridgeParents.emplace_back(lts->mWrBridge.forget());
411         }
412         lts->mParent = nullptr;
413       });
414     }
415     for (const RefPtr<WebRenderBridgeParent>& bridge : indirectBridgeParents) {
416       bridge->Destroy();
417     }
418     indirectBridgeParents.clear();
419 
420     RefPtr<wr::WebRenderAPI> api = mWrBridge->GetWebRenderAPI();
421     // Ensure we are not holding the sIndirectLayerTreesLock here because we
422     // are going to block on WR threads in order to shut it down properly.
423     mWrBridge->Destroy();
424     mWrBridge = nullptr;
425 
426     if (api) {
427       // Make extra sure we are done cleaning WebRender up before continuing.
428       // After that we wont have a way to talk to a lot of the webrender parts.
429       api->FlushSceneBuilder();
430       api = nullptr;
431     }
432 
433     if (mAsyncImageManager) {
434       mAsyncImageManager->Destroy();
435       // WebRenderAPI should be already destructed
436       mAsyncImageManager = nullptr;
437     }
438   }
439 
440   if (mCompositor) {
441     mCompositor->Destroy();
442     mCompositor = nullptr;
443   }
444 
445   // This must be destroyed now since it accesses the widget.
446   if (mCompositorScheduler) {
447     mCompositorScheduler->Destroy();
448     mCompositorScheduler = nullptr;
449   }
450 
451   if (mOMTASampler) {
452     mOMTASampler->Destroy();
453     mOMTASampler = nullptr;
454   }
455 
456   // After this point, it is no longer legal to access the widget.
457   mWidget = nullptr;
458 
459   // Clear mAnimationStorage here to ensure that the compositor thread
460   // still exists when we destroy it.
461   mAnimationStorage = nullptr;
462 }
463 
RecvWillClose()464 mozilla::ipc::IPCResult CompositorBridgeParent::RecvWillClose() {
465   StopAndClearResources();
466   // Once we get the WillClose message, the client side is going to go away
467   // soon and we can't be guaranteed that sending messages will work.
468   mCanSend = false;
469   return IPC_OK();
470 }
471 
DeferredDestroy()472 void CompositorBridgeParent::DeferredDestroy() {
473   MOZ_ASSERT(!NS_IsMainThread());
474   mSelfRef = nullptr;
475 }
476 
RecvPause()477 mozilla::ipc::IPCResult CompositorBridgeParent::RecvPause() {
478   PauseComposition();
479   return IPC_OK();
480 }
481 
RecvRequestFxrOutput()482 mozilla::ipc::IPCResult CompositorBridgeParent::RecvRequestFxrOutput() {
483 #ifdef XP_WIN
484   // Continue forwarding the request to the Widget + SwapChain
485   mWidget->AsWindows()->RequestFxrOutput();
486 #endif
487 
488   return IPC_OK();
489 }
490 
RecvResume()491 mozilla::ipc::IPCResult CompositorBridgeParent::RecvResume() {
492   ResumeComposition();
493   return IPC_OK();
494 }
495 
RecvResumeAsync()496 mozilla::ipc::IPCResult CompositorBridgeParent::RecvResumeAsync() {
497   ResumeComposition();
498   return IPC_OK();
499 }
500 
501 mozilla::ipc::IPCResult
RecvWaitOnTransactionProcessed()502 CompositorBridgeParent::RecvWaitOnTransactionProcessed() {
503   return IPC_OK();
504 }
505 
RecvFlushRendering(const wr::RenderReasons & aReasons)506 mozilla::ipc::IPCResult CompositorBridgeParent::RecvFlushRendering(
507     const wr::RenderReasons& aReasons) {
508   if (mWrBridge) {
509     mWrBridge->FlushRendering(aReasons);
510     return IPC_OK();
511   }
512 
513   if (mCompositorScheduler->NeedsComposite()) {
514     CancelCurrentCompositeTask();
515     ForceComposeToTarget(aReasons, nullptr, nullptr);
516   }
517   return IPC_OK();
518 }
519 
RecvNotifyMemoryPressure()520 mozilla::ipc::IPCResult CompositorBridgeParent::RecvNotifyMemoryPressure() {
521   NotifyMemoryPressure();
522   return IPC_OK();
523 }
524 
RecvFlushRenderingAsync(const wr::RenderReasons & aReasons)525 mozilla::ipc::IPCResult CompositorBridgeParent::RecvFlushRenderingAsync(
526     const wr::RenderReasons& aReasons) {
527   if (mWrBridge) {
528     mWrBridge->FlushRendering(aReasons, false);
529     return IPC_OK();
530   }
531 
532   return RecvFlushRendering(aReasons);
533 }
534 
RecvForcePresent(const wr::RenderReasons & aReasons)535 mozilla::ipc::IPCResult CompositorBridgeParent::RecvForcePresent(
536     const wr::RenderReasons& aReasons) {
537   if (mWrBridge) {
538     mWrBridge->ScheduleForcedGenerateFrame(aReasons);
539   }
540   return IPC_OK();
541 }
542 
Invalidate()543 void CompositorBridgeParent::Invalidate() {}
544 
RecvStartFrameTimeRecording(const int32_t & aBufferSize,uint32_t * aOutStartIndex)545 mozilla::ipc::IPCResult CompositorBridgeParent::RecvStartFrameTimeRecording(
546     const int32_t& aBufferSize, uint32_t* aOutStartIndex) {
547   if (mWrBridge) {
548     *aOutStartIndex = mWrBridge->StartFrameTimeRecording(aBufferSize);
549   } else {
550     *aOutStartIndex = 0;
551   }
552   return IPC_OK();
553 }
554 
RecvStopFrameTimeRecording(const uint32_t & aStartIndex,nsTArray<float> * intervals)555 mozilla::ipc::IPCResult CompositorBridgeParent::RecvStopFrameTimeRecording(
556     const uint32_t& aStartIndex, nsTArray<float>* intervals) {
557   if (mWrBridge) {
558     mWrBridge->StopFrameTimeRecording(aStartIndex, *intervals);
559   }
560   return IPC_OK();
561 }
562 
ActorDestroy(ActorDestroyReason why)563 void CompositorBridgeParent::ActorDestroy(ActorDestroyReason why) {
564   mCanSend = false;
565 
566   StopAndClearResources();
567 
568   RemoveCompositor(mCompositorBridgeID);
569 
570   {  // scope lock
571     MonitorAutoLock lock(*sIndirectLayerTreesLock);
572     sIndirectLayerTrees.erase(mRootLayerTreeID);
573   }
574 
575   // There are chances that the ref count reaches zero on the main thread
576   // shortly after this function returns while some ipdl code still needs to run
577   // on this thread. We must keep the compositor parent alive untill the code
578   // handling message reception is finished on this thread.
579   mSelfRef = this;
580   NS_GetCurrentThread()->Dispatch(
581       NewRunnableMethod("layers::CompositorBridgeParent::DeferredDestroy", this,
582                         &CompositorBridgeParent::DeferredDestroy));
583 }
584 
ScheduleRenderOnCompositorThread(wr::RenderReasons aReasons)585 void CompositorBridgeParent::ScheduleRenderOnCompositorThread(
586     wr::RenderReasons aReasons) {
587   MOZ_ASSERT(CompositorThread());
588   CompositorThread()->Dispatch(NewRunnableMethod<wr::RenderReasons>(
589       "layers::CompositorBridgeParent::ScheduleComposition", this,
590       &CompositorBridgeParent::ScheduleComposition, aReasons));
591 }
592 
PauseComposition()593 void CompositorBridgeParent::PauseComposition() {
594   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread(),
595              "PauseComposition() can only be called on the compositor thread");
596 
597   MonitorAutoLock lock(mPauseCompositionMonitor);
598 
599   if (!mPaused) {
600     mPaused = true;
601 
602     TimeStamp now = TimeStamp::Now();
603     if (mCompositor) {
604       mCompositor->Pause();
605       DidComposite(VsyncId(), now, now);
606     } else if (mWrBridge) {
607       mWrBridge->Pause();
608       NotifyPipelineRendered(mWrBridge->PipelineId(),
609                              mWrBridge->GetCurrentEpoch(), VsyncId(), now, now,
610                              now);
611     }
612   }
613 
614   // if anyone's waiting to make sure that composition really got paused, tell
615   // them
616   lock.NotifyAll();
617 }
618 
ResumeComposition()619 void CompositorBridgeParent::ResumeComposition() {
620   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread(),
621              "ResumeComposition() can only be called on the compositor thread");
622 
623   MonitorAutoLock lock(mResumeCompositionMonitor);
624 
625   bool resumed = mWidget->OnResumeComposition();
626   resumed = resumed && mWrBridge->Resume();
627 
628   if (!resumed) {
629 #ifdef MOZ_WIDGET_ANDROID
630     // We can't get a surface. This could be because the activity changed
631     // between the time resume was scheduled and now.
632     __android_log_print(
633         ANDROID_LOG_INFO, "CompositorBridgeParent",
634         "Unable to renew compositor surface; remaining in paused state");
635 #endif
636     lock.NotifyAll();
637     return;
638   }
639 
640   mPaused = false;
641 
642   Invalidate();
643   mCompositorScheduler->ForceComposeToTarget(wr::RenderReasons::WIDGET, nullptr,
644                                              nullptr);
645 
646   // if anyone's waiting to make sure that composition really got resumed, tell
647   // them
648   lock.NotifyAll();
649 }
650 
ForceComposition(wr::RenderReasons aReasons)651 void CompositorBridgeParent::ForceComposition(wr::RenderReasons aReasons) {
652   // Cancel the orientation changed state to force composition
653   mForceCompositionTask = nullptr;
654   ScheduleRenderOnCompositorThread(aReasons);
655 }
656 
CancelCurrentCompositeTask()657 void CompositorBridgeParent::CancelCurrentCompositeTask() {
658   mCompositorScheduler->CancelCurrentCompositeTask();
659 }
660 
SetEGLSurfaceRect(int x,int y,int width,int height)661 void CompositorBridgeParent::SetEGLSurfaceRect(int x, int y, int width,
662                                                int height) {
663   NS_ASSERTION(mUseExternalSurfaceSize,
664                "Compositor created without UseExternalSurfaceSize provided");
665   mEGLSurfaceSize.SizeTo(width, height);
666   if (mCompositor) {
667     mCompositor->SetDestinationSurfaceSize(
668         gfx::IntSize(mEGLSurfaceSize.width, mEGLSurfaceSize.height));
669     if (mCompositor->AsCompositorOGL()) {
670       mCompositor->AsCompositorOGL()->SetSurfaceOrigin(ScreenIntPoint(x, y));
671     }
672   }
673 }
674 
ResumeCompositionAndResize(int x,int y,int width,int height)675 void CompositorBridgeParent::ResumeCompositionAndResize(int x, int y, int width,
676                                                         int height) {
677   SetEGLSurfaceRect(x, y, width, height);
678   ResumeComposition();
679 }
680 
ScheduleComposition(wr::RenderReasons aReasons)681 void CompositorBridgeParent::ScheduleComposition(wr::RenderReasons aReasons) {
682   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
683   if (mPaused) {
684     return;
685   }
686 
687   if (mWrBridge) {
688     mWrBridge->ScheduleGenerateFrame(aReasons);
689   } else {
690     mCompositorScheduler->ScheduleComposition(aReasons);
691   }
692 }
693 
ForceComposeToTarget(wr::RenderReasons aReasons,DrawTarget * aTarget,const gfx::IntRect * aRect)694 void CompositorBridgeParent::ForceComposeToTarget(wr::RenderReasons aReasons,
695                                                   DrawTarget* aTarget,
696                                                   const gfx::IntRect* aRect) {
697   AUTO_PROFILER_LABEL("CompositorBridgeParent::ForceComposeToTarget", GRAPHICS);
698 
699   AutoRestore<bool> override(mOverrideComposeReadiness);
700   mOverrideComposeReadiness = true;
701   mCompositorScheduler->ForceComposeToTarget(aReasons, aTarget, aRect);
702 }
703 
AllocPAPZCTreeManagerParent(const LayersId & aLayersId)704 PAPZCTreeManagerParent* CompositorBridgeParent::AllocPAPZCTreeManagerParent(
705     const LayersId& aLayersId) {
706   // This should only ever get called in the GPU process.
707   MOZ_ASSERT(XRE_IsGPUProcess());
708   // We should only ever get this if APZ is enabled in this compositor.
709   MOZ_ASSERT(mOptions.UseAPZ());
710   // The mApzcTreeManager and mApzUpdater should have been created via
711   // RecvInitialize()
712   MOZ_ASSERT(mApzcTreeManager);
713   MOZ_ASSERT(mApzUpdater);
714   // The main process should pass in 0 because we assume mRootLayerTreeID
715   MOZ_ASSERT(!aLayersId.IsValid());
716 
717   MonitorAutoLock lock(*sIndirectLayerTreesLock);
718   CompositorBridgeParent::LayerTreeState& state =
719       sIndirectLayerTrees[mRootLayerTreeID];
720   MOZ_ASSERT(state.mParent.get() == this);
721   MOZ_ASSERT(!state.mApzcTreeManagerParent);
722   state.mApzcTreeManagerParent = new APZCTreeManagerParent(
723       mRootLayerTreeID, mApzcTreeManager, mApzUpdater);
724 
725   return state.mApzcTreeManagerParent;
726 }
727 
DeallocPAPZCTreeManagerParent(PAPZCTreeManagerParent * aActor)728 bool CompositorBridgeParent::DeallocPAPZCTreeManagerParent(
729     PAPZCTreeManagerParent* aActor) {
730   delete aActor;
731   return true;
732 }
733 
AllocateAPZCTreeManagerParent(const MonitorAutoLock & aProofOfLayerTreeStateLock,const LayersId & aLayersId,LayerTreeState & aState)734 void CompositorBridgeParent::AllocateAPZCTreeManagerParent(
735     const MonitorAutoLock& aProofOfLayerTreeStateLock,
736     const LayersId& aLayersId, LayerTreeState& aState) {
737   MOZ_ASSERT(aState.mParent == this);
738   MOZ_ASSERT(mApzcTreeManager);
739   MOZ_ASSERT(mApzUpdater);
740   MOZ_ASSERT(!aState.mApzcTreeManagerParent);
741   aState.mApzcTreeManagerParent =
742       new APZCTreeManagerParent(aLayersId, mApzcTreeManager, mApzUpdater);
743 }
744 
AllocPAPZParent(const LayersId & aLayersId)745 PAPZParent* CompositorBridgeParent::AllocPAPZParent(const LayersId& aLayersId) {
746   // This is the CompositorBridgeParent for a window, and so should only be
747   // creating a PAPZ instance if it lives in the GPU process. Instances that
748   // live in the UI process should going through SetControllerForLayerTree.
749   MOZ_RELEASE_ASSERT(XRE_IsGPUProcess());
750 
751   // We should only ever get this if APZ is enabled on this compositor.
752   MOZ_RELEASE_ASSERT(mOptions.UseAPZ());
753 
754   // The main process should pass in 0 because we assume mRootLayerTreeID
755   MOZ_RELEASE_ASSERT(!aLayersId.IsValid());
756 
757   RemoteContentController* controller = new RemoteContentController();
758 
759   // Increment the controller's refcount before we return it. This will keep the
760   // controller alive until it is released by IPDL in DeallocPAPZParent.
761   controller->AddRef();
762 
763   MonitorAutoLock lock(*sIndirectLayerTreesLock);
764   CompositorBridgeParent::LayerTreeState& state =
765       sIndirectLayerTrees[mRootLayerTreeID];
766   MOZ_RELEASE_ASSERT(!state.mController);
767   state.mController = controller;
768 
769   return controller;
770 }
771 
DeallocPAPZParent(PAPZParent * aActor)772 bool CompositorBridgeParent::DeallocPAPZParent(PAPZParent* aActor) {
773   RemoteContentController* controller =
774       static_cast<RemoteContentController*>(aActor);
775   controller->Release();
776   return true;
777 }
778 
GetAPZSampler() const779 RefPtr<APZSampler> CompositorBridgeParent::GetAPZSampler() const {
780   return mApzSampler;
781 }
782 
GetAPZUpdater() const783 RefPtr<APZUpdater> CompositorBridgeParent::GetAPZUpdater() const {
784   return mApzUpdater;
785 }
786 
GetOMTASampler() const787 RefPtr<OMTASampler> CompositorBridgeParent::GetOMTASampler() const {
788   return mOMTASampler;
789 }
790 
791 CompositorBridgeParent*
GetCompositorBridgeParentFromLayersId(const LayersId & aLayersId)792 CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(
793     const LayersId& aLayersId) {
794   MonitorAutoLock lock(*sIndirectLayerTreesLock);
795   return sIndirectLayerTrees[aLayersId].mParent;
796 }
797 
798 /*static*/
799 RefPtr<CompositorBridgeParent>
GetCompositorBridgeParentFromWindowId(const wr::WindowId & aWindowId)800 CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(
801     const wr::WindowId& aWindowId) {
802   MonitorAutoLock lock(*sIndirectLayerTreesLock);
803   for (auto it = sIndirectLayerTrees.begin(); it != sIndirectLayerTrees.end();
804        it++) {
805     LayerTreeState* state = &it->second;
806     if (!state->mWrBridge) {
807       continue;
808     }
809     // state->mWrBridge might be a root WebRenderBridgeParent or one of a
810     // content process, but in either case the state->mParent will be the same.
811     // So we don't need to distinguish between the two.
812     if (RefPtr<wr::WebRenderAPI> api = state->mWrBridge->GetWebRenderAPI()) {
813       if (api->GetId() == aWindowId) {
814         return state->mParent;
815       }
816     }
817   }
818   return nullptr;
819 }
820 
CanComposite()821 bool CompositorBridgeParent::CanComposite() { return false; }
822 
ScheduleRotationOnCompositorThread(const TargetConfig & aTargetConfig,bool aIsFirstPaint)823 void CompositorBridgeParent::ScheduleRotationOnCompositorThread(
824     const TargetConfig& aTargetConfig, bool aIsFirstPaint) {
825   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
826 }
827 
SetTestSampleTime(const LayersId & aId,const TimeStamp & aTime)828 bool CompositorBridgeParent::SetTestSampleTime(const LayersId& aId,
829                                                const TimeStamp& aTime) {
830   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
831 
832   if (aTime.IsNull()) {
833     return false;
834   }
835 
836   mTestTime = Some(aTime);
837   if (mApzcTreeManager) {
838     mApzcTreeManager->SetTestSampleTime(mTestTime);
839   }
840 
841   if (mWrBridge) {
842     mWrBridge->FlushRendering(wr::RenderReasons::TESTING);
843     return true;
844   }
845 
846   return true;
847 }
848 
LeaveTestMode(const LayersId & aId)849 void CompositorBridgeParent::LeaveTestMode(const LayersId& aId) {
850   mTestTime = Nothing();
851   if (mApzcTreeManager) {
852     mApzcTreeManager->SetTestSampleTime(mTestTime);
853   }
854 }
855 
GetAnimationStorage()856 CompositorAnimationStorage* CompositorBridgeParent::GetAnimationStorage() {
857   if (!mAnimationStorage) {
858     mAnimationStorage = new CompositorAnimationStorage(this);
859   }
860   return mAnimationStorage;
861 }
862 
NotifyJankedAnimations(const JankedAnimations & aJankedAnimations)863 void CompositorBridgeParent::NotifyJankedAnimations(
864     const JankedAnimations& aJankedAnimations) {
865   MOZ_ASSERT(!aJankedAnimations.empty());
866 
867   if (StaticPrefs::layout_animation_prerender_partial_jank()) {
868     return;
869   }
870 
871   for (const auto& entry : aJankedAnimations) {
872     const LayersId& layersId = entry.first;
873     const nsTArray<uint64_t>& animations = entry.second;
874     if (layersId == mRootLayerTreeID) {
875       if (mWrBridge) {
876         Unused << SendNotifyJankedAnimations(LayersId{0}, animations);
877       }
878       // It unlikely happens multiple processes have janked animations at same
879       // time, so it should be fine with enumerating sIndirectLayerTrees every
880       // time.
881     } else if (const LayerTreeState* state = GetIndirectShadowTree(layersId)) {
882       if (ContentCompositorBridgeParent* cpcp =
883               state->mContentCompositorBridgeParent) {
884         Unused << cpcp->SendNotifyJankedAnimations(layersId, animations);
885       }
886     }
887   }
888 }
889 
SetTestAsyncScrollOffset(const LayersId & aLayersId,const ScrollableLayerGuid::ViewID & aScrollId,const CSSPoint & aPoint)890 void CompositorBridgeParent::SetTestAsyncScrollOffset(
891     const LayersId& aLayersId, const ScrollableLayerGuid::ViewID& aScrollId,
892     const CSSPoint& aPoint) {
893   if (mApzUpdater) {
894     MOZ_ASSERT(aLayersId.IsValid());
895     mApzUpdater->SetTestAsyncScrollOffset(aLayersId, aScrollId, aPoint);
896   }
897 }
898 
SetTestAsyncZoom(const LayersId & aLayersId,const ScrollableLayerGuid::ViewID & aScrollId,const LayerToParentLayerScale & aZoom)899 void CompositorBridgeParent::SetTestAsyncZoom(
900     const LayersId& aLayersId, const ScrollableLayerGuid::ViewID& aScrollId,
901     const LayerToParentLayerScale& aZoom) {
902   if (mApzUpdater) {
903     MOZ_ASSERT(aLayersId.IsValid());
904     mApzUpdater->SetTestAsyncZoom(aLayersId, aScrollId, aZoom);
905   }
906 }
907 
FlushApzRepaints(const LayersId & aLayersId)908 void CompositorBridgeParent::FlushApzRepaints(const LayersId& aLayersId) {
909   MOZ_ASSERT(mApzUpdater);
910   MOZ_ASSERT(aLayersId.IsValid());
911   mApzUpdater->RunOnControllerThread(
912       aLayersId, NS_NewRunnableFunction(
913                      "layers::CompositorBridgeParent::FlushApzRepaints",
914                      [=]() { APZCTreeManager::FlushApzRepaints(aLayersId); }));
915 }
916 
GetAPZTestData(const LayersId & aLayersId,APZTestData * aOutData)917 void CompositorBridgeParent::GetAPZTestData(const LayersId& aLayersId,
918                                             APZTestData* aOutData) {
919   if (mApzUpdater) {
920     MOZ_ASSERT(aLayersId.IsValid());
921     mApzUpdater->GetAPZTestData(aLayersId, aOutData);
922   }
923 }
924 
GetFrameUniformity(const LayersId & aLayersId,FrameUniformityData * aOutData)925 void CompositorBridgeParent::GetFrameUniformity(const LayersId& aLayersId,
926                                                 FrameUniformityData* aOutData) {
927 }
928 
SetConfirmedTargetAPZC(const LayersId & aLayersId,const uint64_t & aInputBlockId,nsTArray<ScrollableLayerGuid> && aTargets)929 void CompositorBridgeParent::SetConfirmedTargetAPZC(
930     const LayersId& aLayersId, const uint64_t& aInputBlockId,
931     nsTArray<ScrollableLayerGuid>&& aTargets) {
932   if (!mApzcTreeManager || !mApzUpdater) {
933     return;
934   }
935   // Need to specifically bind this since it's overloaded.
936   void (APZCTreeManager::*setTargetApzcFunc)(
937       uint64_t, const nsTArray<ScrollableLayerGuid>&) =
938       &APZCTreeManager::SetTargetAPZC;
939   RefPtr<Runnable> task =
940       NewRunnableMethod<uint64_t,
941                         StoreCopyPassByRRef<nsTArray<ScrollableLayerGuid>>>(
942           "layers::CompositorBridgeParent::SetConfirmedTargetAPZC",
943           mApzcTreeManager.get(), setTargetApzcFunc, aInputBlockId,
944           std::move(aTargets));
945   mApzUpdater->RunOnUpdaterThread(aLayersId, task.forget());
946 }
947 
SetFixedLayerMargins(ScreenIntCoord aTop,ScreenIntCoord aBottom)948 void CompositorBridgeParent::SetFixedLayerMargins(ScreenIntCoord aTop,
949                                                   ScreenIntCoord aBottom) {
950   if (mApzcTreeManager) {
951     mApzcTreeManager->SetFixedLayerMargins(aTop, aBottom);
952   }
953 
954   Invalidate();
955   ScheduleComposition(wr::RenderReasons::RESIZE);
956 }
957 
GetCompositorBridgeParent(uint64_t id)958 CompositorBridgeParent* CompositorBridgeParent::GetCompositorBridgeParent(
959     uint64_t id) {
960   AssertIsInCompositorThread();
961   CompositorMap::iterator it = sCompositorMap->find(id);
962   return it != sCompositorMap->end() ? it->second : nullptr;
963 }
964 
AddCompositor(CompositorBridgeParent * compositor,uint64_t * outID)965 void CompositorBridgeParent::AddCompositor(CompositorBridgeParent* compositor,
966                                            uint64_t* outID) {
967   AssertIsInCompositorThread();
968 
969   static uint64_t sNextID = 1;
970 
971   ++sNextID;
972   (*sCompositorMap)[sNextID] = compositor;
973   *outID = sNextID;
974 }
975 
RemoveCompositor(uint64_t id)976 CompositorBridgeParent* CompositorBridgeParent::RemoveCompositor(uint64_t id) {
977   AssertIsInCompositorThread();
978 
979   CompositorMap::iterator it = sCompositorMap->find(id);
980   if (it == sCompositorMap->end()) {
981     return nullptr;
982   }
983   CompositorBridgeParent* retval = it->second;
984   sCompositorMap->erase(it);
985   return retval;
986 }
987 
NotifyVsync(const VsyncEvent & aVsync,const LayersId & aLayersId)988 void CompositorBridgeParent::NotifyVsync(const VsyncEvent& aVsync,
989                                          const LayersId& aLayersId) {
990   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
991   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
992 
993   MonitorAutoLock lock(*sIndirectLayerTreesLock);
994   auto it = sIndirectLayerTrees.find(aLayersId);
995   if (it == sIndirectLayerTrees.end()) return;
996 
997   CompositorBridgeParent* cbp = it->second.mParent;
998   if (!cbp || !cbp->mWidget) return;
999 
1000   RefPtr<VsyncObserver> obs = cbp->mWidget->GetVsyncObserver();
1001   if (!obs) return;
1002 
1003   obs->NotifyVsync(aVsync);
1004 }
1005 
1006 /* static */
ScheduleForcedComposition(const LayersId & aLayersId,wr::RenderReasons aReasons)1007 void CompositorBridgeParent::ScheduleForcedComposition(
1008     const LayersId& aLayersId, wr::RenderReasons aReasons) {
1009   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
1010   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1011 
1012   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1013   auto it = sIndirectLayerTrees.find(aLayersId);
1014   if (it == sIndirectLayerTrees.end()) {
1015     return;
1016   }
1017 
1018   CompositorBridgeParent* cbp = it->second.mParent;
1019   if (!cbp || !cbp->mWidget) {
1020     return;
1021   }
1022 
1023   if (cbp->mWrBridge) {
1024     cbp->mWrBridge->ScheduleForcedGenerateFrame(aReasons);
1025   } else if (cbp->CanComposite()) {
1026     cbp->mCompositorScheduler->ScheduleComposition(aReasons);
1027   }
1028 }
1029 
RecvNotifyChildCreated(const LayersId & child,CompositorOptions * aOptions)1030 mozilla::ipc::IPCResult CompositorBridgeParent::RecvNotifyChildCreated(
1031     const LayersId& child, CompositorOptions* aOptions) {
1032   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1033   NotifyChildCreated(child);
1034   *aOptions = mOptions;
1035   return IPC_OK();
1036 }
1037 
RecvNotifyChildRecreated(const LayersId & aChild,CompositorOptions * aOptions)1038 mozilla::ipc::IPCResult CompositorBridgeParent::RecvNotifyChildRecreated(
1039     const LayersId& aChild, CompositorOptions* aOptions) {
1040   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1041 
1042   if (sIndirectLayerTrees.find(aChild) != sIndirectLayerTrees.end()) {
1043     NS_WARNING("Invalid to register the same layer tree twice");
1044     return IPC_FAIL_NO_REASON(this);
1045   }
1046 
1047   NotifyChildCreated(aChild);
1048   *aOptions = mOptions;
1049   return IPC_OK();
1050 }
1051 
NotifyChildCreated(LayersId aChild)1052 void CompositorBridgeParent::NotifyChildCreated(LayersId aChild) {
1053   sIndirectLayerTreesLock->AssertCurrentThreadOwns();
1054   sIndirectLayerTrees[aChild].mParent = this;
1055 }
1056 
RecvMapAndNotifyChildCreated(const LayersId & aChild,const base::ProcessId & aOwnerPid,CompositorOptions * aOptions)1057 mozilla::ipc::IPCResult CompositorBridgeParent::RecvMapAndNotifyChildCreated(
1058     const LayersId& aChild, const base::ProcessId& aOwnerPid,
1059     CompositorOptions* aOptions) {
1060   // We only use this message when the remote compositor is in the GPU process.
1061   // It is harmless to call it, though.
1062   MOZ_ASSERT(XRE_IsGPUProcess());
1063 
1064   LayerTreeOwnerTracker::Get()->Map(aChild, aOwnerPid);
1065 
1066   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1067   NotifyChildCreated(aChild);
1068   *aOptions = mOptions;
1069   return IPC_OK();
1070 }
1071 
1072 enum class CompositorOptionsChangeKind {
1073   eSupported,
1074   eBestEffort,
1075   eUnsupported
1076 };
1077 
ClassifyCompositorOptionsChange(const CompositorOptions & aOld,const CompositorOptions & aNew)1078 static CompositorOptionsChangeKind ClassifyCompositorOptionsChange(
1079     const CompositorOptions& aOld, const CompositorOptions& aNew) {
1080   if (aOld == aNew) {
1081     return CompositorOptionsChangeKind::eSupported;
1082   }
1083   return CompositorOptionsChangeKind::eUnsupported;
1084 }
1085 
RecvAdoptChild(const LayersId & child)1086 mozilla::ipc::IPCResult CompositorBridgeParent::RecvAdoptChild(
1087     const LayersId& child) {
1088   RefPtr<APZUpdater> oldApzUpdater;
1089   APZCTreeManagerParent* parent;
1090   bool apzEnablementChanged = false;
1091   RefPtr<WebRenderBridgeParent> childWrBridge;
1092 
1093   // Before adopting the child, save the old compositor's root content
1094   // controller. We may need this to clear old layer transforms associated
1095   // with the child.
1096   // This is outside the lock because GetGeckoContentControllerForRoot()
1097   // does its own locking.
1098   RefPtr<GeckoContentController> oldRootController =
1099       GetGeckoContentControllerForRoot(child);
1100 
1101   {  // scope lock
1102     MonitorAutoLock lock(*sIndirectLayerTreesLock);
1103     // If child is already belong to this CompositorBridgeParent,
1104     // no need to handle adopting child.
1105     if (sIndirectLayerTrees[child].mParent == this) {
1106       return IPC_OK();
1107     }
1108 
1109     if (sIndirectLayerTrees[child].mParent) {
1110       switch (ClassifyCompositorOptionsChange(
1111           sIndirectLayerTrees[child].mParent->mOptions, mOptions)) {
1112         case CompositorOptionsChangeKind::eUnsupported: {
1113           MOZ_ASSERT(false,
1114                      "Moving tab between windows whose compositor options"
1115                      "differ in unsupported ways. Things may break in "
1116                      "unexpected ways");
1117           break;
1118         }
1119         case CompositorOptionsChangeKind::eBestEffort: {
1120           NS_WARNING(
1121               "Moving tab between windows with different APZ enablement. "
1122               "This is supported on a best-effort basis, but some things may "
1123               "break.");
1124           apzEnablementChanged = true;
1125           break;
1126         }
1127         case CompositorOptionsChangeKind::eSupported: {
1128           // The common case, no action required.
1129           break;
1130         }
1131       }
1132       oldApzUpdater = sIndirectLayerTrees[child].mParent->mApzUpdater;
1133     }
1134     NotifyChildCreated(child);
1135     if (mWrBridge) {
1136       childWrBridge = sIndirectLayerTrees[child].mWrBridge;
1137     }
1138     parent = sIndirectLayerTrees[child].mApzcTreeManagerParent;
1139   }
1140 
1141   if (childWrBridge) {
1142     MOZ_ASSERT(mWrBridge);
1143     RefPtr<wr::WebRenderAPI> api = mWrBridge->GetWebRenderAPI();
1144     api = api->Clone();
1145     wr::Epoch newEpoch = childWrBridge->UpdateWebRender(
1146         mWrBridge->CompositorScheduler(), std::move(api),
1147         mWrBridge->AsyncImageManager(),
1148         mWrBridge->GetTextureFactoryIdentifier());
1149     // Pretend we composited, since parent CompositorBridgeParent was replaced.
1150     TimeStamp now = TimeStamp::Now();
1151     NotifyPipelineRendered(childWrBridge->PipelineId(), newEpoch, VsyncId(),
1152                            now, now, now);
1153   }
1154 
1155   if (oldApzUpdater) {
1156     // If we are moving a child from an APZ-enabled window to an APZ-disabled
1157     // window (which can happen if e.g. a WebExtension moves a tab into a
1158     // popup window), try to handle it gracefully by clearing the old layer
1159     // transforms associated with the child. (Since the new compositor is
1160     // APZ-disabled, there will be nothing to update the transforms going
1161     // forward.)
1162     if (!mApzUpdater && oldRootController) {
1163       // Tell the old APZCTreeManager not to send any more layer transforms
1164       // for this layers ids.
1165       oldApzUpdater->MarkAsDetached(child);
1166 
1167       // Clear the current transforms.
1168       nsTArray<MatrixMessage> clear;
1169       clear.AppendElement(MatrixMessage(Nothing(), ScreenRect(), child));
1170       oldRootController->NotifyLayerTransforms(std::move(clear));
1171     }
1172   }
1173   if (mApzUpdater) {
1174     if (parent) {
1175       MOZ_ASSERT(mApzcTreeManager);
1176       parent->ChildAdopted(mApzcTreeManager, mApzUpdater);
1177     }
1178     mApzUpdater->NotifyLayerTreeAdopted(child, oldApzUpdater);
1179   }
1180   if (apzEnablementChanged) {
1181     Unused << SendCompositorOptionsChanged(child, mOptions);
1182   }
1183   return IPC_OK();
1184 }
1185 
AllocPWebRenderBridgeParent(const wr::PipelineId & aPipelineId,const LayoutDeviceIntSize & aSize,const WindowKind & aWindowKind)1186 PWebRenderBridgeParent* CompositorBridgeParent::AllocPWebRenderBridgeParent(
1187     const wr::PipelineId& aPipelineId, const LayoutDeviceIntSize& aSize,
1188     const WindowKind& aWindowKind) {
1189   MOZ_ASSERT(wr::AsLayersId(aPipelineId) == mRootLayerTreeID);
1190   MOZ_ASSERT(!mWrBridge);
1191   MOZ_ASSERT(!mCompositor);
1192   MOZ_ASSERT(!mCompositorScheduler);
1193   MOZ_ASSERT(mWidget);
1194 
1195 #ifdef XP_WIN
1196   if (mWidget && mWidget->AsWindows()) {
1197     const auto options = mWidget->GetCompositorOptions();
1198     if (!options.UseSoftwareWebRender() &&
1199         (DeviceManagerDx::Get()->CanUseDComp() ||
1200          gfxVars::UseWebRenderFlipSequentialWin())) {
1201       mWidget->AsWindows()->EnsureCompositorWindow();
1202     } else if (options.UseSoftwareWebRender() &&
1203                mWidget->AsWindows()->GetCompositorHwnd()) {
1204       mWidget->AsWindows()->DestroyCompositorWindow();
1205     }
1206   }
1207 #endif
1208 
1209   RefPtr<widget::CompositorWidget> widget = mWidget;
1210   wr::WrWindowId windowId = wr::NewWindowId();
1211   if (mApzUpdater) {
1212     // If APZ is enabled, we need to register the APZ updater with the window id
1213     // before the updater thread is created in WebRenderAPI::Create, so
1214     // that the callback from the updater thread can find the right APZUpdater.
1215     mApzUpdater->SetWebRenderWindowId(windowId);
1216   }
1217   if (mApzSampler) {
1218     // Same as for mApzUpdater, but for the sampler thread.
1219     mApzSampler->SetWebRenderWindowId(windowId);
1220   }
1221   if (mOMTASampler) {
1222     // Same, but for the OMTA sampler.
1223     mOMTASampler->SetWebRenderWindowId(windowId);
1224   }
1225 
1226   nsCString error("FEATURE_FAILURE_WEBRENDER_INITIALIZE_UNSPECIFIED");
1227   RefPtr<wr::WebRenderAPI> api = wr::WebRenderAPI::Create(
1228       this, std::move(widget), windowId, aSize, aWindowKind, error);
1229   if (!api) {
1230     mWrBridge =
1231         WebRenderBridgeParent::CreateDestroyed(aPipelineId, std::move(error));
1232     mWrBridge.get()->AddRef();  // IPDL reference
1233     return mWrBridge;
1234   }
1235 
1236 #ifdef MOZ_WIDGET_ANDROID
1237   // On Android, WebRenderAPI::Resume() call is triggered from Java side. But
1238   // Java side does not know about fallback to RenderCompositorOGLSWGL. In this
1239   // fallback case, RenderCompositor::Resume() needs to be called from gfx code.
1240   if (!mPaused && mWidget->GetCompositorOptions().UseSoftwareWebRender() &&
1241       mWidget->GetCompositorOptions().AllowSoftwareWebRenderOGL()) {
1242     api->Resume();
1243   }
1244 #endif
1245 
1246   wr::TransactionBuilder txn(api);
1247   txn.SetRootPipeline(aPipelineId);
1248   api->SendTransaction(txn);
1249 
1250   bool useCompositorWnd = false;
1251 #ifdef XP_WIN
1252   // Headless mode uses HeadlessWidget.
1253   if (mWidget->AsWindows()) {
1254     useCompositorWnd = !!mWidget->AsWindows()->GetCompositorHwnd();
1255   }
1256 #endif
1257   mAsyncImageManager =
1258       new AsyncImagePipelineManager(api->Clone(), useCompositorWnd);
1259   RefPtr<AsyncImagePipelineManager> asyncMgr = mAsyncImageManager;
1260   mWrBridge = new WebRenderBridgeParent(this, aPipelineId, mWidget, nullptr,
1261                                         std::move(api), std::move(asyncMgr),
1262                                         mVsyncRate);
1263   mWrBridge.get()->AddRef();  // IPDL reference
1264 
1265   mCompositorScheduler = mWrBridge->CompositorScheduler();
1266   MOZ_ASSERT(mCompositorScheduler);
1267   {  // scope lock
1268     MonitorAutoLock lock(*sIndirectLayerTreesLock);
1269     MOZ_ASSERT(sIndirectLayerTrees[mRootLayerTreeID].mWrBridge == nullptr);
1270     sIndirectLayerTrees[mRootLayerTreeID].mWrBridge = mWrBridge;
1271   }
1272   return mWrBridge;
1273 }
1274 
DeallocPWebRenderBridgeParent(PWebRenderBridgeParent * aActor)1275 bool CompositorBridgeParent::DeallocPWebRenderBridgeParent(
1276     PWebRenderBridgeParent* aActor) {
1277   WebRenderBridgeParent* parent = static_cast<WebRenderBridgeParent*>(aActor);
1278   {
1279     MonitorAutoLock lock(*sIndirectLayerTreesLock);
1280     auto it = sIndirectLayerTrees.find(wr::AsLayersId(parent->PipelineId()));
1281     if (it != sIndirectLayerTrees.end()) {
1282       it->second.mWrBridge = nullptr;
1283     }
1284   }
1285   parent->Release();  // IPDL reference
1286   return true;
1287 }
1288 
NotifyMemoryPressure()1289 void CompositorBridgeParent::NotifyMemoryPressure() {
1290   if (mWrBridge) {
1291     RefPtr<wr::WebRenderAPI> api = mWrBridge->GetWebRenderAPI();
1292     if (api) {
1293       api->NotifyMemoryPressure();
1294     }
1295   }
1296 }
1297 
AccumulateMemoryReport(wr::MemoryReport * aReport)1298 void CompositorBridgeParent::AccumulateMemoryReport(wr::MemoryReport* aReport) {
1299   if (mWrBridge) {
1300     RefPtr<wr::WebRenderAPI> api = mWrBridge->GetWebRenderAPI();
1301     if (api) {
1302       api->AccumulateMemoryReport(aReport);
1303     }
1304   }
1305 }
1306 
1307 /*static*/
InitializeStatics()1308 void CompositorBridgeParent::InitializeStatics() {
1309   gfxVars::SetForceSubpixelAAWherePossibleListener(&UpdateQualitySettings);
1310   gfxVars::SetWebRenderDebugFlagsListener(&UpdateDebugFlags);
1311   gfxVars::SetWebRenderBoolParametersListener(&UpdateWebRenderBoolParameters);
1312   gfxVars::SetWebRenderBatchingLookbackListener(&UpdateWebRenderParameters);
1313   gfxVars::SetWebRenderBlobTileSizeListener(&UpdateWebRenderParameters);
1314   gfxVars::SetWebRenderBatchedUploadThresholdListener(
1315       &UpdateWebRenderParameters);
1316 
1317   gfxVars::SetWebRenderProfilerUIListener(&UpdateWebRenderProfilerUI);
1318 }
1319 
1320 /*static*/
UpdateQualitySettings()1321 void CompositorBridgeParent::UpdateQualitySettings() {
1322   if (!CompositorThreadHolder::IsInCompositorThread()) {
1323     if (CompositorThread()) {
1324       CompositorThread()->Dispatch(
1325           NewRunnableFunction("CompositorBridgeParent::UpdateQualitySettings",
1326                               &CompositorBridgeParent::UpdateQualitySettings));
1327     }
1328 
1329     // If there is no compositor thread, e.g. due to shutdown, then we can
1330     // safefully just ignore this request.
1331     return;
1332   }
1333 
1334   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1335   ForEachWebRenderBridgeParent([&](WebRenderBridgeParent* wrBridge) -> void {
1336     wrBridge->UpdateQualitySettings();
1337   });
1338 }
1339 
1340 /*static*/
UpdateDebugFlags()1341 void CompositorBridgeParent::UpdateDebugFlags() {
1342   if (!CompositorThreadHolder::IsInCompositorThread()) {
1343     if (CompositorThread()) {
1344       CompositorThread()->Dispatch(
1345           NewRunnableFunction("CompositorBridgeParent::UpdateDebugFlags",
1346                               &CompositorBridgeParent::UpdateDebugFlags));
1347     }
1348 
1349     // If there is no compositor thread, e.g. due to shutdown, then we can
1350     // safefully just ignore this request.
1351     return;
1352   }
1353 
1354   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1355   ForEachWebRenderBridgeParent([&](WebRenderBridgeParent* wrBridge) -> void {
1356     wrBridge->UpdateDebugFlags();
1357   });
1358 }
1359 
1360 /*static*/
UpdateWebRenderBoolParameters()1361 void CompositorBridgeParent::UpdateWebRenderBoolParameters() {
1362   if (!CompositorThreadHolder::IsInCompositorThread()) {
1363     if (CompositorThread()) {
1364       CompositorThread()->Dispatch(NewRunnableFunction(
1365           "CompositorBridgeParent::UpdateWebRenderBoolParameters",
1366           &CompositorBridgeParent::UpdateWebRenderBoolParameters));
1367     }
1368 
1369     return;
1370   }
1371 
1372   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1373   ForEachWebRenderBridgeParent([&](WebRenderBridgeParent* wrBridge) -> void {
1374     wrBridge->UpdateBoolParameters();
1375   });
1376 }
1377 
1378 /*static*/
UpdateWebRenderParameters()1379 void CompositorBridgeParent::UpdateWebRenderParameters() {
1380   if (!CompositorThreadHolder::IsInCompositorThread()) {
1381     if (CompositorThread()) {
1382       CompositorThread()->Dispatch(NewRunnableFunction(
1383           "CompositorBridgeParent::UpdateWebRenderParameters",
1384           &CompositorBridgeParent::UpdateWebRenderParameters));
1385     }
1386 
1387     return;
1388   }
1389 
1390   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1391   ForEachWebRenderBridgeParent([&](WebRenderBridgeParent* wrBridge) -> void {
1392     wrBridge->UpdateParameters();
1393   });
1394 }
1395 
1396 /*static*/
UpdateWebRenderProfilerUI()1397 void CompositorBridgeParent::UpdateWebRenderProfilerUI() {
1398   if (!sIndirectLayerTreesLock) {
1399     return;
1400   }
1401   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1402   ForEachWebRenderBridgeParent([&](WebRenderBridgeParent* wrBridge) -> void {
1403     wrBridge->UpdateProfilerUI();
1404   });
1405 }
1406 
GetWebRenderBridgeParent() const1407 RefPtr<WebRenderBridgeParent> CompositorBridgeParent::GetWebRenderBridgeParent()
1408     const {
1409   return mWrBridge;
1410 }
1411 
GetTestingTimeStamp() const1412 Maybe<TimeStamp> CompositorBridgeParent::GetTestingTimeStamp() const {
1413   return mTestTime;
1414 }
1415 
EraseLayerState(LayersId aId)1416 void EraseLayerState(LayersId aId) {
1417   RefPtr<APZUpdater> apz;
1418   RefPtr<WebRenderBridgeParent> wrBridge;
1419 
1420   {  // scope lock
1421     MonitorAutoLock lock(*sIndirectLayerTreesLock);
1422     auto iter = sIndirectLayerTrees.find(aId);
1423     if (iter != sIndirectLayerTrees.end()) {
1424       CompositorBridgeParent* parent = iter->second.mParent;
1425       if (parent) {
1426         apz = parent->GetAPZUpdater();
1427       }
1428       wrBridge = iter->second.mWrBridge;
1429       sIndirectLayerTrees.erase(iter);
1430     }
1431   }
1432 
1433   if (apz) {
1434     apz->NotifyLayerTreeRemoved(aId);
1435   }
1436 
1437   if (wrBridge) {
1438     wrBridge->Destroy();
1439   }
1440 }
1441 
1442 /*static*/
DeallocateLayerTreeId(LayersId aId)1443 void CompositorBridgeParent::DeallocateLayerTreeId(LayersId aId) {
1444   MOZ_ASSERT(NS_IsMainThread());
1445   // Here main thread notifies compositor to remove an element from
1446   // sIndirectLayerTrees. This removed element might be queried soon.
1447   // Checking the elements of sIndirectLayerTrees exist or not before using.
1448   if (!CompositorThread()) {
1449     gfxCriticalError() << "Attempting to post to an invalid Compositor Thread";
1450     return;
1451   }
1452   CompositorThread()->Dispatch(
1453       NewRunnableFunction("EraseLayerStateRunnable", &EraseLayerState, aId));
1454 }
1455 
UpdateControllerForLayersId(LayersId aLayersId,GeckoContentController * aController)1456 static void UpdateControllerForLayersId(LayersId aLayersId,
1457                                         GeckoContentController* aController) {
1458   // Adopt ref given to us by SetControllerForLayerTree()
1459   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1460   sIndirectLayerTrees[aLayersId].mController =
1461       already_AddRefed<GeckoContentController>(aController);
1462 }
1463 
ScopedLayerTreeRegistration(LayersId aLayersId,GeckoContentController * aController)1464 ScopedLayerTreeRegistration::ScopedLayerTreeRegistration(
1465     LayersId aLayersId, GeckoContentController* aController)
1466     : mLayersId(aLayersId) {
1467   EnsureLayerTreeMapReady();
1468   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1469   sIndirectLayerTrees[aLayersId].mController = aController;
1470 }
1471 
~ScopedLayerTreeRegistration()1472 ScopedLayerTreeRegistration::~ScopedLayerTreeRegistration() {
1473   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1474   sIndirectLayerTrees.erase(mLayersId);
1475 }
1476 
1477 /*static*/
SetControllerForLayerTree(LayersId aLayersId,GeckoContentController * aController)1478 void CompositorBridgeParent::SetControllerForLayerTree(
1479     LayersId aLayersId, GeckoContentController* aController) {
1480   // This ref is adopted by UpdateControllerForLayersId().
1481   aController->AddRef();
1482   CompositorThread()->Dispatch(NewRunnableFunction(
1483       "UpdateControllerForLayersIdRunnable", &UpdateControllerForLayersId,
1484       aLayersId, aController));
1485 }
1486 
1487 /*static*/
GetAPZCTreeManager(LayersId aLayersId)1488 already_AddRefed<IAPZCTreeManager> CompositorBridgeParent::GetAPZCTreeManager(
1489     LayersId aLayersId) {
1490   EnsureLayerTreeMapReady();
1491   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1492   LayerTreeMap::iterator cit = sIndirectLayerTrees.find(aLayersId);
1493   if (sIndirectLayerTrees.end() == cit) {
1494     return nullptr;
1495   }
1496   LayerTreeState* lts = &cit->second;
1497 
1498   RefPtr<IAPZCTreeManager> apzctm =
1499       lts->mParent ? lts->mParent->mApzcTreeManager.get() : nullptr;
1500   return apzctm.forget();
1501 }
1502 
InsertVsyncProfilerMarker(TimeStamp aVsyncTimestamp)1503 static void InsertVsyncProfilerMarker(TimeStamp aVsyncTimestamp) {
1504   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1505   if (profiler_thread_is_being_profiled_for_markers()) {
1506     // Tracks when a vsync occurs according to the HardwareComposer.
1507     struct VsyncMarker {
1508       static constexpr mozilla::Span<const char> MarkerTypeName() {
1509         return mozilla::MakeStringSpan("VsyncTimestamp");
1510       }
1511       static void StreamJSONMarkerData(
1512           baseprofiler::SpliceableJSONWriter& aWriter) {}
1513       static MarkerSchema MarkerTypeDisplay() {
1514         using MS = MarkerSchema;
1515         MS schema{MS::Location::MarkerChart, MS::Location::MarkerTable};
1516         // Nothing outside the defaults.
1517         return schema;
1518       }
1519     };
1520     profiler_add_marker("VsyncTimestamp", geckoprofiler::category::GRAPHICS,
1521                         MarkerTiming::InstantAt(aVsyncTimestamp),
1522                         VsyncMarker{});
1523   }
1524 }
1525 
1526 /*static */
PostInsertVsyncProfilerMarker(TimeStamp aVsyncTimestamp)1527 void CompositorBridgeParent::PostInsertVsyncProfilerMarker(
1528     TimeStamp aVsyncTimestamp) {
1529   // Called in the vsync thread
1530   if (profiler_is_active() && CompositorThreadHolder::IsActive()) {
1531     CompositorThread()->Dispatch(
1532         NewRunnableFunction("InsertVsyncProfilerMarkerRunnable",
1533                             InsertVsyncProfilerMarker, aVsyncTimestamp));
1534   }
1535 }
1536 
1537 widget::PCompositorWidgetParent*
AllocPCompositorWidgetParent(const CompositorWidgetInitData & aInitData)1538 CompositorBridgeParent::AllocPCompositorWidgetParent(
1539     const CompositorWidgetInitData& aInitData) {
1540 #if defined(MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING)
1541   if (mWidget) {
1542     // Should not create two widgets on the same compositor.
1543     return nullptr;
1544   }
1545 
1546   widget::CompositorWidgetParent* widget =
1547       new widget::CompositorWidgetParent(aInitData, mOptions);
1548   widget->AddRef();
1549 
1550   // Sending the constructor acts as initialization as well.
1551   mWidget = widget;
1552   return widget;
1553 #else
1554   return nullptr;
1555 #endif
1556 }
1557 
DeallocPCompositorWidgetParent(PCompositorWidgetParent * aActor)1558 bool CompositorBridgeParent::DeallocPCompositorWidgetParent(
1559     PCompositorWidgetParent* aActor) {
1560 #if defined(MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING)
1561   static_cast<widget::CompositorWidgetParent*>(aActor)->Release();
1562   return true;
1563 #else
1564   return false;
1565 #endif
1566 }
1567 
1568 CompositorController*
GetCompositorController() const1569 CompositorBridgeParent::LayerTreeState::GetCompositorController() const {
1570   return mParent;
1571 }
1572 
DidComposite(const VsyncId & aId,TimeStamp & aCompositeStart,TimeStamp & aCompositeEnd)1573 void CompositorBridgeParent::DidComposite(const VsyncId& aId,
1574                                           TimeStamp& aCompositeStart,
1575                                           TimeStamp& aCompositeEnd) {
1576   if (mWrBridge) {
1577     MOZ_ASSERT(false);  // This should never get called for a WR compositor
1578   } else {
1579     NotifyDidComposite(mPendingTransactions, aId, aCompositeStart,
1580                        aCompositeEnd);
1581 #if defined(ENABLE_FRAME_LATENCY_LOG)
1582     if (!mPendingTransactions.IsEmpty()) {
1583       if (mRefreshStartTime) {
1584         int32_t latencyMs =
1585             lround((aCompositeEnd - mRefreshStartTime).ToMilliseconds());
1586         printf_stderr(
1587             "From transaction start to end of generate frame latencyMs %d this "
1588             "%p\n",
1589             latencyMs, this);
1590       }
1591       if (mFwdTime) {
1592         int32_t latencyMs = lround((aCompositeEnd - mFwdTime).ToMilliseconds());
1593         printf_stderr(
1594             "From forwarding transaction to end of generate frame latencyMs %d "
1595             "this %p\n",
1596             latencyMs, this);
1597       }
1598     }
1599     mRefreshStartTime = TimeStamp();
1600     mTxnStartTime = TimeStamp();
1601     mFwdTime = TimeStamp();
1602 #endif
1603     mPendingTransactions.Clear();
1604   }
1605 }
1606 
NotifyDidSceneBuild(RefPtr<const wr::WebRenderPipelineInfo> aInfo)1607 void CompositorBridgeParent::NotifyDidSceneBuild(
1608     RefPtr<const wr::WebRenderPipelineInfo> aInfo) {
1609   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1610   if (mPaused) {
1611     return;
1612   }
1613 
1614   if (mWrBridge) {
1615     mWrBridge->NotifyDidSceneBuild(aInfo);
1616   } else {
1617     mCompositorScheduler->ScheduleComposition(wr::RenderReasons::SCENE);
1618   }
1619 }
1620 
NotifyDidRender(const VsyncId & aCompositeStartId,TimeStamp & aCompositeStart,TimeStamp & aRenderStart,TimeStamp & aCompositeEnd,wr::RendererStats * aStats)1621 void CompositorBridgeParent::NotifyDidRender(const VsyncId& aCompositeStartId,
1622                                              TimeStamp& aCompositeStart,
1623                                              TimeStamp& aRenderStart,
1624                                              TimeStamp& aCompositeEnd,
1625                                              wr::RendererStats* aStats) {
1626   if (!mWrBridge) {
1627     return;
1628   }
1629 
1630   MOZ_RELEASE_ASSERT(mWrBridge->IsRootWebRenderBridgeParent());
1631 
1632   RefPtr<UiCompositorControllerParent> uiController =
1633       UiCompositorControllerParent::GetFromRootLayerTreeId(mRootLayerTreeID);
1634 
1635   if (uiController && mIsForcedFirstPaint) {
1636     uiController->NotifyFirstPaint();
1637     mIsForcedFirstPaint = false;
1638   }
1639 
1640   nsTArray<CompositionPayload> payload =
1641       mWrBridge->TakePendingScrollPayload(aCompositeStartId);
1642   if (!payload.IsEmpty()) {
1643     RecordCompositionPayloadsPresented(aCompositeEnd, payload);
1644   }
1645 
1646   nsTArray<ImageCompositeNotificationInfo> notifications;
1647   mWrBridge->ExtractImageCompositeNotifications(&notifications);
1648   if (!notifications.IsEmpty()) {
1649     Unused << ImageBridgeParent::NotifyImageComposites(notifications);
1650   }
1651 }
1652 
MaybeDeclareStable()1653 void CompositorBridgeParent::MaybeDeclareStable() {
1654   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1655 
1656   static bool sStable = false;
1657   if (!XRE_IsGPUProcess() || sStable) {
1658     return;
1659   }
1660 
1661   // Once we render as many frames as the threshold, we declare this instance of
1662   // the GPU process 'stable'. This causes the parent process to always respawn
1663   // the GPU process if it crashes.
1664   static uint32_t sFramesComposited = 0;
1665 
1666   if (++sFramesComposited >=
1667       StaticPrefs::layers_gpu_process_stable_frame_threshold()) {
1668     sStable = true;
1669 
1670     NS_DispatchToMainThread(NS_NewRunnableFunction(
1671         "gfx::GPUParent::SendDeclareStable", []() -> void {
1672           Unused << GPUParent::GetSingleton()->SendDeclareStable();
1673         }));
1674   }
1675 }
1676 
NotifyPipelineRendered(const wr::PipelineId & aPipelineId,const wr::Epoch & aEpoch,const VsyncId & aCompositeStartId,TimeStamp & aCompositeStart,TimeStamp & aRenderStart,TimeStamp & aCompositeEnd,wr::RendererStats * aStats)1677 void CompositorBridgeParent::NotifyPipelineRendered(
1678     const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch,
1679     const VsyncId& aCompositeStartId, TimeStamp& aCompositeStart,
1680     TimeStamp& aRenderStart, TimeStamp& aCompositeEnd,
1681     wr::RendererStats* aStats) {
1682   if (!mWrBridge || !mAsyncImageManager) {
1683     return;
1684   }
1685 
1686   bool isRoot = mWrBridge->PipelineId() == aPipelineId;
1687   RefPtr<WebRenderBridgeParent> wrBridge =
1688       isRoot ? mWrBridge
1689              : RefPtr<WebRenderBridgeParent>(
1690                    mAsyncImageManager->GetWrBridge(aPipelineId));
1691   if (!wrBridge) {
1692     return;
1693   }
1694 
1695   CompositorBridgeParentBase* compBridge =
1696       isRoot ? this : wrBridge->GetCompositorBridge();
1697   if (!compBridge) {
1698     return;
1699   }
1700 
1701   MOZ_RELEASE_ASSERT(isRoot == wrBridge->IsRootWebRenderBridgeParent());
1702 
1703   wrBridge->RemoveEpochDataPriorTo(aEpoch);
1704 
1705   nsTArray<FrameStats> stats;
1706   nsTArray<TransactionId> transactions;
1707 
1708   RefPtr<UiCompositorControllerParent> uiController =
1709       UiCompositorControllerParent::GetFromRootLayerTreeId(mRootLayerTreeID);
1710 
1711   wrBridge->FlushTransactionIdsForEpoch(
1712       aEpoch, aCompositeStartId, aCompositeStart, aRenderStart, aCompositeEnd,
1713       uiController, aStats, stats, transactions);
1714   if (transactions.IsEmpty()) {
1715     MOZ_ASSERT(stats.IsEmpty());
1716     return;
1717   }
1718 
1719   MaybeDeclareStable();
1720 
1721   LayersId layersId = isRoot ? LayersId{0} : wrBridge->GetLayersId();
1722   Unused << compBridge->SendDidComposite(layersId, transactions,
1723                                          aCompositeStart, aCompositeEnd);
1724 
1725   if (!stats.IsEmpty()) {
1726     Unused << SendNotifyFrameStats(stats);
1727   }
1728 }
1729 
1730 RefPtr<AsyncImagePipelineManager>
GetAsyncImagePipelineManager() const1731 CompositorBridgeParent::GetAsyncImagePipelineManager() const {
1732   return mAsyncImageManager;
1733 }
1734 
NotifyDidComposite(const nsTArray<TransactionId> & aTransactionIds,VsyncId aId,TimeStamp & aCompositeStart,TimeStamp & aCompositeEnd)1735 void CompositorBridgeParent::NotifyDidComposite(
1736     const nsTArray<TransactionId>& aTransactionIds, VsyncId aId,
1737     TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd) {
1738   MOZ_ASSERT(!mWrBridge,
1739              "We should be going through NotifyDidRender and "
1740              "NotifyPipelineRendered instead");
1741 
1742   MaybeDeclareStable();
1743   Unused << SendDidComposite(LayersId{0}, aTransactionIds, aCompositeStart,
1744                              aCompositeEnd);
1745 
1746   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1747   ForEachIndirectLayerTree([&](LayerTreeState* lts,
1748                                const LayersId& aLayersId) -> void {
1749     if (lts->mContentCompositorBridgeParent && lts->mParent == this) {
1750       ContentCompositorBridgeParent* cpcp = lts->mContentCompositorBridgeParent;
1751       cpcp->DidCompositeLocked(aLayersId, aId, aCompositeStart, aCompositeEnd);
1752     }
1753   });
1754 }
1755 
InvalidateRemoteLayers()1756 void CompositorBridgeParent::InvalidateRemoteLayers() {
1757   MOZ_ASSERT(CompositorThread()->IsOnCurrentThread());
1758 
1759   Unused << PCompositorBridgeParent::SendInvalidateLayers(LayersId{0});
1760 
1761   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1762   ForEachIndirectLayerTree([](LayerTreeState* lts,
1763                               const LayersId& aLayersId) -> void {
1764     if (lts->mContentCompositorBridgeParent) {
1765       ContentCompositorBridgeParent* cpcp = lts->mContentCompositorBridgeParent;
1766       Unused << cpcp->SendInvalidateLayers(aLayersId);
1767     }
1768   });
1769 }
1770 
1771 /* static */ CompositorBridgeParent::LayerTreeState*
GetIndirectShadowTree(LayersId aId)1772 CompositorBridgeParent::GetIndirectShadowTree(LayersId aId) {
1773   // Only the compositor thread should use this method variant
1774   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1775 
1776   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1777   LayerTreeMap::iterator cit = sIndirectLayerTrees.find(aId);
1778   if (sIndirectLayerTrees.end() == cit) {
1779     return nullptr;
1780   }
1781   return &cit->second;
1782 }
1783 
1784 /* static */
CallWithIndirectShadowTree(LayersId aId,const std::function<void (CompositorBridgeParent::LayerTreeState &)> & aFunc)1785 bool CompositorBridgeParent::CallWithIndirectShadowTree(
1786     LayersId aId,
1787     const std::function<void(CompositorBridgeParent::LayerTreeState&)>& aFunc) {
1788   if (!sIndirectLayerTreesLock) {
1789     // Can hapen during shutdown
1790     return false;
1791   }
1792   // Note that this does not make things universally threadsafe just because the
1793   // sIndirectLayerTreesLock mutex is held. This is because the compositor
1794   // thread can mutate the LayerTreeState outside the lock. It does however
1795   // ensure that the *storage* for the LayerTreeState remains stable, since we
1796   // should always hold the lock when adding/removing entries to the map.
1797   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1798   LayerTreeMap::iterator cit = sIndirectLayerTrees.find(aId);
1799   if (sIndirectLayerTrees.end() == cit) {
1800     return false;
1801   }
1802   aFunc(cit->second);
1803   return true;
1804 }
1805 
GetStateForRoot(LayersId aContentLayersId,const MonitorAutoLock & aProofOfLock)1806 static CompositorBridgeParent::LayerTreeState* GetStateForRoot(
1807     LayersId aContentLayersId, const MonitorAutoLock& aProofOfLock) {
1808   CompositorBridgeParent::LayerTreeState* state = nullptr;
1809   LayerTreeMap::iterator itr = sIndirectLayerTrees.find(aContentLayersId);
1810   if (sIndirectLayerTrees.end() != itr) {
1811     state = &itr->second;
1812   }
1813 
1814   // |state| is the state for the content process, but we want the APZCTMParent
1815   // for the parent process owning that content process. So we have to jump to
1816   // the LayerTreeState for the root layer tree id for that layer tree, and use
1817   // the mApzcTreeManagerParent from that. This should also work with nested
1818   // content processes, because RootLayerTreeId() will bypass any intermediate
1819   // processes' ids and go straight to the root.
1820   if (state && state->mParent) {
1821     LayersId rootLayersId = state->mParent->RootLayerTreeId();
1822     itr = sIndirectLayerTrees.find(rootLayersId);
1823     state = (sIndirectLayerTrees.end() != itr) ? &itr->second : nullptr;
1824   }
1825 
1826   return state;
1827 }
1828 
1829 /* static */
GetApzcTreeManagerParentForRoot(LayersId aContentLayersId)1830 APZCTreeManagerParent* CompositorBridgeParent::GetApzcTreeManagerParentForRoot(
1831     LayersId aContentLayersId) {
1832   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1833   CompositorBridgeParent::LayerTreeState* state =
1834       GetStateForRoot(aContentLayersId, lock);
1835   return state ? state->mApzcTreeManagerParent : nullptr;
1836 }
1837 
1838 /* static */
1839 GeckoContentController*
GetGeckoContentControllerForRoot(LayersId aContentLayersId)1840 CompositorBridgeParent::GetGeckoContentControllerForRoot(
1841     LayersId aContentLayersId) {
1842   MonitorAutoLock lock(*sIndirectLayerTreesLock);
1843   CompositorBridgeParent::LayerTreeState* state =
1844       GetStateForRoot(aContentLayersId, lock);
1845   return state ? state->mController.get() : nullptr;
1846 }
1847 
AllocPTextureParent(const SurfaceDescriptor & aSharedData,ReadLockDescriptor & aReadLock,const LayersBackend & aLayersBackend,const TextureFlags & aFlags,const LayersId & aId,const uint64_t & aSerial,const wr::MaybeExternalImageId & aExternalImageId)1848 PTextureParent* CompositorBridgeParent::AllocPTextureParent(
1849     const SurfaceDescriptor& aSharedData, ReadLockDescriptor& aReadLock,
1850     const LayersBackend& aLayersBackend, const TextureFlags& aFlags,
1851     const LayersId& aId, const uint64_t& aSerial,
1852     const wr::MaybeExternalImageId& aExternalImageId) {
1853   return TextureHost::CreateIPDLActor(this, aSharedData, std::move(aReadLock),
1854                                       aLayersBackend, aFlags, aSerial,
1855                                       aExternalImageId);
1856 }
1857 
DeallocPTextureParent(PTextureParent * actor)1858 bool CompositorBridgeParent::DeallocPTextureParent(PTextureParent* actor) {
1859   return TextureHost::DestroyIPDLActor(actor);
1860 }
1861 
RecvInitPCanvasParent(Endpoint<PCanvasParent> && aEndpoint)1862 mozilla::ipc::IPCResult CompositorBridgeParent::RecvInitPCanvasParent(
1863     Endpoint<PCanvasParent>&& aEndpoint) {
1864   MOZ_CRASH("PCanvasParent shouldn't be created via CompositorBridgeParent.");
1865 }
1866 
RecvReleasePCanvasParent()1867 mozilla::ipc::IPCResult CompositorBridgeParent::RecvReleasePCanvasParent() {
1868   MOZ_CRASH("PCanvasParent shouldn't be released via CompositorBridgeParent.");
1869 }
1870 
IsSameProcess() const1871 bool CompositorBridgeParent::IsSameProcess() const {
1872   return OtherPid() == base::GetCurrentProcId();
1873 }
1874 
NotifyWebRenderDisableNativeCompositor()1875 void CompositorBridgeParent::NotifyWebRenderDisableNativeCompositor() {
1876   MOZ_ASSERT(CompositorThread()->IsOnCurrentThread());
1877   if (mWrBridge) {
1878     mWrBridge->DisableNativeCompositor();
1879   }
1880 }
1881 
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)1882 int32_t RecordContentFrameTime(
1883     const VsyncId& aTxnId, const TimeStamp& aVsyncStart,
1884     const TimeStamp& aTxnStart, const VsyncId& aCompositeId,
1885     const TimeStamp& aCompositeEnd, const TimeDuration& aFullPaintTime,
1886     const TimeDuration& aVsyncRate, bool aContainsSVGGroup,
1887     bool aRecordUploadStats, wr::RendererStats* aStats /* = nullptr */) {
1888   double latencyMs = (aCompositeEnd - aTxnStart).ToMilliseconds();
1889   double latencyNorm = latencyMs / aVsyncRate.ToMilliseconds();
1890   int32_t fracLatencyNorm = lround(latencyNorm * 100.0);
1891 
1892   if (profiler_thread_is_being_profiled_for_markers()) {
1893     struct ContentFrameMarker {
1894       static constexpr Span<const char> MarkerTypeName() {
1895         return MakeStringSpan("CONTENT_FRAME_TIME");
1896       }
1897       static void StreamJSONMarkerData(
1898           baseprofiler::SpliceableJSONWriter& aWriter) {}
1899       static MarkerSchema MarkerTypeDisplay() {
1900         using MS = MarkerSchema;
1901         MS schema{MS::Location::MarkerChart, MS::Location::MarkerTable};
1902         // Nothing outside the defaults.
1903         return schema;
1904       }
1905     };
1906 
1907     profiler_add_marker("CONTENT_FRAME_TIME", geckoprofiler::category::GRAPHICS,
1908                         MarkerTiming::Interval(aTxnStart, aCompositeEnd),
1909                         ContentFrameMarker{});
1910   }
1911 
1912   Telemetry::Accumulate(Telemetry::CONTENT_FRAME_TIME, fracLatencyNorm);
1913 
1914   if (!(aTxnId == VsyncId()) && aVsyncStart) {
1915     latencyMs = (aCompositeEnd - aVsyncStart).ToMilliseconds();
1916     latencyNorm = latencyMs / aVsyncRate.ToMilliseconds();
1917     fracLatencyNorm = lround(latencyNorm * 100.0);
1918     int32_t result = fracLatencyNorm;
1919     Telemetry::Accumulate(Telemetry::CONTENT_FRAME_TIME_VSYNC, fracLatencyNorm);
1920 
1921     if (aContainsSVGGroup) {
1922       Telemetry::Accumulate(Telemetry::CONTENT_FRAME_TIME_WITH_SVG,
1923                             fracLatencyNorm);
1924     }
1925 
1926     // Record CONTENT_FRAME_TIME_REASON.
1927     //
1928     // Note that deseralizing a layers update (RecvUpdate) can delay the receipt
1929     // of the composite vsync message
1930     // (CompositorBridgeParent::CompositeToTarget), since they're using the same
1931     // thread. This can mean that compositing might start significantly late,
1932     // but this code will still detect it as having successfully started on the
1933     // right vsync (which is somewhat correct). We'd now have reduced time left
1934     // in the vsync interval to finish compositing, so the chances of a missed
1935     // frame increases. This is effectively including the RecvUpdate work as
1936     // part of the 'compositing' phase for this metric, but it isn't included in
1937     // COMPOSITE_TIME, and *is* included in CONTENT_FULL_PAINT_TIME.
1938     //
1939     // Also of note is that when the root WebRenderBridgeParent decides to
1940     // skip a composite (due to the Renderer being busy), that won't notify
1941     // child WebRenderBridgeParents. That failure will show up as the
1942     // composite starting late (since it did), but it's really a fault of a
1943     // slow composite on the previous frame, not a slow
1944     // CONTENT_FULL_PAINT_TIME. It would be nice to have a separate bucket for
1945     // this category (scene was ready on the next vsync, but we chose not to
1946     // composite), but I can't find a way to locate the right child
1947     // WebRenderBridgeParents from the root. WebRender notifies us of the
1948     // child pipelines contained within a render, after it finishes, but I
1949     // can't see how to query what child pipeline would have been rendered,
1950     // when we choose to not do it.
1951     if (fracLatencyNorm < 200) {
1952       // Success
1953       Telemetry::AccumulateCategorical(
1954           LABELS_CONTENT_FRAME_TIME_REASON::OnTime);
1955     } else {
1956       if (aCompositeId == VsyncId()) {
1957         // aCompositeId is 0, possibly something got trigged from
1958         // outside vsync?
1959         Telemetry::AccumulateCategorical(
1960             LABELS_CONTENT_FRAME_TIME_REASON::NoVsyncNoId);
1961       } else if (aTxnId >= aCompositeId) {
1962         // Vsync ids are nonsensical, maybe we're trying to catch up?
1963         Telemetry::AccumulateCategorical(
1964             LABELS_CONTENT_FRAME_TIME_REASON::NoVsync);
1965       } else if (aCompositeId - aTxnId > 1) {
1966         // Composite started late (and maybe took too long as well)
1967         if (aFullPaintTime >= TimeDuration::FromMilliseconds(20)) {
1968           Telemetry::AccumulateCategorical(
1969               LABELS_CONTENT_FRAME_TIME_REASON::MissedCompositeLong);
1970         } else if (aFullPaintTime >= TimeDuration::FromMilliseconds(10)) {
1971           Telemetry::AccumulateCategorical(
1972               LABELS_CONTENT_FRAME_TIME_REASON::MissedCompositeMid);
1973         } else if (aFullPaintTime >= TimeDuration::FromMilliseconds(5)) {
1974           Telemetry::AccumulateCategorical(
1975               LABELS_CONTENT_FRAME_TIME_REASON::MissedCompositeLow);
1976         } else {
1977           Telemetry::AccumulateCategorical(
1978               LABELS_CONTENT_FRAME_TIME_REASON::MissedComposite);
1979         }
1980       } else {
1981         // Composite started on time, but must have taken too long.
1982         Telemetry::AccumulateCategorical(
1983             LABELS_CONTENT_FRAME_TIME_REASON::SlowComposite);
1984       }
1985     }
1986 
1987     if (aRecordUploadStats) {
1988       if (aStats) {
1989         latencyMs -= (double(aStats->resource_upload_time) / 1000000.0);
1990         latencyNorm = latencyMs / aVsyncRate.ToMilliseconds();
1991         fracLatencyNorm = lround(latencyNorm * 100.0);
1992       }
1993       Telemetry::Accumulate(
1994           Telemetry::CONTENT_FRAME_TIME_WITHOUT_RESOURCE_UPLOAD,
1995           fracLatencyNorm);
1996 
1997       if (aStats) {
1998         latencyMs -= (double(aStats->gpu_cache_upload_time) / 1000000.0);
1999         latencyNorm = latencyMs / aVsyncRate.ToMilliseconds();
2000         fracLatencyNorm = lround(latencyNorm * 100.0);
2001       }
2002       Telemetry::Accumulate(Telemetry::CONTENT_FRAME_TIME_WITHOUT_UPLOAD,
2003                             fracLatencyNorm);
2004     }
2005     return result;
2006   }
2007 
2008   return 0;
2009 }
2010 
RecvBeginRecording(const TimeStamp & aRecordingStart,BeginRecordingResolver && aResolve)2011 mozilla::ipc::IPCResult CompositorBridgeParent::RecvBeginRecording(
2012     const TimeStamp& aRecordingStart, BeginRecordingResolver&& aResolve) {
2013   if (mHaveCompositionRecorder) {
2014     aResolve(false);
2015     return IPC_OK();
2016   }
2017 
2018   if (mWrBridge) {
2019     mWrBridge->BeginRecording(aRecordingStart);
2020   }
2021 
2022   mHaveCompositionRecorder = true;
2023   aResolve(true);
2024 
2025   return IPC_OK();
2026 }
2027 
RecvEndRecordingToDisk(EndRecordingToDiskResolver && aResolve)2028 mozilla::ipc::IPCResult CompositorBridgeParent::RecvEndRecordingToDisk(
2029     EndRecordingToDiskResolver&& aResolve) {
2030   if (!mHaveCompositionRecorder) {
2031     aResolve(false);
2032     return IPC_OK();
2033   }
2034 
2035   if (mWrBridge) {
2036     mWrBridge->WriteCollectedFrames()->Then(
2037         NS_GetCurrentThread(), __func__,
2038         [resolve{aResolve}](const bool success) { resolve(success); },
2039         [resolve{aResolve}]() { resolve(false); });
2040   } else {
2041     aResolve(false);
2042   }
2043 
2044   mHaveCompositionRecorder = false;
2045 
2046   return IPC_OK();
2047 }
2048 
RecvEndRecordingToMemory(EndRecordingToMemoryResolver && aResolve)2049 mozilla::ipc::IPCResult CompositorBridgeParent::RecvEndRecordingToMemory(
2050     EndRecordingToMemoryResolver&& aResolve) {
2051   if (!mHaveCompositionRecorder) {
2052     aResolve(Nothing());
2053     return IPC_OK();
2054   }
2055 
2056   if (mWrBridge) {
2057     RefPtr<CompositorBridgeParent> self = this;
2058     mWrBridge->GetCollectedFrames()->Then(
2059         NS_GetCurrentThread(), __func__,
2060         [self, resolve{aResolve}](CollectedFrames&& frames) {
2061           resolve(self->WrapCollectedFrames(std::move(frames)));
2062         },
2063         [resolve{aResolve}]() { resolve(Nothing()); });
2064   }
2065 
2066   mHaveCompositionRecorder = false;
2067 
2068   return IPC_OK();
2069 }
2070 
WrapCollectedFrames(CollectedFrames && aFrames)2071 Maybe<CollectedFramesParams> CompositorBridgeParent::WrapCollectedFrames(
2072     CollectedFrames&& aFrames) {
2073   CollectedFramesParams ipcFrames;
2074   ipcFrames.recordingStart() = aFrames.mRecordingStart;
2075 
2076   size_t totalLength = 0;
2077   for (const CollectedFrame& frame : aFrames.mFrames) {
2078     totalLength += frame.mDataUri.Length();
2079   }
2080 
2081   Shmem shmem;
2082   if (!AllocShmem(totalLength, SharedMemory::TYPE_BASIC, &shmem)) {
2083     return Nothing();
2084   }
2085 
2086   {
2087     char* raw = shmem.get<char>();
2088     for (CollectedFrame& frame : aFrames.mFrames) {
2089       size_t length = frame.mDataUri.Length();
2090 
2091       PodCopy(raw, frame.mDataUri.get(), length);
2092       raw += length;
2093 
2094       ipcFrames.frames().EmplaceBack(frame.mTimeOffset, length);
2095     }
2096   }
2097   ipcFrames.buffer() = std::move(shmem);
2098 
2099   return Some(std::move(ipcFrames));
2100 }
2101 
2102 }  // namespace layers
2103 }  // namespace mozilla
2104