From 2292edf20cb6f9aa98ded38e84a5225de838a830 Mon Sep 17 00:00:00 2001 From: sotaro Date: Thu, 29 Jun 2017 18:06:11 -0700 Subject: [PATCH] Bug 1335335 - Tab move between different windows does not work when e10s is enabled r=nical When the tab move happens, related non-root WebRenderBridgeParent is updated as to render to different webrender instance. webrender does not support of sharing resources and keys yet. Then when the tab move happens, the patch just removes all keys and resources that belongs to previous webrender. Ideally all resources that belong to WebRenderBridgeParent should be reallocated in an update webrender. But the patch does not do it, instead it just request WebRenderBridgeChild to re-allocate all resources again for simplicity. Performance improvement will happen in a future patch. This patch support only tab move that uses only raw data external images. Support of native texture external images will happen in a future patch. --- gfx/layers/ipc/CompositorBridgeParent.cpp | 12 ++ .../CrossProcessCompositorBridgeParent.cpp | 11 +- gfx/layers/ipc/PWebRenderBridge.ipdl | 5 +- gfx/layers/wr/WebRenderBridgeChild.cpp | 19 ++- gfx/layers/wr/WebRenderBridgeChild.h | 2 + gfx/layers/wr/WebRenderBridgeParent.cpp | 145 ++++++++++++++++-- gfx/layers/wr/WebRenderBridgeParent.h | 20 ++- gfx/layers/wr/WebRenderCompositableHolder.cpp | 13 +- 8 files changed, 197 insertions(+), 30 deletions(-) diff --git a/gfx/layers/ipc/CompositorBridgeParent.cpp b/gfx/layers/ipc/CompositorBridgeParent.cpp index db734f7dd110..08e8c0ff21d5 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CompositorBridgeParent.cpp @@ -1651,6 +1651,18 @@ CompositorBridgeParent::RecvAdoptChild(const uint64_t& child) // by previous CompositorBridgeParent, since nsRefreshDriver might wait composition complete. ScheduleComposition(); } + if (mWrBridge && sIndirectLayerTrees[child].mWrBridge) { + sIndirectLayerTrees[child].mWrBridge->UpdateWebRender(mWrBridge->CompositorScheduler(), + mWrBridge->GetWebRenderAPI(), + mWrBridge->CompositableHolder(), + GetAnimationStorage(0)); + // Pretend we composited, since parent CompositorBridgeParent was replaced. + CrossProcessCompositorBridgeParent* cpcp = sIndirectLayerTrees[child].mCrossProcessParent; + if (cpcp) { + TimeStamp now = TimeStamp::Now(); + cpcp->DidComposite(child, now, now); + } + } parent = sIndirectLayerTrees[child].mApzcTreeManagerParent; } diff --git a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp index 8a05f48469ef..661663e38c23 100644 --- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp @@ -207,10 +207,19 @@ CrossProcessCompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::Pipeli MonitorAutoLock lock(*sIndirectLayerTreesLock); MOZ_ASSERT(sIndirectLayerTrees.find(layersId) != sIndirectLayerTrees.end()); MOZ_ASSERT(sIndirectLayerTrees[layersId].mWrBridge == nullptr); + WebRenderBridgeParent* parent = nullptr; CompositorBridgeParent* cbp = sIndirectLayerTrees[layersId].mParent; + if (!cbp) { + // This could happen when this function is called after CompositorBridgeParent destruction. + // This was observed during Tab move between different windows. + NS_WARNING("Created child without a matching parent?"); + parent = WebRenderBridgeParent::CeateDestroyed(); + *aIdNamespace = parent->GetIdNameSpace(); + *aTextureFactoryIdentifier = TextureFactoryIdentifier(LayersBackend::LAYERS_NONE); + return parent; + } WebRenderBridgeParent* root = sIndirectLayerTrees[cbp->RootLayerTreeId()].mWrBridge.get(); - WebRenderBridgeParent* parent = nullptr; RefPtr api = root->GetWebRenderAPI(); RefPtr holder = root->CompositableHolder(); RefPtr animStorage = cbp->GetAnimationStorage(0); diff --git a/gfx/layers/ipc/PWebRenderBridge.ipdl b/gfx/layers/ipc/PWebRenderBridge.ipdl index 9bc0b7229db0..d284ea3ab89a 100644 --- a/gfx/layers/ipc/PWebRenderBridge.ipdl +++ b/gfx/layers/ipc/PWebRenderBridge.ipdl @@ -56,10 +56,10 @@ parent: async DPBegin(IntSize aSize); async DPEnd(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId, WrSize aContentSize, ByteBuffer aDL, WrBuiltDisplayListDescriptor aDLDesc, - WebRenderScrollData aScrollData); + WebRenderScrollData aScrollData, uint32_t idNameSpace); sync DPSyncEnd(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId, WrSize aContentSize, ByteBuffer aDL, WrBuiltDisplayListDescriptor aDLDesc, - WebRenderScrollData aScrollData); + WebRenderScrollData aScrollData, uint32_t idNameSpace); async ParentCommands(WebRenderParentCommand[] commands); sync DPGetSnapshot(PTexture texture); async AddPipelineIdForAsyncCompositable(PipelineId aImageId, CompositableHandle aHandle); @@ -88,6 +88,7 @@ parent: async Shutdown(); sync ShutdownSync(); child: + async WrUpdated(uint32_t newIdNameSpace); async __delete__(); }; diff --git a/gfx/layers/wr/WebRenderBridgeChild.cpp b/gfx/layers/wr/WebRenderBridgeChild.cpp index 874835454d09..8ee419ce79c7 100644 --- a/gfx/layers/wr/WebRenderBridgeChild.cpp +++ b/gfx/layers/wr/WebRenderBridgeChild.cpp @@ -113,10 +113,10 @@ WebRenderBridgeChild::DPEnd(wr::DisplayListBuilder &aBuilder, if (aIsSync) { this->SendDPSyncEnd(aSize, mParentCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId, - contentSize, dlData, dl.dl_desc, aScrollData); + contentSize, dlData, dl.dl_desc, aScrollData, mIdNamespace); } else { this->SendDPEnd(aSize, mParentCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId, - contentSize, dlData, dl.dl_desc, aScrollData); + contentSize, dlData, dl.dl_desc, aScrollData, mIdNamespace); } mParentCommands.Clear(); @@ -445,5 +445,20 @@ WebRenderBridgeChild::InForwarderThread() return NS_IsMainThread(); } +mozilla::ipc::IPCResult +WebRenderBridgeChild::RecvWrUpdated(const uint32_t& aNewIdNameSpace) +{ + // Update mIdNamespace to identify obsolete keys and messages by WebRenderBridgeParent. + // Since usage of invalid keys could cause crash in webrender. + mIdNamespace = aNewIdNameSpace; + // Remove all FontKeys since they are removed by WebRenderBridgeParent + for (auto iter = mFontKeys.Iter(); !iter.Done(); iter.Next()) { + SendDeleteFont(iter.Data()); + } + mFontKeys.Clear(); + GetCompositorBridgeChild()->RecvInvalidateLayers(wr::AsUint64(mPipelineId)); + return IPC_OK(); +} + } // namespace layers } // namespace mozilla diff --git a/gfx/layers/wr/WebRenderBridgeChild.h b/gfx/layers/wr/WebRenderBridgeChild.h index d63e729b0cfc..a965ad5cd45a 100644 --- a/gfx/layers/wr/WebRenderBridgeChild.h +++ b/gfx/layers/wr/WebRenderBridgeChild.h @@ -141,6 +141,8 @@ private: void ActorDestroy(ActorDestroyReason why) override; + virtual mozilla::ipc::IPCResult RecvWrUpdated(const uint32_t& aNewIdNameSpace) override; + void AddIPDLReference() { MOZ_ASSERT(mIPCOpen == false); mIPCOpen = true; diff --git a/gfx/layers/wr/WebRenderBridgeParent.cpp b/gfx/layers/wr/WebRenderBridgeParent.cpp index 86bddc13cec3..cdd40d75fa83 100644 --- a/gfx/layers/wr/WebRenderBridgeParent.cpp +++ b/gfx/layers/wr/WebRenderBridgeParent.cpp @@ -26,6 +26,7 @@ #include "mozilla/layers/WebRenderImageHost.h" #include "mozilla/layers/WebRenderTextureHost.h" #include "mozilla/TimeStamp.h" +#include "mozilla/Unused.h" #include "mozilla/webrender/RenderThread.h" #include "mozilla/widget/CompositorWidget.h" @@ -137,6 +138,24 @@ WebRenderBridgeParent::WebRenderBridgeParent(CompositorBridgeParentBase* aCompos } } +WebRenderBridgeParent::WebRenderBridgeParent() + : mCompositorBridge(nullptr) + , mChildLayerObserverEpoch(0) + , mParentLayerObserverEpoch(0) + , mWrEpoch(0) + , mIdNameSpace(AllocIdNameSpace()) + , mPaused(false) + , mDestroyed(true) + , mForceRendering(false) +{ +} + +/* static */ WebRenderBridgeParent* +WebRenderBridgeParent::CeateDestroyed() +{ + return new WebRenderBridgeParent(); +} + WebRenderBridgeParent::~WebRenderBridgeParent() { } @@ -206,6 +225,12 @@ WebRenderBridgeParent::RecvAddImage(const wr::ImageKey& aImageKey, if (mDestroyed) { return IPC_OK(); } + + // Check if key is obsoleted. + if (aImageKey.mNamespace != mIdNameSpace) { + return IPC_OK(); + } + MOZ_ASSERT(mApi); MOZ_ASSERT(mActiveImageKeys.find(wr::AsUint64(aImageKey)) == mActiveImageKeys.end()); @@ -227,6 +252,12 @@ WebRenderBridgeParent::RecvAddBlobImage(const wr::ImageKey& aImageKey, if (mDestroyed) { return IPC_OK(); } + + // Check if key is obsoleted. + if (aImageKey.mNamespace != mIdNameSpace) { + return IPC_OK(); + } + MOZ_ASSERT(mApi); MOZ_ASSERT(mActiveImageKeys.find(wr::AsUint64(aImageKey)) == mActiveImageKeys.end()); @@ -246,6 +277,12 @@ WebRenderBridgeParent::RecvAddRawFont(const wr::FontKey& aFontKey, if (mDestroyed) { return IPC_OK(); } + + // Check if key is obsoleted. + if (aFontKey.mNamespace != mIdNameSpace) { + return IPC_OK(); + } + MOZ_ASSERT(mApi); MOZ_ASSERT(mFontKeys.find(wr::AsUint64(aFontKey)) == mFontKeys.end()); @@ -264,6 +301,11 @@ WebRenderBridgeParent::RecvDeleteFont(const wr::FontKey& aFontKey) } MOZ_ASSERT(mApi); + // Check if key is obsoleted. + if (aFontKey.mNamespace != mIdNameSpace) { + return IPC_OK(); + } + if (mFontKeys.find(wr::AsUint64(aFontKey)) != mFontKeys.end()) { mFontKeys.erase(wr::AsUint64(aFontKey)); mApi->DeleteFont(aFontKey); @@ -284,6 +326,12 @@ WebRenderBridgeParent::RecvUpdateImage(const wr::ImageKey& aImageKey, return IPC_OK(); } MOZ_ASSERT(mApi); + + // Check if key is obsoleted. + if (aImageKey.mNamespace != mIdNameSpace) { + return IPC_OK(); + } + wr::ImageDescriptor descriptor(aSize, aFormat); mApi->UpdateImageBuffer(aImageKey, descriptor, aBuffer.AsSlice()); @@ -297,6 +345,12 @@ WebRenderBridgeParent::RecvDeleteImage(const wr::ImageKey& aImageKey) return IPC_OK(); } MOZ_ASSERT(mApi); + + // Check if key is obsoleted. + if (aImageKey.mNamespace != mIdNameSpace) { + return IPC_OK(); + } + if (mActiveImageKeys.find(wr::AsUint64(aImageKey)) != mActiveImageKeys.end()) { mActiveImageKeys.erase(wr::AsUint64(aImageKey)); mKeysToDelete.push_back(aImageKey); @@ -344,7 +398,8 @@ WebRenderBridgeParent::HandleDPEnd(const gfx::IntSize& aSize, const WrSize& aContentSize, const ByteBuffer& dl, const WrBuiltDisplayListDescriptor& dlDesc, - const WebRenderScrollData& aScrollData) + const WebRenderScrollData& aScrollData, + const uint32_t& aIdNameSpace) { AutoProfilerTracing tracing("Paint", "DPTransaction"); UpdateFwdTransactionId(aFwdTransactionId); @@ -362,7 +417,7 @@ WebRenderBridgeParent::HandleDPEnd(const gfx::IntSize& aSize, ++mWrEpoch; // Update webrender epoch ProcessWebRenderCommands(aSize, aCommands, wr::NewEpoch(mWrEpoch), - aContentSize, dl, dlDesc); + aContentSize, dl, dlDesc, aIdNameSpace); HoldPendingTransactionId(mWrEpoch, aTransactionId); mScrollData = aScrollData; @@ -449,13 +504,14 @@ WebRenderBridgeParent::RecvDPEnd(const gfx::IntSize& aSize, const WrSize& aContentSize, const ByteBuffer& dl, const WrBuiltDisplayListDescriptor& dlDesc, - const WebRenderScrollData& aScrollData) + const WebRenderScrollData& aScrollData, + const uint32_t& aIdNameSpace) { if (mDestroyed) { return IPC_OK(); } HandleDPEnd(aSize, Move(aCommands), Move(aToDestroy), aFwdTransactionId, aTransactionId, - aContentSize, dl, dlDesc, aScrollData); + aContentSize, dl, dlDesc, aScrollData, aIdNameSpace); return IPC_OK(); } @@ -468,13 +524,14 @@ WebRenderBridgeParent::RecvDPSyncEnd(const gfx::IntSize &aSize, const WrSize& aContentSize, const ByteBuffer& dl, const WrBuiltDisplayListDescriptor& dlDesc, - const WebRenderScrollData& aScrollData) + const WebRenderScrollData& aScrollData, + const uint32_t& aIdNameSpace) { if (mDestroyed) { return IPC_OK(); } HandleDPEnd(aSize, Move(aCommands), Move(aToDestroy), aFwdTransactionId, aTransactionId, - aContentSize, dl, dlDesc, aScrollData); + aContentSize, dl, dlDesc, aScrollData, aIdNameSpace); return IPC_OK(); } @@ -497,6 +554,10 @@ WebRenderBridgeParent::ProcessWebRenderParentCommands(InfallibleTArray keys(&op.key(), 1); + // Check if key is obsoleted. + if (keys[0].mNamespace != mIdNameSpace) { + break; + } MOZ_ASSERT(mExternalImageIds.Get(wr::AsUint64(op.externalImageId())).get()); MOZ_ASSERT(mActiveImageKeys.find(wr::AsUint64(keys[0])) == mActiveImageKeys.end()); mActiveImageKeys.insert(wr::AsUint64(keys[0])); @@ -582,11 +643,18 @@ void WebRenderBridgeParent::ProcessWebRenderCommands(const gfx::IntSize &aSize, InfallibleTArray& aCommands, const wr::Epoch& aEpoch, const WrSize& aContentSize, const ByteBuffer& dl, - const WrBuiltDisplayListDescriptor& dlDesc) + const WrBuiltDisplayListDescriptor& dlDesc, + const uint32_t& aIdNameSpace) { mCompositableHolder->SetCompositionTime(TimeStamp::Now()); ProcessWebRenderParentCommands(aCommands); + // The command is obsoleted. + // Do not set the command to webrender since it causes crash in webrender. + if (mIdNameSpace != aIdNameSpace) { + return; + } + if (mWidget) { LayoutDeviceIntSize size = mWidget->GetClientSize(); mApi->SetWindowParameters(size); @@ -673,13 +741,11 @@ WebRenderBridgeParent::RecvAddPipelineIdForAsyncCompositable(const wr::PipelineI } RefPtr host = imageBridge->FindCompositable(aHandle); if (!host) { - NS_ERROR("CompositableHost not found in the map!"); return IPC_FAIL_NO_REASON(this); } MOZ_ASSERT(host->AsWebRenderImageHost()); WebRenderImageHost* wrHost = host->AsWebRenderImageHost(); if (!wrHost) { - NS_ERROR("Incompatible CompositableHost"); return IPC_OK(); } @@ -697,12 +763,13 @@ WebRenderBridgeParent::RecvRemovePipelineIdForAsyncCompositable(const wr::Pipeli return IPC_OK(); } - MOZ_ASSERT(mAsyncCompositables.Get(wr::AsUint64(aPipelineId)).get()); WebRenderImageHost* wrHost = mAsyncCompositables.Get(wr::AsUint64(aPipelineId)).get(); - if (wrHost) { - wrHost->ClearWrBridge(); - mCompositableHolder->RemoveAsyncImagePipeline(mApi, aPipelineId); + if (!wrHost) { + return IPC_OK(); } + + wrHost->ClearWrBridge(); + mCompositableHolder->RemoveAsyncImagePipeline(mApi, aPipelineId); mAsyncCompositables.Remove(wr::AsUint64(aPipelineId)); return IPC_OK(); } @@ -720,7 +787,6 @@ WebRenderBridgeParent::RecvAddExternalImageIdForCompositable(const ExternalImage MOZ_ASSERT(host->AsWebRenderImageHost()); WebRenderImageHost* wrHost = host->AsWebRenderImageHost(); if (!wrHost) { - NS_ERROR("Incompatible CompositableHost"); return IPC_OK(); } @@ -736,11 +802,12 @@ WebRenderBridgeParent::RecvRemoveExternalImageId(const ExternalImageId& aImageId if (mDestroyed) { return IPC_OK(); } - MOZ_ASSERT(mExternalImageIds.Get(wr::AsUint64(aImageId)).get()); WebRenderImageHost* wrHost = mExternalImageIds.Get(wr::AsUint64(aImageId)).get(); - if (wrHost) { - wrHost->ClearWrBridge(); + if (!wrHost) { + return IPC_OK(); } + + wrHost->ClearWrBridge(); mExternalImageIds.Remove(wr::AsUint64(aImageId)); return IPC_OK(); @@ -766,6 +833,48 @@ WebRenderBridgeParent::RecvClearCachedResources() return IPC_OK(); } +void +WebRenderBridgeParent::UpdateWebRender(CompositorVsyncScheduler* aScheduler, + wr::WebRenderAPI* aApi, + WebRenderCompositableHolder* aHolder, + CompositorAnimationStorage* aAnimStorage) +{ + MOZ_ASSERT(!mWidget); + MOZ_ASSERT(aScheduler); + MOZ_ASSERT(aApi); + MOZ_ASSERT(aHolder); + MOZ_ASSERT(aAnimStorage); + + if (mDestroyed) { + return; + } + + // Update id name space to identify obsoleted keys. + // Since usage of invalid keys could cause crash in webrender. + mIdNameSpace = AllocIdNameSpace(); + // XXX Remove it when webrender supports sharing/moving Keys between different webrender instances. + // XXX It requests client to update/reallocate webrender related resources, + // but parent side does not wait end of the update. + // The code could become simpler if we could serialise old keys deallocation and new keys allocation. + // But we do not do it, it is because client side deallocate old layers/webrender keys + // after new layers/webrender keys allocation. + // Without client side's layout refactoring, we could not finish all old layers/webrender keys removals + // before new layer/webrender keys allocation. In future, we could address the problem. + Unused << SendWrUpdated(mIdNameSpace); + CompositorBridgeParentBase* cBridge = mCompositorBridge; + // XXX Stop to clear resources if webreder supports resources sharing between different webrender instances. + ClearResources(); + mCompositorBridge = cBridge; + mCompositorScheduler = aScheduler; + mApi = aApi; + mCompositableHolder = aHolder; + mAnimStorage = aAnimStorage; + + ++mWrEpoch; // Update webrender epoch + // Register pipeline to updated CompositableHolder. + mCompositableHolder->AddPipeline(mPipelineId); +} + mozilla::ipc::IPCResult WebRenderBridgeParent::RecvForceComposite() { @@ -1128,6 +1237,8 @@ WebRenderBridgeParent::ClearResources() mApi->ClearRootDisplayList(wr::NewEpoch(mWrEpoch), mPipelineId); // Schedule composition to clean up Pipeline mCompositorScheduler->ScheduleComposition(); + // XXX webrender does not hava a way to delete a group of resources/keys, + // then delete keys one by one. for (std::unordered_set::iterator iter = mFontKeys.begin(); iter != mFontKeys.end(); iter++) { mApi->DeleteFont(wr::AsFontKey(*iter)); } diff --git a/gfx/layers/wr/WebRenderBridgeParent.h b/gfx/layers/wr/WebRenderBridgeParent.h index 194a0f2cf618..352d003779e4 100644 --- a/gfx/layers/wr/WebRenderBridgeParent.h +++ b/gfx/layers/wr/WebRenderBridgeParent.h @@ -55,6 +55,8 @@ public: RefPtr&& aHolder, RefPtr&& aAnimStorage); + static WebRenderBridgeParent* CeateDestroyed(); + wr::PipelineId PipelineId() { return mPipelineId; } wr::WebRenderAPI* GetWebRenderAPI() { return mApi; } wr::Epoch WrEpoch() { return wr::NewEpoch(mWrEpoch); } @@ -99,7 +101,8 @@ public: const WrSize& aContentSize, const ByteBuffer& dl, const WrBuiltDisplayListDescriptor& dlDesc, - const WebRenderScrollData& aScrollData) override; + const WebRenderScrollData& aScrollData, + const uint32_t& aIdNameSpace) override; mozilla::ipc::IPCResult RecvDPSyncEnd(const gfx::IntSize& aSize, InfallibleTArray&& aCommands, InfallibleTArray&& aToDestroy, @@ -108,7 +111,8 @@ public: const WrSize& aContentSize, const ByteBuffer& dl, const WrBuiltDisplayListDescriptor& dlDesc, - const WebRenderScrollData& aScrollData) override; + const WebRenderScrollData& aScrollData, + const uint32_t& aIdNameSpace) override; mozilla::ipc::IPCResult RecvParentCommands(nsTArray&& commands) override; mozilla::ipc::IPCResult RecvDPGetSnapshot(PTextureParent* aTexture) override; @@ -198,7 +202,13 @@ public: void ScheduleComposition(); + void UpdateWebRender(CompositorVsyncScheduler* aScheduler, + wr::WebRenderAPI* aApi, + WebRenderCompositableHolder* aHolder, + CompositorAnimationStorage* aAnimStorage); + private: + WebRenderBridgeParent(); virtual ~WebRenderBridgeParent(); uint64_t GetLayersId() const; @@ -209,7 +219,8 @@ private: const wr::Epoch& aEpoch, const WrSize& aContentSize, const ByteBuffer& dl, - const WrBuiltDisplayListDescriptor& dlDesc); + const WrBuiltDisplayListDescriptor& dlDesc, + const uint32_t& aIdNameSpace); void ClearResources(); uint64_t GetChildLayerObserverEpoch() const { return mChildLayerObserverEpoch; } bool ShouldParentObserveEpoch(); @@ -221,7 +232,8 @@ private: const WrSize& aContentSize, const ByteBuffer& dl, const WrBuiltDisplayListDescriptor& dlDesc, - const WebRenderScrollData& aScrollData); + const WebRenderScrollData& aScrollData, + const uint32_t& aIdNameSpace); mozilla::ipc::IPCResult HandleShutdown(); void AdvanceAnimations(); diff --git a/gfx/layers/wr/WebRenderCompositableHolder.cpp b/gfx/layers/wr/WebRenderCompositableHolder.cpp index 0ea0ccbd9079..e008ef580683 100644 --- a/gfx/layers/wr/WebRenderCompositableHolder.cpp +++ b/gfx/layers/wr/WebRenderCompositableHolder.cpp @@ -66,8 +66,15 @@ WebRenderCompositableHolder::AddPipeline(const wr::PipelineId& aPipelineId) } uint64_t id = wr::AsUint64(aPipelineId); - MOZ_ASSERT(!mPipelineTexturesHolders.Get(id)); - PipelineTexturesHolder* holder = new PipelineTexturesHolder(); + PipelineTexturesHolder* holder = mPipelineTexturesHolders.Get(wr::AsUint64(aPipelineId)); + if(holder) { + // This could happen during tab move between different windows. + // Previously removed holder could be still alive for waiting destroyed. + MOZ_ASSERT(holder->mDestroyedEpoch.isSome()); + holder->mDestroyedEpoch = Nothing(); // Revive holder + return; + } + holder = new PipelineTexturesHolder(); mPipelineTexturesHolders.Put(id, holder); } @@ -83,7 +90,6 @@ WebRenderCompositableHolder::RemovePipeline(const wr::PipelineId& aPipelineId, c if (!holder) { return; } - MOZ_ASSERT(holder->mDestroyedEpoch.isNothing()); holder->mDestroyedEpoch = Some(aEpoch); } @@ -135,7 +141,6 @@ WebRenderCompositableHolder::UpdateAsyncImagePipeline(const wr::PipelineId& aPip return; } AsyncImagePipelineHolder* holder = mAsyncImagePipelineHolders.Get(wr::AsUint64(aPipelineId)); - MOZ_ASSERT(holder); if (!holder) { return; }