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