# HG changeset patch # User Kartikaya Gupta # Date 1523377801 14400 # Node ID 3542146e997310c11ab000341cce6360623fce30 # Parent 5ec0f0947e7650588f020428f8f6cc2714c6f6cd Bug 1449982 - Conceptually split the mUpdaterQueue into separate queues per layers id. r=botond This allows us to treat tasks from different layers id as independent, thereby removing the unnecessary latency increase as described in bug 1449982 comment 33. Note that we could probably implement this by actually maintaining separate queues for each layers id, but that involves more overhead since we would need to have a map from layers id to task queue, and removing entries from that map becomes tricky with respect to locking and timing. MozReview-Commit-ID: 7jtYqNDwJqP diff --git a/gfx/layers/apz/public/APZUpdater.h b/gfx/layers/apz/public/APZUpdater.h --- a/gfx/layers/apz/public/APZUpdater.h +++ b/gfx/layers/apz/public/APZUpdater.h @@ -55,17 +55,17 @@ public: * which thread it is. */ static void SetUpdaterThread(const wr::WrWindowId& aWindowId); static void PrepareForSceneSwap(const wr::WrWindowId& aWindowId); static void CompleteSceneSwap(const wr::WrWindowId& aWindowId, wr::WrPipelineInfo* aInfo); static void ProcessPendingTasks(const wr::WrWindowId& aWindowId); - void ClearTree(); + void ClearTree(LayersId aRootLayersId); void UpdateFocusState(LayersId aRootLayerTreeId, LayersId aOriginatingLayersId, const FocusTarget& aFocusTarget); void UpdateHitTestingTree(LayersId aRootLayerTreeId, Layer* aRoot, bool aIsFirstPaint, LayersId aOriginatingLayersId, uint32_t aPaintSequenceNumber); @@ -104,41 +104,47 @@ public: * This does nothing if thread assertions are disabled. */ void AssertOnUpdaterThread() const; /** * Runs the given task on the APZ "updater thread" for this APZUpdater. If * this function is called from the updater thread itself then the task is * run immediately without getting queued. + * The layers id argument should be the id of the layer tree that is + * requesting this task to be run. Conceptually each layer tree has a separate + * task queue, so that if one layer tree is blocked waiting for a scene build + * then tasks for the other layer trees can still be processed. */ - void RunOnUpdaterThread(already_AddRefed aTask); + void RunOnUpdaterThread(LayersId aLayersId, already_AddRefed aTask); /** * Returns true if currently on the APZUpdater's "updater thread". */ bool IsUpdaterThread() const; /** * Dispatches the given task to the APZ "controller thread", but does it *from* * the updater thread. That is, if the thread on which this function is called * is not the updater thread, the task is first dispatched to the updater thread. * When the updater thread runs it (or if this is called directly on the updater * thread), that is when the task gets dispatched to the controller thread. * The controller thread then actually runs the task. + * The layers id argument should be the id of the layer tree that is + * requesting this task to be run; in most cases this will probably just be + * the root layers id of the compositor. */ - void RunOnControllerThread(already_AddRefed aTask); + void RunOnControllerThread(LayersId aLayersId, already_AddRefed aTask); protected: virtual ~APZUpdater(); bool UsingWebRenderUpdaterThread() const; static already_AddRefed GetUpdater(const wr::WrWindowId& aWindowId); - bool IsQueueBlocked() const; void ProcessQueue(); private: RefPtr mApz; // Map from layers id to WebRenderScrollData. This can only be touched on // the updater thread. std::unordered_map mBuilt; // True if and only if the layers id is the root layers id for the compositor bool mIsRoot; EpochState(); // Whether or not the state for this layers id is such that it blocks - // processing of queued tasks. This happens if the root layers id or any - // "visible" layers id has scroll data for an epoch newer than what has - // been built. A "visible" layers id is one that is attached to the full + // processing of tasks for the layer tree. This happens if the root layers + // id or a "visible" layers id has scroll data for an epoch newer than what + // has been built. A "visible" layers id is one that is attached to the full // layer tree (i.e. there is a chain of reflayer items from the root layer // tree to the relevant layer subtree. This is not always the case; for // instance a content process may send the compositor layers for a document // before the chrome has attached the remote iframe to the root document. // Since WR only builds pipelines for "visible" layers ids, |mBuilt| being // populated means that the layers id is "visible". - bool IsBlockingQueue() const; + bool IsBlocked() const; }; - // Map from layers id to epoch state. If any of the epoch states returns true - // for IsBlockingQueue(), that means we cannot yet process content-side data - // still in the task queue, because otherwise we would apply it before the - // scene swap for that scene has occurred. + // Map from layers id to epoch state. // This data structure can only be touched on the updater thread. std::unordered_map mEpochData; // Used to manage the mapping from a WR window id to APZUpdater. These are only // used if WebRender is enabled. Both sWindowIdMap and mWindowId should only // be used while holding the sWindowIdLock. @@ -196,20 +199,31 @@ private: // without locking should be fine. Maybe mUpdaterThreadId; #ifdef DEBUG // This flag is used to ensure that we don't ever try to do updater-thread // stuff before the updater thread has been properly initialized. mutable bool mUpdaterThreadQueried; #endif + // Helper struct that pairs each queued runnable with the layers id that it + // is associated with. This allows us to easily implement the conceptual + // separation of mUpdaterQueue into independent queues per layers id. + struct QueuedTask { + LayersId mLayersId; + RefPtr mRunnable; + }; + // Lock used to protect mUpdaterQueue Mutex mQueueLock; - // Holds a FIFO queue of tasks to be run on the updater thread, + // Holds a queue of tasks to be run on the updater thread, // when the updater thread is a WebRender thread, since it won't have a - // message loop we can dispatch to. - std::deque> mUpdaterQueue; + // message loop we can dispatch to. Note that although this is a single queue + // it is conceptually separated into multiple ones, one per layers id. Tasks + // for a given layers id will always run in FIFO order, but there is no + // guaranteed ordering for tasks with different layers ids. + std::deque mUpdaterQueue; }; } // namespace layers } // namespace mozilla #endif // mozilla_layers_APZUpdater_h diff --git a/gfx/layers/apz/src/APZCTreeManager.cpp b/gfx/layers/apz/src/APZCTreeManager.cpp --- a/gfx/layers/apz/src/APZCTreeManager.cpp +++ b/gfx/layers/apz/src/APZCTreeManager.cpp @@ -1970,16 +1970,17 @@ APZCTreeManager::UpdateZoomConstraints(c { if (!GetUpdater()->IsUpdaterThread()) { // This can happen if we're in the UI process and got a call directly from // nsBaseWidget (as opposed to over PAPZCTreeManager). We want this function // to run on the updater thread, so bounce it over. MOZ_ASSERT(XRE_IsParentProcess()); GetUpdater()->RunOnUpdaterThread( + aGuid.mLayersId, NewRunnableMethod>( "APZCTreeManager::UpdateZoomConstraints", this, &APZCTreeManager::UpdateZoomConstraints, aGuid, aConstraints)); return; } diff --git a/gfx/layers/apz/src/APZUpdater.cpp b/gfx/layers/apz/src/APZUpdater.cpp --- a/gfx/layers/apz/src/APZUpdater.cpp +++ b/gfx/layers/apz/src/APZUpdater.cpp @@ -130,21 +130,21 @@ APZUpdater::CompleteSceneSwap(const wr:: APZUpdater::ProcessPendingTasks(const wr::WrWindowId& aWindowId) { if (RefPtr updater = GetUpdater(aWindowId)) { updater->ProcessQueue(); } } void -APZUpdater::ClearTree() +APZUpdater::ClearTree(LayersId aRootLayersId) { MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); RefPtr self = this; - RunOnUpdaterThread(NS_NewRunnableFunction( + RunOnUpdaterThread(aRootLayersId, NS_NewRunnableFunction( "APZUpdater::ClearTree", [=]() { self->mApz->ClearTree(); // Once ClearTree is called on the APZCTreeManager, we are in a shutdown // phase. After this point it's ok if WebRender cannot get a hold of the // updater via the window id, and it's a good point to remove the mapping // and avoid leaving a dangling pointer to this object. @@ -157,17 +157,17 @@ APZUpdater::ClearTree() } void APZUpdater::UpdateFocusState(LayersId aRootLayerTreeId, LayersId aOriginatingLayersId, const FocusTarget& aFocusTarget) { MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); - RunOnUpdaterThread(NewRunnableMethod( + RunOnUpdaterThread(aOriginatingLayersId, NewRunnableMethod( "APZUpdater::UpdateFocusState", mApz, &APZCTreeManager::UpdateFocusState, aRootLayerTreeId, aOriginatingLayersId, aFocusTarget)); } @@ -192,26 +192,26 @@ APZUpdater::UpdateScrollDataAndTreeState { MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); RefPtr self = this; // Insert an epoch requirement update into the queue, so that // tasks inserted into the queue after this point only get executed // once the epoch requirement is satisfied. In particular, the // UpdateHitTestingTree call below needs to wait until the epoch requirement // is satisfied, which is why it is a separate task in the queue. - RunOnUpdaterThread(NS_NewRunnableFunction( + RunOnUpdaterThread(aOriginatingLayersId, NS_NewRunnableFunction( "APZUpdater::UpdateEpochRequirement", [=]() { if (aRootLayerTreeId == aOriginatingLayersId) { self->mEpochData[aOriginatingLayersId].mIsRoot = true; } self->mEpochData[aOriginatingLayersId].mRequired = aEpoch; } )); - RunOnUpdaterThread(NS_NewRunnableFunction( + RunOnUpdaterThread(aOriginatingLayersId, NS_NewRunnableFunction( "APZUpdater::UpdateHitTestingTree", [=,aScrollData=Move(aScrollData)]() { self->mApz->UpdateFocusState(aRootLayerTreeId, aOriginatingLayersId, aScrollData.GetFocusTarget()); self->mScrollData[aOriginatingLayersId] = aScrollData; auto root = self->mScrollData.find(aRootLayerTreeId); if (root == self->mScrollData.end()) { @@ -225,30 +225,30 @@ APZUpdater::UpdateScrollDataAndTreeState )); } void APZUpdater::NotifyLayerTreeAdopted(LayersId aLayersId, const RefPtr& aOldUpdater) { MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); - RunOnUpdaterThread(NewRunnableMethod>( + RunOnUpdaterThread(aLayersId, NewRunnableMethod>( "APZUpdater::NotifyLayerTreeAdopted", mApz, &APZCTreeManager::NotifyLayerTreeAdopted, aLayersId, aOldUpdater ? aOldUpdater->mApz : nullptr)); } void APZUpdater::NotifyLayerTreeRemoved(LayersId aLayersId) { MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); RefPtr self = this; - RunOnUpdaterThread(NS_NewRunnableFunction( + RunOnUpdaterThread(aLayersId, NS_NewRunnableFunction( "APZUpdater::NotifyLayerTreeRemoved", [=]() { self->mEpochData.erase(aLayersId); self->mScrollData.erase(aLayersId); self->mApz->NotifyLayerTreeRemoved(aLayersId); } )); } @@ -257,17 +257,17 @@ bool APZUpdater::GetAPZTestData(LayersId aLayersId, APZTestData* aOutData) { MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); RefPtr apz = mApz; bool ret = false; SynchronousTask waiter("APZUpdater::GetAPZTestData"); - RunOnUpdaterThread(NS_NewRunnableFunction( + RunOnUpdaterThread(aLayersId, NS_NewRunnableFunction( "APZUpdater::GetAPZTestData", [&]() { AutoCompleteTask notifier(&waiter); ret = apz->GetAPZTestData(aLayersId, aOutData); } )); // Wait until the task posted above has run and populated aOutData and ret @@ -278,17 +278,17 @@ APZUpdater::GetAPZTestData(LayersId aLay void APZUpdater::SetTestAsyncScrollOffset(LayersId aLayersId, const FrameMetrics::ViewID& aScrollId, const CSSPoint& aOffset) { MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); RefPtr apz = mApz; - RunOnUpdaterThread(NS_NewRunnableFunction( + RunOnUpdaterThread(aLayersId, NS_NewRunnableFunction( "APZUpdater::SetTestAsyncScrollOffset", [=]() { RefPtr apzc = apz->GetTargetAPZC(aLayersId, aScrollId); if (apzc) { apzc->SetTestAsyncScrollOffset(aOffset); } else { NS_WARNING("Unable to find APZC in SetTestAsyncScrollOffset"); } @@ -298,17 +298,17 @@ APZUpdater::SetTestAsyncScrollOffset(Lay void APZUpdater::SetTestAsyncZoom(LayersId aLayersId, const FrameMetrics::ViewID& aScrollId, const LayerToParentLayerScale& aZoom) { MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); RefPtr apz = mApz; - RunOnUpdaterThread(NS_NewRunnableFunction( + RunOnUpdaterThread(aLayersId, NS_NewRunnableFunction( "APZUpdater::SetTestAsyncZoom", [=]() { RefPtr apzc = apz->GetTargetAPZC(aLayersId, aScrollId); if (apzc) { apzc->SetTestAsyncZoom(aZoom); } else { NS_WARNING("Unable to find APZC in SetTestAsyncZoom"); } @@ -328,34 +328,34 @@ void APZUpdater::AssertOnUpdaterThread() const { if (APZThreadUtils::GetThreadAssertionsEnabled()) { MOZ_ASSERT(IsUpdaterThread()); } } void -APZUpdater::RunOnUpdaterThread(already_AddRefed aTask) +APZUpdater::RunOnUpdaterThread(LayersId aLayersId, already_AddRefed aTask) { RefPtr task = aTask; if (IsUpdaterThread()) { task->Run(); return; } if (UsingWebRenderUpdaterThread()) { // If the updater thread is a WebRender thread, and we're not on it // right now, save the task in the queue. We will run tasks from the queue // during the callback from the updater thread, which we trigger by the // call to WakeSceneBuilder. { // scope lock MutexAutoLock lock(mQueueLock); - mUpdaterQueue.push_back(task); + mUpdaterQueue.push_back(QueuedTask { aLayersId, task }); } RefPtr api = mApz->GetWebRenderAPI(); if (api) { api->WakeSceneBuilder(); } else { // Not sure if this can happen, but it might be possible. If it does, // the task is in the queue, but if we didn't get a WebRenderAPI it // might never run, or it might run later if we manage to get a @@ -379,21 +379,21 @@ APZUpdater::IsUpdaterThread() const { if (UsingWebRenderUpdaterThread()) { return PlatformThread::CurrentId() == *mUpdaterThreadId; } return CompositorThreadHolder::IsInCompositorThread(); } void -APZUpdater::RunOnControllerThread(already_AddRefed aTask) +APZUpdater::RunOnControllerThread(LayersId aLayersId, already_AddRefed aTask) { MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); - RunOnUpdaterThread(NewRunnableFunction( + RunOnUpdaterThread(aLayersId, NewRunnableFunction( "APZUpdater::RunOnControllerThread", &APZThreadUtils::RunOnControllerThread, Move(aTask))); } bool APZUpdater::UsingWebRenderUpdaterThread() const { @@ -421,65 +421,69 @@ APZUpdater::GetUpdater(const wr::WrWindo StaticMutexAutoLock lock(sWindowIdLock); auto it = sWindowIdMap.find(wr::AsUint64(aWindowId)); if (it != sWindowIdMap.end()) { updater = it->second; } return updater.forget(); } -bool -APZUpdater::IsQueueBlocked() const -{ - AssertOnUpdaterThread(); - - for (const auto& i : mEpochData) { - if (i.second.IsBlockingQueue()) { - return true; - } - } - return false; -} - void APZUpdater::ProcessQueue() { { // scope lock to check for emptiness MutexAutoLock lock(mQueueLock); if (mUpdaterQueue.empty()) { return; } } - // Note that running a task might update mEpochData, so we can't - // cache the result of IsQueueBlocked(). - while (!IsQueueBlocked()) { - RefPtr task; + std::deque blockedTasks; + while (true) { + QueuedTask task; { // scope lock to extract a task MutexAutoLock lock(mQueueLock); if (mUpdaterQueue.empty()) { + // If we're done processing mUpdaterQueue, swap the tasks that are + // still blocked back in and finish + std::swap(mUpdaterQueue, blockedTasks); break; } task = mUpdaterQueue.front(); mUpdaterQueue.pop_front(); } - task->Run(); + // We check the task to see if it is blocked. Note that while this + // ProcessQueue function is executing, a particular layers is cannot go + // from blocked to unblocked, because only CompleteSceneSwap can unblock + // a layers id, and that also runs on the updater thread. If somehow + // a layers id gets unblocked while we're processing the queue, then it + // might result in tasks getting executed out of order. + + auto it = mEpochData.find(task.mLayersId); + if (it != mEpochData.end() && it->second.IsBlocked()) { + // If this task is blocked, put it into the blockedTasks queue that + // we will replace mUpdaterQueue with + blockedTasks.push_back(task); + } else { + // Run and discard the task + task.mRunnable->Run(); + } } } APZUpdater::EpochState::EpochState() : mRequired{0} , mIsRoot(false) { } bool -APZUpdater::EpochState::IsBlockingQueue() const +APZUpdater::EpochState::IsBlocked() const { // The root is a special case because we basically assume it is "visible" // even before it is built for the first time. This is because building the // scene automatically makes it visible, and we need to make sure the APZ // scroll data gets applied atomically with that happening. // // Layer subtrees on the other hand do not automatically become visible upon // being built, because there must be a another layer tree update to change diff --git a/gfx/layers/ipc/APZCTreeManagerParent.cpp b/gfx/layers/ipc/APZCTreeManagerParent.cpp --- a/gfx/layers/ipc/APZCTreeManagerParent.cpp +++ b/gfx/layers/ipc/APZCTreeManagerParent.cpp @@ -38,17 +38,17 @@ APZCTreeManagerParent::ChildAdopted(RefP MOZ_ASSERT(aAPZUpdater->HasTreeManager(aAPZCTreeManager)); mTreeManager = Move(aAPZCTreeManager); mUpdater = Move(aAPZUpdater); } mozilla::ipc::IPCResult APZCTreeManagerParent::RecvSetKeyboardMap(const KeyboardMap& aKeyboardMap) { - mUpdater->RunOnControllerThread(NewRunnableMethod( + mUpdater->RunOnControllerThread(mLayersId, NewRunnableMethod( "layers::IAPZCTreeManager::SetKeyboardMap", mTreeManager, &IAPZCTreeManager::SetKeyboardMap, aKeyboardMap)); return IPC_OK(); } @@ -60,30 +60,31 @@ APZCTreeManagerParent::RecvZoomToRect( { if (aGuid.mLayersId != mLayersId) { // Guard against bad data from hijacked child processes NS_ERROR("Unexpected layers id in RecvZoomToRect; dropping message..."); return IPC_FAIL_NO_REASON(this); } mUpdater->RunOnControllerThread( + mLayersId, NewRunnableMethod( "layers::IAPZCTreeManager::ZoomToRect", mTreeManager, &IAPZCTreeManager::ZoomToRect, aGuid, aRect, aFlags)); return IPC_OK(); } mozilla::ipc::IPCResult APZCTreeManagerParent::RecvContentReceivedInputBlock( const uint64_t& aInputBlockId, const bool& aPreventDefault) { - mUpdater->RunOnControllerThread(NewRunnableMethod( + mUpdater->RunOnControllerThread(mLayersId, NewRunnableMethod( "layers::IAPZCTreeManager::ContentReceivedInputBlock", mTreeManager, &IAPZCTreeManager::ContentReceivedInputBlock, aInputBlockId, aPreventDefault)); return IPC_OK(); } @@ -96,16 +97,17 @@ APZCTreeManagerParent::RecvSetTargetAPZC for (size_t i = 0; i < aTargets.Length(); i++) { if (aTargets[i].mLayersId != mLayersId) { // Guard against bad data from hijacked child processes NS_ERROR("Unexpected layers id in RecvSetTargetAPZC; dropping message..."); return IPC_FAIL_NO_REASON(this); } } mUpdater->RunOnControllerThread( + mLayersId, NewRunnableMethod>>( "layers::IAPZCTreeManager::SetTargetAPZC", mTreeManager, &IAPZCTreeManager::SetTargetAPZC, aInputBlockId, aTargets)); @@ -125,30 +127,31 @@ APZCTreeManagerParent::RecvUpdateZoomCon mTreeManager->UpdateZoomConstraints(aGuid, aConstraints); return IPC_OK(); } mozilla::ipc::IPCResult APZCTreeManagerParent::RecvSetDPI(const float& aDpiValue) { - mUpdater->RunOnControllerThread(NewRunnableMethod( + mUpdater->RunOnControllerThread(mLayersId, NewRunnableMethod( "layers::IAPZCTreeManager::SetDPI", mTreeManager, &IAPZCTreeManager::SetDPI, aDpiValue)); return IPC_OK(); } mozilla::ipc::IPCResult APZCTreeManagerParent::RecvSetAllowedTouchBehavior( const uint64_t& aInputBlockId, nsTArray&& aValues) { mUpdater->RunOnControllerThread( + mLayersId, NewRunnableMethod>>( "layers::IAPZCTreeManager::SetAllowedTouchBehavior", mTreeManager, &IAPZCTreeManager::SetAllowedTouchBehavior, aInputBlockId, Move(aValues))); @@ -162,16 +165,17 @@ APZCTreeManagerParent::RecvStartScrollba { if (aGuid.mLayersId != mLayersId) { // Guard against bad data from hijacked child processes NS_ERROR("Unexpected layers id in RecvStartScrollbarDrag; dropping message..."); return IPC_FAIL_NO_REASON(this); } mUpdater->RunOnControllerThread( + mLayersId, NewRunnableMethod( "layers::IAPZCTreeManager::StartScrollbarDrag", mTreeManager, &IAPZCTreeManager::StartScrollbarDrag, aGuid, aDragMetrics)); return IPC_OK(); @@ -185,44 +189,47 @@ APZCTreeManagerParent::RecvStartAutoscro // Unlike RecvStartScrollbarDrag(), this message comes from the parent // process (via nsBaseWidget::mAPZC) rather than from the child process // (via TabChild::mApzcTreeManager), so there is no need to check the // layers id against mLayersId (and in any case, it wouldn't match, because // mLayersId stores the parent process's layers id, while nsBaseWidget is // sending the child process's layers id). mUpdater->RunOnControllerThread( + mLayersId, NewRunnableMethod( "layers::IAPZCTreeManager::StartAutoscroll", mTreeManager, &IAPZCTreeManager::StartAutoscroll, aGuid, aAnchorLocation)); return IPC_OK(); } mozilla::ipc::IPCResult APZCTreeManagerParent::RecvStopAutoscroll(const ScrollableLayerGuid& aGuid) { // See RecvStartAutoscroll() for why we don't check the layers id. mUpdater->RunOnControllerThread( + mLayersId, NewRunnableMethod( "layers::IAPZCTreeManager::StopAutoscroll", mTreeManager, &IAPZCTreeManager::StopAutoscroll, aGuid)); return IPC_OK(); } mozilla::ipc::IPCResult APZCTreeManagerParent::RecvSetLongTapEnabled(const bool& aLongTapEnabled) { mUpdater->RunOnControllerThread( + mLayersId, NewRunnableMethod( "layers::IAPZCTreeManager::SetLongTapEnabled", mTreeManager, &IAPZCTreeManager::SetLongTapEnabled, aLongTapEnabled)); return IPC_OK(); } diff --git a/gfx/layers/ipc/CompositorBridgeParent.cpp b/gfx/layers/ipc/CompositorBridgeParent.cpp --- a/gfx/layers/ipc/CompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CompositorBridgeParent.cpp @@ -617,17 +617,17 @@ CompositorBridgeParent::ActorDestroy(Act RemoveCompositor(mCompositorBridgeID); mCompositionManager = nullptr; MOZ_ASSERT((mApzSampler != nullptr) == (mApzcTreeManager != nullptr)); MOZ_ASSERT((mApzUpdater != nullptr) == (mApzcTreeManager != nullptr)); if (mApzUpdater) { mApzSampler = nullptr; - mApzUpdater->ClearTree(); + mApzUpdater->ClearTree(mRootLayerTreeID); mApzUpdater = nullptr; mApzcTreeManager = nullptr; } { // scope lock MonitorAutoLock lock(*sIndirectLayerTreesLock); sIndirectLayerTrees.erase(mRootLayerTreeID); } diff --git a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp --- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp @@ -128,19 +128,20 @@ CrossProcessCompositorBridgeParent::Allo CompositorBridgeParent::LayerTreeState& state = sIndirectLayerTrees[aLayersId]; // If the widget has shutdown its compositor, we may not have had a chance yet // to unmap our layers id, and we could get here without a parent compositor. // In this case return an empty APZCTM. if (!state.mParent) { // Note: we immediately call ClearTree since otherwise the APZCTM will // retain a reference to itself, through the checkerboard observer. - RefPtr temp = new APZCTreeManager(LayersId{0}); + LayersId dummyId{0}; + RefPtr temp = new APZCTreeManager(dummyId); RefPtr tempUpdater = new APZUpdater(temp); - tempUpdater->ClearTree(); + tempUpdater->ClearTree(dummyId); return new APZCTreeManagerParent(aLayersId, temp, tempUpdater); } state.mParent->AllocateAPZCTreeManagerParent(lock, aLayersId, state); return state.mApzcTreeManagerParent; } bool CrossProcessCompositorBridgeParent::DeallocPAPZCTreeManagerParent(PAPZCTreeManagerParent* aActor)