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(¬ifications);
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