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