From bb09834391e2a95c164aab811a0e2487d0b570ff Mon Sep 17 00:00:00 2001 From: Alexis Beingessner Date: Wed, 24 Jul 2019 14:10:56 +0000 Subject: [PATCH] Bug 1547351 - Automatically set content process render root r=kats This implements the idea of automatically setting a content proc's render root based on the render root enclosing the iframe that points to it. There was a bit of cleanup in here that was a bit tricky to extract from the core patch revolving around how we use the Api(...) helper. This was to avoid the situation where we use the Api(...) helper before our render root is initialized, when we don't actually have to. I.e., when we just want the root WebRenderAPI in all cases. An alternative to this approach could be to fully built out the WebRender transactions and just queue those up to be sent. However, transaction building has various side effects which are committed before the transaction is actually sent, so we would have to build out some scheme for deferring those as well. This seemed simpler. Patch primarily written by :dthayer Differential Revision: https://phabricator.services.mozilla.com/D37078 --HG-- extra : moz-landing-system : lando --- .../components/extensions/ExtensionPopups.jsm | 1 - gfx/layers/FrameMetrics.h | 4 +- gfx/layers/Layers.cpp | 15 +- gfx/layers/ScrollableLayerGuid.h | 1 + gfx/layers/apz/src/APZUpdater.cpp | 36 +- gfx/layers/ipc/PWebRenderBridge.ipdl | 5 +- gfx/layers/wr/RenderRootTypes.cpp | 45 +- gfx/layers/wr/RenderRootTypes.h | 14 + gfx/layers/wr/WebRenderBridgeChild.cpp | 21 +- gfx/layers/wr/WebRenderBridgeChild.h | 1 - gfx/layers/wr/WebRenderBridgeParent.cpp | 455 ++++++++++++++---- gfx/layers/wr/WebRenderBridgeParent.h | 85 +++- gfx/layers/wr/WebRenderLayerManager.cpp | 11 +- gfx/layers/wr/WebRenderScrollData.cpp | 27 +- gfx/layers/wr/WebRenderScrollData.h | 6 +- gfx/webrender_bindings/WebRenderAPI.cpp | 3 + gfx/webrender_bindings/WebRenderAPI.h | 1 + 17 files changed, 554 insertions(+), 177 deletions(-) diff --git a/browser/components/extensions/ExtensionPopups.jsm b/browser/components/extensions/ExtensionPopups.jsm index 99041143f51f..eebb652e5efe 100644 --- a/browser/components/extensions/ExtensionPopups.jsm +++ b/browser/components/extensions/ExtensionPopups.jsm @@ -293,7 +293,6 @@ class BasePopup { if (this.extension.remote) { browser.setAttribute("remote", "true"); browser.setAttribute("remoteType", E10SUtils.EXTENSION_REMOTE_TYPE); - browser.setAttribute("renderroot", "content"); } // We only need flex sizing for the sake of the slide-in sub-views of the diff --git a/gfx/layers/FrameMetrics.h b/gfx/layers/FrameMetrics.h index 6deac644c182..de79ad2517fd 100644 --- a/gfx/layers/FrameMetrics.h +++ b/gfx/layers/FrameMetrics.h @@ -8,7 +8,6 @@ #define GFX_FRAMEMETRICS_H #include // for uint8_t, uint32_t, uint64_t -#include #include "Units.h" // for CSSRect, CSSPixel, etc #include "mozilla/DefineEnum.h" // for MOZ_DEFINE_ENUM #include "mozilla/HashFunctions.h" // for HashGeneric @@ -21,6 +20,7 @@ #include "mozilla/layers/ScrollableLayerGuid.h" // for ScrollableLayerGuid #include "mozilla/StaticPtr.h" // for StaticAutoPtr #include "mozilla/TimeStamp.h" // for TimeStamp +#include "nsDataHashtable.h" // for nsDataHashtable #include "nsString.h" #include "mozilla/ServoStyleConsts.h" #include "PLDHashTable.h" // for PLDHashNumber @@ -1099,7 +1099,7 @@ struct ScrollMetadata { // Please add new fields above this comment. }; -typedef std::map +typedef nsDataHashtable ScrollUpdatesMap; } // namespace layers diff --git a/gfx/layers/Layers.cpp b/gfx/layers/Layers.cpp index a05e84f14d05..106dda1e3936 100644 --- a/gfx/layers/Layers.cpp +++ b/gfx/layers/Layers.cpp @@ -2241,7 +2241,7 @@ bool LayerManager::SetPendingScrollUpdateForNextTransaction( wr::RenderRoot renderRoot = (GetBackendType() == LayersBackend::LAYERS_WR) ? aRenderRoot : wr::RenderRoot::Default; - mPendingScrollUpdates[renderRoot][aScrollId] = aUpdateInfo; + mPendingScrollUpdates[renderRoot].Put(aScrollId, aUpdateInfo); return true; } @@ -2250,11 +2250,8 @@ Maybe LayerManager::GetPendingScrollInfoUpdate( // This never gets called for WebRenderLayerManager, so we assume that all // pending scroll info updates are stored under the default RenderRoot. MOZ_ASSERT(GetBackendType() != LayersBackend::LAYERS_WR); - auto it = mPendingScrollUpdates[wr::RenderRoot::Default].find(aScrollId); - if (it != mPendingScrollUpdates[wr::RenderRoot::Default].end()) { - return Some(it->second); - } - return Nothing(); + auto p = mPendingScrollUpdates[wr::RenderRoot::Default].Lookup(aScrollId); + return p ? Some(p.Data()) : Nothing(); } std::unordered_set @@ -2262,10 +2259,10 @@ LayerManager::ClearPendingScrollInfoUpdate() { std::unordered_set scrollIds; for (auto renderRoot : wr::kRenderRoots) { auto& updates = mPendingScrollUpdates[renderRoot]; - for (const auto& update : updates) { - scrollIds.insert(update.first); + for (auto it = updates.Iter(); !it.Done(); it.Next()) { + scrollIds.insert(it.Key()); } - updates.clear(); + updates.Clear(); } return scrollIds; } diff --git a/gfx/layers/ScrollableLayerGuid.h b/gfx/layers/ScrollableLayerGuid.h index 497786bce1db..27291d3995e5 100644 --- a/gfx/layers/ScrollableLayerGuid.h +++ b/gfx/layers/ScrollableLayerGuid.h @@ -27,6 +27,7 @@ namespace layers { struct ScrollableLayerGuid { // We use IDs to identify frames across processes. typedef uint64_t ViewID; + typedef nsUint64HashKey ViewIDHashKey; static const ViewID NULL_SCROLL_ID; // This container layer does not scroll. static const ViewID START_SCROLL_ID = 2; // This is the ID that scrolling // subframes will begin at. diff --git a/gfx/layers/apz/src/APZUpdater.cpp b/gfx/layers/apz/src/APZUpdater.cpp index 2a7e7dd1300a..e7da681da269 100644 --- a/gfx/layers/apz/src/APZUpdater.cpp +++ b/gfx/layers/apz/src/APZUpdater.cpp @@ -204,22 +204,24 @@ void APZUpdater::UpdateScrollDataAndTreeState( } self->mEpochData[aOriginatingWrRootId].mRequired = aEpoch; })); - RunOnUpdaterThread(UpdaterQueueSelector(aOriginatingWrRootId), - NS_NewRunnableFunction( - "APZUpdater::UpdateHitTestingTree", - [=, aScrollData = std::move(aScrollData)]() { - self->mScrollData[aOriginatingWrRootId] = - aScrollData; - auto root = self->mScrollData.find(aRootLayerTreeId); - if (root == self->mScrollData.end()) { - return; - } - self->mApz->UpdateHitTestingTree( - WebRenderScrollDataWrapper( - *self, aRootLayerTreeId, &(root->second)), - aScrollData.IsFirstPaint(), aOriginatingWrRootId, - aScrollData.GetPaintSequenceNumber()); - })); + RunOnUpdaterThread( + UpdaterQueueSelector(aOriginatingWrRootId), + NS_NewRunnableFunction( + "APZUpdater::UpdateHitTestingTree", + [=, aScrollData = std::move(aScrollData)]() mutable { + auto isFirstPaint = aScrollData.IsFirstPaint(); + auto paintSequenceNumber = aScrollData.GetPaintSequenceNumber(); + + self->mScrollData[aOriginatingWrRootId] = std::move(aScrollData); + auto root = self->mScrollData.find(aRootLayerTreeId); + if (root == self->mScrollData.end()) { + return; + } + self->mApz->UpdateHitTestingTree( + WebRenderScrollDataWrapper(*self, aRootLayerTreeId, + &(root->second)), + isFirstPaint, aOriginatingWrRootId, paintSequenceNumber); + })); } void APZUpdater::UpdateScrollOffsets(WRRootId aRootLayerTreeId, @@ -231,7 +233,7 @@ void APZUpdater::UpdateScrollOffsets(WRRootId aRootLayerTreeId, RunOnUpdaterThread(UpdaterQueueSelector(aOriginatingWrRootId), NS_NewRunnableFunction( "APZUpdater::UpdateScrollOffsets", - [=, updates = std::move(aUpdates)]() { + [=, updates = std::move(aUpdates)]() mutable { self->mScrollData[aOriginatingWrRootId].ApplyUpdates( updates, aPaintSequenceNumber); auto root = self->mScrollData.find(aRootLayerTreeId); diff --git a/gfx/layers/ipc/PWebRenderBridge.ipdl b/gfx/layers/ipc/PWebRenderBridge.ipdl index 551f16da07a6..c3f528c16a65 100644 --- a/gfx/layers/ipc/PWebRenderBridge.ipdl +++ b/gfx/layers/ipc/PWebRenderBridge.ipdl @@ -49,14 +49,13 @@ parent: async DeleteCompositorAnimations(uint64_t[] aIds); async SetDisplayList(RenderRootDisplayListData[] displayLists, OpDestroy[] toDestroy, uint64_t fwdTransactionId, TransactionId transactionId, - IdNamespace aIdNamespace, bool containsSVGGroup, + bool containsSVGGroup, VsyncId vsyncId, TimeStamp vsyncStartTime, TimeStamp refreshStartTime, TimeStamp txnStartTime, nsCString txnURL, TimeStamp fwdTime, CompositionPayload[] payloads); - async EmptyTransaction(FocusTarget focusTarget, uint32_t aPaintSequenceNumber, + async EmptyTransaction(FocusTarget focusTarget, RenderRootUpdates[] renderRootUpdates, OpDestroy[] toDestroy, uint64_t fwdTransactionId, TransactionId transactionId, - IdNamespace aIdNamespace, VsyncId vsyncId, TimeStamp vsyncStartTime, TimeStamp refreshStartTime, TimeStamp txnStartTime, nsCString txnURL, TimeStamp fwdTime, diff --git a/gfx/layers/wr/RenderRootTypes.cpp b/gfx/layers/wr/RenderRootTypes.cpp index 03b7be60493f..ef3b25dca7e2 100644 --- a/gfx/layers/wr/RenderRootTypes.cpp +++ b/gfx/layers/wr/RenderRootTypes.cpp @@ -14,11 +14,13 @@ namespace ipc { void IPDLParamTraits::Write( IPC::Message* aMsg, IProtocol* aActor, paramType&& aParam) { WriteIPDLParam(aMsg, aActor, aParam.mRenderRoot); + WriteIPDLParam(aMsg, aActor, aParam.mIdNamespace); WriteIPDLParam(aMsg, aActor, aParam.mRect); WriteIPDLParam(aMsg, aActor, aParam.mCommands); WriteIPDLParam(aMsg, aActor, aParam.mContentSize); WriteIPDLParam(aMsg, aActor, std::move(aParam.mDL)); WriteIPDLParam(aMsg, aActor, aParam.mDLDesc); + WriteIPDLParam(aMsg, aActor, aParam.mRemotePipelineIds); WriteIPDLParam(aMsg, aActor, aParam.mResourceUpdates); WriteIPDLParam(aMsg, aActor, aParam.mSmallShmems); WriteIPDLParam(aMsg, aActor, std::move(aParam.mLargeShmems)); @@ -29,11 +31,13 @@ bool IPDLParamTraits::Read( const IPC::Message* aMsg, PickleIterator* aIter, IProtocol* aActor, paramType* aResult) { if (ReadIPDLParam(aMsg, aIter, aActor, &aResult->mRenderRoot) && + ReadIPDLParam(aMsg, aIter, aActor, &aResult->mIdNamespace) && ReadIPDLParam(aMsg, aIter, aActor, &aResult->mRect) && ReadIPDLParam(aMsg, aIter, aActor, &aResult->mCommands) && ReadIPDLParam(aMsg, aIter, aActor, &aResult->mContentSize) && ReadIPDLParam(aMsg, aIter, aActor, &aResult->mDL) && ReadIPDLParam(aMsg, aIter, aActor, &aResult->mDLDesc) && + ReadIPDLParam(aMsg, aIter, aActor, &aResult->mRemotePipelineIds) && ReadIPDLParam(aMsg, aIter, aActor, &aResult->mResourceUpdates) && ReadIPDLParam(aMsg, aIter, aActor, &aResult->mSmallShmems) && ReadIPDLParam(aMsg, aIter, aActor, &aResult->mLargeShmems) && @@ -43,6 +47,41 @@ bool IPDLParamTraits::Read( return false; } +void WriteScrollUpdates(IPC::Message* aMsg, IProtocol* aActor, + layers::ScrollUpdatesMap& aParam) { + // ICK: we need to manually serialize this map because + // nsDataHashTable doesn't support it (and other maps cause other issues) + WriteIPDLParam(aMsg, aActor, aParam.Count()); + for (auto it = aParam.Iter(); !it.Done(); it.Next()) { + WriteIPDLParam(aMsg, aActor, it.Key()); + WriteIPDLParam(aMsg, aActor, it.Data()); + } +} + +bool ReadScrollUpdates(const IPC::Message* aMsg, PickleIterator* aIter, + IProtocol* aActor, layers::ScrollUpdatesMap* aResult) { + // Manually deserialize mScrollUpdates as a stream of K,V pairs + uint32_t count; + if (!ReadIPDLParam(aMsg, aIter, aActor, &count)) { + return false; + } + + layers::ScrollUpdatesMap map(count); + for (size_t i = 0; i < count; ++i) { + layers::ScrollableLayerGuid::ViewID key; + layers::ScrollUpdateInfo data; + if (!ReadIPDLParam(aMsg, aIter, aActor, &key) || + !ReadIPDLParam(aMsg, aIter, aActor, &data)) { + return false; + } + map.Put(key, data); + } + + MOZ_RELEASE_ASSERT(map.Count() == count); + *aResult = std::move(map); + return true; +} + void IPDLParamTraits::Write( IPC::Message* aMsg, IProtocol* aActor, paramType&& aParam) { WriteIPDLParam(aMsg, aActor, aParam.mRenderRoot); @@ -50,7 +89,8 @@ void IPDLParamTraits::Write( WriteIPDLParam(aMsg, aActor, aParam.mResourceUpdates); WriteIPDLParam(aMsg, aActor, aParam.mSmallShmems); WriteIPDLParam(aMsg, aActor, std::move(aParam.mLargeShmems)); - WriteIPDLParam(aMsg, aActor, aParam.mScrollUpdates); + WriteScrollUpdates(aMsg, aActor, aParam.mScrollUpdates); + WriteIPDLParam(aMsg, aActor, aParam.mPaintSequenceNumber); } bool IPDLParamTraits::Read( @@ -61,7 +101,8 @@ bool IPDLParamTraits::Read( ReadIPDLParam(aMsg, aIter, aActor, &aResult->mResourceUpdates) && ReadIPDLParam(aMsg, aIter, aActor, &aResult->mSmallShmems) && ReadIPDLParam(aMsg, aIter, aActor, &aResult->mLargeShmems) && - ReadIPDLParam(aMsg, aIter, aActor, &aResult->mScrollUpdates)) { + ReadScrollUpdates(aMsg, aIter, aActor, &aResult->mScrollUpdates) && + ReadIPDLParam(aMsg, aIter, aActor, &aResult->mPaintSequenceNumber)) { return true; } return false; diff --git a/gfx/layers/wr/RenderRootTypes.h b/gfx/layers/wr/RenderRootTypes.h index 1a195423a3a3..3dea57c1d15f 100644 --- a/gfx/layers/wr/RenderRootTypes.h +++ b/gfx/layers/wr/RenderRootTypes.h @@ -11,6 +11,7 @@ #include "mozilla/webrender/WebRenderTypes.h" #include "mozilla/layers/WebRenderMessages.h" #include "mozilla/layers/WebRenderScrollData.h" +#include "mozilla/Variant.h" namespace mozilla { @@ -18,11 +19,13 @@ namespace layers { struct RenderRootDisplayListData { wr::RenderRoot mRenderRoot; + wr::IdNamespace mIdNamespace; LayoutDeviceRect mRect; nsTArray mCommands; wr::LayoutSize mContentSize; Maybe mDL; wr::BuiltDisplayListDescriptor mDLDesc; + nsTArray mRemotePipelineIds; nsTArray mResourceUpdates; nsTArray mSmallShmems; nsTArray mLargeShmems; @@ -36,8 +39,19 @@ struct RenderRootUpdates { nsTArray mSmallShmems; nsTArray mLargeShmems; ScrollUpdatesMap mScrollUpdates; + uint32_t mPaintSequenceNumber; }; +struct ResourceUpdates { + nsTArray mResourceUpdates; + nsTArray mSmallShmems; + nsTArray mLargeShmems; +}; + +typedef Variant + RenderRootDeferredData; + } // namespace layers namespace ipc { diff --git a/gfx/layers/wr/WebRenderBridgeChild.cpp b/gfx/layers/wr/WebRenderBridgeChild.cpp index feafd8c5356a..ed0efd18b75a 100644 --- a/gfx/layers/wr/WebRenderBridgeChild.cpp +++ b/gfx/layers/wr/WebRenderBridgeChild.cpp @@ -122,6 +122,7 @@ void WebRenderBridgeChild::EndTransaction( (XRE_IsParentProcess() && StaticPrefs::gfx_webrender_split_render_roots_AtStartup())); renderRoot.mCommands = std::move(mParentCommands[renderRoot.mRenderRoot]); + renderRoot.mIdNamespace = mIdNamespace; } nsTArray payloads; @@ -129,11 +130,10 @@ void WebRenderBridgeChild::EndTransaction( mManager->TakeCompositionPayloads(payloads); } - this->SendSetDisplayList(std::move(aRenderRoots), mDestroyedActors, - GetFwdTransactionId(), aTransactionId, mIdNamespace, - aContainsSVGGroup, aVsyncId, aVsyncStartTime, - aRefreshStartTime, aTxnStartTime, aTxnURL, fwdTime, - payloads); + this->SendSetDisplayList( + std::move(aRenderRoots), mDestroyedActors, GetFwdTransactionId(), + aTransactionId, aContainsSVGGroup, aVsyncId, aVsyncStartTime, + aRefreshStartTime, aTxnStartTime, aTxnURL, fwdTime, payloads); // With multiple render roots, we may not have sent all of our // mParentCommands, so go ahead and go through our mParentCommands and ensure @@ -146,8 +146,8 @@ void WebRenderBridgeChild::EndTransaction( void WebRenderBridgeChild::EndEmptyTransaction( const FocusTarget& aFocusTarget, nsTArray& aRenderRootUpdates, - uint32_t aPaintSequenceNumber, TransactionId aTransactionId, - const mozilla::VsyncId& aVsyncId, const mozilla::TimeStamp& aVsyncStartTime, + TransactionId aTransactionId, const mozilla::VsyncId& aVsyncId, + const mozilla::TimeStamp& aVsyncStartTime, const mozilla::TimeStamp& aRefreshStartTime, const mozilla::TimeStamp& aTxnStartTime, const nsCString& aTxnURL) { MOZ_ASSERT(!mDestroyed); @@ -168,10 +168,9 @@ void WebRenderBridgeChild::EndEmptyTransaction( } this->SendEmptyTransaction( - aFocusTarget, aPaintSequenceNumber, std::move(aRenderRootUpdates), - mDestroyedActors, GetFwdTransactionId(), aTransactionId, mIdNamespace, - aVsyncId, aVsyncStartTime, aRefreshStartTime, aTxnStartTime, aTxnURL, - fwdTime, payloads); + aFocusTarget, std::move(aRenderRootUpdates), mDestroyedActors, + GetFwdTransactionId(), aTransactionId, aVsyncId, aVsyncStartTime, + aRefreshStartTime, aTxnStartTime, aTxnURL, fwdTime, payloads); // With multiple render roots, we may not have sent all of our // mParentCommands, so go ahead and go through our mParentCommands and ensure diff --git a/gfx/layers/wr/WebRenderBridgeChild.h b/gfx/layers/wr/WebRenderBridgeChild.h index f61448fb6fc8..0126090f72c2 100644 --- a/gfx/layers/wr/WebRenderBridgeChild.h +++ b/gfx/layers/wr/WebRenderBridgeChild.h @@ -82,7 +82,6 @@ class WebRenderBridgeChild final : public PWebRenderBridgeChild, const nsCString& aTxtURL); void EndEmptyTransaction(const FocusTarget& aFocusTarget, nsTArray& aRenderRootUpdates, - uint32_t aPaintSequenceNumber, TransactionId aTransactionId, const mozilla::VsyncId& aVsyncId, const mozilla::TimeStamp& aVsyncStartTime, diff --git a/gfx/layers/wr/WebRenderBridgeParent.cpp b/gfx/layers/wr/WebRenderBridgeParent.cpp index 34ca7c61e33d..07c34ad900c6 100644 --- a/gfx/layers/wr/WebRenderBridgeParent.cpp +++ b/gfx/layers/wr/WebRenderBridgeParent.cpp @@ -306,7 +306,6 @@ WebRenderBridgeParent::WebRenderBridgeParent( mWrEpoch{0}, mIdNamespace(aApis[0]->GetNamespace()), mRenderRootRectMutex("WebRenderBridgeParent::mRenderRootRectMutex"), - mRenderRoot(wr::RenderRoot::Default), mPaused(false), mDestroyed(false), mReceivedDisplayList(false), @@ -320,9 +319,9 @@ WebRenderBridgeParent::WebRenderBridgeParent( mCompositorScheduler = new CompositorVsyncScheduler(this, mWidget); } - if (!IsRootWebRenderBridgeParent() && - StaticPrefs::gfx_webrender_split_render_roots_AtStartup()) { - mRenderRoot = wr::RenderRoot::Content; + if (IsRootWebRenderBridgeParent() || + !StaticPrefs::gfx_webrender_split_render_roots_AtStartup()) { + mRenderRoot = Some(wr::RenderRoot::Default); } for (auto& api : aApis) { @@ -339,19 +338,196 @@ WebRenderBridgeParent::WebRenderBridgeParent(const wr::PipelineId& aPipelineId) mWrEpoch{0}, mIdNamespace{0}, mRenderRootRectMutex("WebRenderBridgeParent::mRenderRootRectMutex"), - mRenderRoot(wr::RenderRoot::Default), mPaused(false), mDestroyed(true), mReceivedDisplayList(false), mIsFirstPaint(false), mSkippedComposite(false) {} +WebRenderBridgeParent::~WebRenderBridgeParent() { + if (RefPtr root = GetRootWebRenderBridgeParent()) { + root->RemoveDeferredPipeline(mPipelineId); + } +} + +bool WebRenderBridgeParent::RenderRootIsValid(wr::RenderRoot aRenderRoot) { + if (StaticPrefs::gfx_webrender_split_render_roots_AtStartup() && + IsRootWebRenderBridgeParent()) { + return aRenderRoot <= wr::kHighestRenderRoot; + } else { + return aRenderRoot == wr::RenderRoot::Default; + } +} + +void WebRenderBridgeParent::RemoveDeferredPipeline(wr::PipelineId aPipelineId) { + MOZ_ASSERT(IsRootWebRenderBridgeParent()); + mPipelineRenderRoots.Remove(wr::AsUint64(aPipelineId)); + if (auto entry = mPipelineDeferredUpdates.Lookup(wr::AsUint64(aPipelineId))) { + RefPtr self = this; + for (auto& variant : entry.Data()) { + variant.match( + [=](RenderRootDisplayListData& x) { + wr::IpcResourceUpdateQueue::ReleaseShmems(self, x.mSmallShmems); + wr::IpcResourceUpdateQueue::ReleaseShmems(self, x.mLargeShmems); + }, + [=](RenderRootUpdates& x) { + wr::IpcResourceUpdateQueue::ReleaseShmems(self, x.mSmallShmems); + wr::IpcResourceUpdateQueue::ReleaseShmems(self, x.mLargeShmems); + }, + [=](ResourceUpdates& x) { + wr::IpcResourceUpdateQueue::ReleaseShmems(self, x.mSmallShmems); + wr::IpcResourceUpdateQueue::ReleaseShmems(self, x.mLargeShmems); + }, + [=](FocusTarget& x) {}); + } + entry.Remove(); + } +} + + /* static */ WebRenderBridgeParent* WebRenderBridgeParent::CreateDestroyed( const wr::PipelineId& aPipelineId) { return new WebRenderBridgeParent(aPipelineId); } +void WebRenderBridgeParent::PushDeferredPipelineData( + RenderRootDeferredData&& aDeferredData) { + MOZ_ASSERT(!IsRootWebRenderBridgeParent()); + if (RefPtr root = GetRootWebRenderBridgeParent()) { + uint64_t key = wr::AsUint64(mPipelineId); + root->mPipelineDeferredUpdates.LookupForAdd(key) + .OrInsert([]() { return nsTArray(); }) + .AppendElement(std::move(aDeferredData)); + } +} + +bool WebRenderBridgeParent::HandleDeferredPipelineData( + nsTArray& aDeferredData, + const TimeStamp& aTxnStartTime) { + MOZ_ASSERT(!IsRootWebRenderBridgeParent()); + for (auto& entry : aDeferredData) { + bool success = entry.match( + [&](RenderRootDisplayListData& data) { + // We ensure this with RenderRootIsValid before calling + // PushDeferredPipelineData: + MOZ_ASSERT(data.mRenderRoot == wr::RenderRoot::Default); + wr::Epoch wrEpoch = GetNextWrEpoch(); + bool validTransaction = data.mIdNamespace == mIdNamespace; + + if (!ProcessRenderRootDisplayListData(data, + wrEpoch, + aTxnStartTime, + validTransaction, + false)){ + return false; + } + + wr::IpcResourceUpdateQueue::ReleaseShmems(this, data.mSmallShmems); + wr::IpcResourceUpdateQueue::ReleaseShmems(this, data.mLargeShmems); + return true; + }, + [&](RenderRootUpdates& data) { + // We ensure this with RenderRootIsValid before calling + // PushDeferredPipelineData: + MOZ_ASSERT(data.mRenderRoot == wr::RenderRoot::Default); + bool scheduleComposite; + if (!ProcessEmptyTransactionUpdates(data, &scheduleComposite)) { + return false; + } + if (scheduleComposite) { + ScheduleGenerateFrame(Nothing()); + } + wr::IpcResourceUpdateQueue::ReleaseShmems(this, data.mSmallShmems); + wr::IpcResourceUpdateQueue::ReleaseShmems(this, data.mLargeShmems); + return true; + }, + [&](ResourceUpdates& data) { + wr::TransactionBuilder txn; + txn.SetLowPriority(!IsRootWebRenderBridgeParent()); + + if (!UpdateResources(data.mResourceUpdates, data.mSmallShmems, + data.mLargeShmems, txn)) { + return false; + } + + Api(wr::RenderRoot::Default)->SendTransaction(txn); + wr::IpcResourceUpdateQueue::ReleaseShmems(this, data.mSmallShmems); + wr::IpcResourceUpdateQueue::ReleaseShmems(this, data.mLargeShmems); + return true; + }, + [&](FocusTarget& data) { + UpdateAPZFocusState(data); + return true; + }); + + if (!success) { + return false; + } + } + aDeferredData.Clear(); + return true; +} + +bool WebRenderBridgeParent::MaybeHandleDeferredPipelineDataForPipeline( + wr::RenderRoot aRenderRoot, wr::PipelineId aPipelineId, + const TimeStamp& aTxnStartTime) { + MOZ_ASSERT(IsRootWebRenderBridgeParent()); + + uint64_t key = wr::AsUint64(aPipelineId); + auto entry = mPipelineRenderRoots.LookupForAdd(key); + if (!entry) { + entry.OrInsert([=]() { return aRenderRoot; }); + + CompositorBridgeParent::LayerTreeState* lts = + CompositorBridgeParent::GetIndirectShadowTree( + wr::AsLayersId(aPipelineId)); + if (!lts) { + return true; + } + RefPtr wrbp = lts->mWrBridge; + if (!wrbp) { + return true; + } + MOZ_ASSERT(wrbp->mRenderRoot.refOr(aRenderRoot) == aRenderRoot); + wrbp->mRenderRoot = Some(aRenderRoot); + + if (auto entry = mPipelineDeferredUpdates.Lookup(key)) { + wrbp->HandleDeferredPipelineData(entry.Data(), aTxnStartTime); + entry.Remove(); + + for (auto it = wrbp->mChildPipelines.Iter(); !it.Done(); it.Next()) { + if (!MaybeHandleDeferredPipelineDataForPipeline( + aRenderRoot, wr::AsPipelineId(it.Get()->GetKey()), + aTxnStartTime)) { + return false; + } + } + } + } + + return true; +} + +bool WebRenderBridgeParent::MaybeHandleDeferredPipelineData( + wr::RenderRoot aRenderRoot, const nsTArray& aPipelineIds, + const TimeStamp& aTxnStartTime) { + MOZ_ASSERT(IsRootWebRenderBridgeParent()); + if (!StaticPrefs::gfx_webrender_split_render_roots_AtStartup()) { + return true; + } + for (wr::PipelineId pipelineId : aPipelineIds) { + if (!MaybeHandleDeferredPipelineDataForPipeline(aRenderRoot, pipelineId, + aTxnStartTime)) { + return false; + } + + } + + return true; +} + + mozilla::ipc::IPCResult WebRenderBridgeParent::RecvEnsureConnected( TextureFactoryIdentifier* aTextureFactoryIdentifier, MaybeIdNamespace* aMaybeIdNamespace) { @@ -366,6 +542,16 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvEnsureConnected( *aTextureFactoryIdentifier = GetTextureFactoryIdentifier(); *aMaybeIdNamespace = Some(mIdNamespace); + if (!mRenderRoot) { + RefPtr root = GetRootWebRenderBridgeParent(); + if (!root) { + return IPC_FAIL(this, "Root WRBP is missing (shutting down?)"); + } + if (auto p = root->mPipelineRenderRoots.Lookup(wr::AsUint64(mPipelineId))) { + mRenderRoot.emplace(p.Data()); + } + } + return IPC_OK(); } @@ -736,7 +922,18 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvUpdateResources( return IPC_OK(); } - MOZ_RELEASE_ASSERT(aRenderRoot <= wr::kHighestRenderRoot); + if (!RenderRootIsValid(aRenderRoot)) { + return IPC_FAIL(this, "Received an invalid renderRoot"); + } + + if (!mRenderRoot) { + PushDeferredPipelineData(AsVariant(ResourceUpdates{ + std::move(aResourceUpdates), + std::move(aSmallShmems), + std::move(aLargeShmems), + })); + return IPC_OK(); + } wr::TransactionBuilder txn; txn.SetLowPriority(!IsRootWebRenderBridgeParent()); @@ -832,13 +1029,18 @@ WebRenderBridgeParent::GetRootWebRenderBridgeParent() const { } void WebRenderBridgeParent::UpdateAPZFocusState(const FocusTarget& aFocus) { + if (!mRenderRoot) { + PushDeferredPipelineData(AsVariant(aFocus)); + return; + } + CompositorBridgeParent* cbp = GetRootCompositorBridgeParent(); if (!cbp) { return; } LayersId rootLayersId = cbp->RootLayerTreeId(); if (RefPtr apz = cbp->GetAPZUpdater()) { - apz->UpdateFocusState(rootLayersId, WRRootId(GetLayersId(), mRenderRoot), + apz->UpdateFocusState(rootLayersId, WRRootId(GetLayersId(), *mRenderRoot), aFocus); } } @@ -962,14 +1164,57 @@ bool WebRenderBridgeParent::SetDisplayList( return true; } +bool WebRenderBridgeParent::ProcessRenderRootDisplayListData( + RenderRootDisplayListData& aDisplayList, + wr::Epoch aWrEpoch, + const TimeStamp& aTxnStartTime, + bool aValidTransaction, + bool aObserveLayersUpdate) { + wr::TransactionBuilder txn; + Maybe sender; + + // Note that this needs to happen before the display list transaction is + // sent to WebRender, so that the UpdateHitTestingTree call is guaranteed to + // be in the updater queue at the time that the scene swap completes. + if (aDisplayList.mScrollData) { + UpdateAPZScrollData(aWrEpoch, std::move(aDisplayList.mScrollData.ref()), + aDisplayList.mRenderRoot); + } + + MOZ_ASSERT(aDisplayList.mRenderRoot == wr::RenderRoot::Default || + IsRootWebRenderBridgeParent()); + auto renderRoot = aDisplayList.mRenderRoot; + + txn.SetLowPriority(!IsRootWebRenderBridgeParent()); + if (aValidTransaction) { + MOZ_ASSERT(aDisplayList.mIdNamespace == mIdNamespace); + sender.emplace(Api(renderRoot), &txn); + } + + if (NS_WARN_IF(!ProcessWebRenderParentCommands(aDisplayList.mCommands, txn, + renderRoot))) { + return false; + } + + if (aDisplayList.mDL && + !SetDisplayList(renderRoot, aDisplayList.mRect, aDisplayList.mContentSize, + std::move(aDisplayList.mDL.ref()), aDisplayList.mDLDesc, + aDisplayList.mResourceUpdates, aDisplayList.mSmallShmems, + aDisplayList.mLargeShmems, aTxnStartTime, txn, aWrEpoch, + aValidTransaction, aObserveLayersUpdate)) { + return false; + } + return true; +} + mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetDisplayList( nsTArray&& aDisplayLists, nsTArray&& aToDestroy, const uint64_t& aFwdTransactionId, - const TransactionId& aTransactionId, const wr::IdNamespace& aIdNamespace, - const bool& aContainsSVGGroup, const VsyncId& aVsyncId, - const TimeStamp& aVsyncStartTime, const TimeStamp& aRefreshStartTime, - const TimeStamp& aTxnStartTime, const nsCString& aTxnURL, - const TimeStamp& aFwdTime, nsTArray&& aPayloads) { + const TransactionId& aTransactionId, const bool& aContainsSVGGroup, + const VsyncId& aVsyncId, const TimeStamp& aVsyncStartTime, + const TimeStamp& aRefreshStartTime, const TimeStamp& aTxnStartTime, + const nsCString& aTxnURL, const TimeStamp& aFwdTime, + nsTArray&& aPayloads) { if (mDestroyed) { for (const auto& op : aToDestroy) { DestroyActor(op); @@ -978,9 +1223,13 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetDisplayList( } // Guard against malicious content processes - MOZ_RELEASE_ASSERT(aDisplayLists.Length() > 0); + if (aDisplayLists.Length() == 0) { + return IPC_FAIL(this, "Must send at least one RenderRootDisplayListData."); + } for (auto& displayList : aDisplayLists) { - MOZ_RELEASE_ASSERT(displayList.mRenderRoot <= wr::kHighestRenderRoot); + if (!RenderRootIsValid(displayList.mRenderRoot)) { + return IPC_FAIL(this, "Received an invalid renderRoot"); + } } if (!IsRootWebRenderBridgeParent()) { @@ -1000,7 +1249,6 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetDisplayList( mAsyncImageManager->SetCompositionTime(TimeStamp::Now()); mReceivedDisplayList = true; - bool observeLayersUpdate = ShouldParentObserveEpoch(); // The IsFirstPaint() flag should be the same for all the non-empty // scrolldata across all the renderroot display lists in a given @@ -1016,7 +1264,7 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetDisplayList( mIsFirstPaint = true; } } else { - auto firstNonEmpty = aDisplayLists[*firstScrollDataIndex].mScrollData; + auto& firstNonEmpty = aDisplayLists[*firstScrollDataIndex].mScrollData; // Ensure the flag is the same on all of them. MOZ_RELEASE_ASSERT(scrollData->IsFirstPaint() == firstNonEmpty->IsFirstPaint()); @@ -1024,47 +1272,50 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetDisplayList( } } - // aScrollData is moved into this function but that is not reflected by the - // function signature due to the way the IPDL generator works. We remove the - // const so that we can move this structure all the way to the desired - // destination. - // Also note that this needs to happen before the display list transaction is - // sent to WebRender, so that the UpdateHitTestingTree call is guaranteed to - // be in the updater queue at the time that the scene swap completes. + if (!mRenderRoot) { + // Only non-root WRBPs will ever have an unresolved mRenderRoot + MOZ_ASSERT(!IsRootWebRenderBridgeParent()); + if (aDisplayLists.Length() != 1) { + return IPC_FAIL(this, "Well-behaved content processes must only send a DL for a single renderRoot"); + } + PushDeferredPipelineData(AsVariant(std::move(aDisplayLists[0]))); + aDisplayLists.Clear(); + } + for (auto& displayList : aDisplayLists) { - if (displayList.mScrollData) { - UpdateAPZScrollData(wrEpoch, std::move(displayList.mScrollData.ref()), - displayList.mRenderRoot); + if (IsRootWebRenderBridgeParent()) { + if (!MaybeHandleDeferredPipelineData( + displayList.mRenderRoot, + displayList.mRemotePipelineIds, + aTxnStartTime)) { + return IPC_FAIL(this, "Failed processing deferred pipeline data"); + } + } else { + RefPtr root = GetRootWebRenderBridgeParent(); + if (!root) { + return IPC_FAIL(this, "Root WRBP is missing (shutting down?)"); + } + + for (auto pipelineId : displayList.mRemotePipelineIds) { + auto id = wr::AsUint64(pipelineId); + root->mPipelineRenderRoots.Put(id, *mRenderRoot); + mChildPipelines.PutEntry(id); + } } } - bool validTransaction = aIdNamespace == mIdNamespace; + bool validTransaction = aDisplayLists.Length() > 0 && + aDisplayLists[0].mIdNamespace == mIdNamespace; + bool observeLayersUpdate = ShouldParentObserveEpoch(); - wr::RenderRootArray txns; - wr::RenderRootArray> senders; for (auto& displayList : aDisplayLists) { - MOZ_ASSERT(displayList.mRenderRoot == wr::RenderRoot::Default || - IsRootWebRenderBridgeParent()); - auto renderRoot = displayList.mRenderRoot; - auto& txn = txns[renderRoot]; - - txn.SetLowPriority(!IsRootWebRenderBridgeParent()); - if (validTransaction) { - senders[renderRoot].emplace(Api(renderRoot), &txn); - } - - if (NS_WARN_IF(!ProcessWebRenderParentCommands(displayList.mCommands, txn, - renderRoot))) { - return IPC_FAIL(this, "Invalid parent command found"); - } - - if (displayList.mDL && - !SetDisplayList(renderRoot, displayList.mRect, displayList.mContentSize, - std::move(displayList.mDL.ref()), displayList.mDLDesc, - displayList.mResourceUpdates, displayList.mSmallShmems, - displayList.mLargeShmems, aTxnStartTime, txn, wrEpoch, - validTransaction, observeLayersUpdate)) { - return IPC_FAIL(this, "Failed call to SetDisplayList"); + if (!ProcessRenderRootDisplayListData( + displayList, + wrEpoch, + aTxnStartTime, + validTransaction, + observeLayersUpdate)) { + return IPC_FAIL(this, "Failed to process RenderRootDisplayListData."); } } @@ -1103,8 +1354,7 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetDisplayList( } bool WebRenderBridgeParent::ProcessEmptyTransactionUpdates( - RenderRootUpdates& aUpdates, uint32_t aPaintSequenceNumber, - bool* aScheduleComposite) { + RenderRootUpdates& aUpdates, bool* aScheduleComposite) { *aScheduleComposite = false; wr::TransactionBuilder txn; txn.SetLowPriority(!IsRootWebRenderBridgeParent()); @@ -1112,9 +1362,9 @@ bool WebRenderBridgeParent::ProcessEmptyTransactionUpdates( MOZ_ASSERT(aUpdates.mRenderRoot == wr::RenderRoot::Default || IsRootWebRenderBridgeParent()); - if (!aUpdates.mScrollUpdates.empty()) { + if (!aUpdates.mScrollUpdates.IsEmpty()) { UpdateAPZScrollOffsets(std::move(aUpdates.mScrollUpdates), - aPaintSequenceNumber, aUpdates.mRenderRoot); + aUpdates.mPaintSequenceNumber, aUpdates.mRenderRoot); } // Update WrEpoch for UpdateResources() and ProcessWebRenderParentCommands(). @@ -1169,14 +1419,13 @@ bool WebRenderBridgeParent::ProcessEmptyTransactionUpdates( } mozilla::ipc::IPCResult WebRenderBridgeParent::RecvEmptyTransaction( - const FocusTarget& aFocusTarget, const uint32_t& aPaintSequenceNumber, + const FocusTarget& aFocusTarget, nsTArray&& aRenderRootUpdates, nsTArray&& aToDestroy, const uint64_t& aFwdTransactionId, - const TransactionId& aTransactionId, const wr::IdNamespace& aIdNamespace, - const VsyncId& aVsyncId, const TimeStamp& aVsyncStartTime, - const TimeStamp& aRefreshStartTime, const TimeStamp& aTxnStartTime, - const nsCString& aTxnURL, const TimeStamp& aFwdTime, - nsTArray&& aPayloads) { + const TransactionId& aTransactionId, const VsyncId& aVsyncId, + const TimeStamp& aVsyncStartTime, const TimeStamp& aRefreshStartTime, + const TimeStamp& aTxnStartTime, const nsCString& aTxnURL, + const TimeStamp& aFwdTime, nsTArray&& aPayloads) { if (mDestroyed) { for (const auto& op : aToDestroy) { DestroyActor(op); @@ -1186,7 +1435,9 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvEmptyTransaction( // Guard against malicious content processes for (auto& update : aRenderRootUpdates) { - MOZ_RELEASE_ASSERT(update.mRenderRoot <= wr::kHighestRenderRoot); + if (!RenderRootIsValid(update.mRenderRoot)) { + return IPC_FAIL(this, "Received an invalid renderRoot"); + } } if (!IsRootWebRenderBridgeParent()) { @@ -1201,16 +1452,26 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvEmptyTransaction( AutoWebRenderBridgeParentAsyncMessageSender autoAsyncMessageSender( this, &aToDestroy); + if (!mRenderRoot && aRenderRootUpdates.Length() > 0) { + // Only non-root WRBPs will ever have an unresolved mRenderRoot + MOZ_ASSERT(!IsRootWebRenderBridgeParent()); + if (aRenderRootUpdates.Length() != 1) { + return IPC_FAIL(this, "Well-behaved content processes must only send a DL for a single renderRoot"); + } + PushDeferredPipelineData(AsVariant(std::move(aRenderRootUpdates[0]))); + aRenderRootUpdates.Clear(); + } + UpdateAPZFocusState(aFocusTarget); bool scheduleAnyComposite = false; + for (auto& update : aRenderRootUpdates) { MOZ_ASSERT(update.mRenderRoot == wr::RenderRoot::Default || IsRootWebRenderBridgeParent()); bool scheduleComposite = false; - if (!ProcessEmptyTransactionUpdates(update, aPaintSequenceNumber, - &scheduleComposite)) { + if (!ProcessEmptyTransactionUpdates(update, &scheduleComposite)) { return IPC_FAIL(this, "Failed to process empty transaction update."); } scheduleAnyComposite = scheduleAnyComposite || scheduleComposite; @@ -1370,7 +1631,7 @@ void WebRenderBridgeParent::FlushSceneBuilds() { // to block until all the inflight transactions have been processed. This // flush message blocks until all previously sent scenes have been built // and received by the render backend thread. - Api(wr::RenderRoot::Default)->FlushSceneBuilder(); + mApis[wr::RenderRoot::Default]->FlushSceneBuilder(); // The post-swap hook for async-scene-building calls the // ScheduleRenderOnCompositorThread function from the scene builder thread, // which then triggers a call to ScheduleGenerateFrame() on the compositor @@ -1410,7 +1671,7 @@ void WebRenderBridgeParent::FlushFramePresentation() { // this effectively blocks on the render backend and renderer threads, // following the same codepath that WebRender takes to render and composite // a frame. - Api(wr::RenderRoot::Default)->WaitFlushed(); + mApis[wr::RenderRoot::Default]->WaitFlushed(); } mozilla::ipc::IPCResult WebRenderBridgeParent::RecvGetSnapshot( @@ -1465,9 +1726,9 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvGetSnapshot( FlushSceneBuilds(); FlushFrameGeneration(); - Api(wr::RenderRoot::Default) - ->Readback(start, size, bufferTexture->GetFormat(), - Range(buffer, buffer_size)); + mApis[wr::RenderRoot::Default]->Readback(start, size, + bufferTexture->GetFormat(), + Range(buffer, buffer_size)); return IPC_OK(); } @@ -1603,16 +1864,22 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvClearCachedResources() { if (renderRoot == wr::RenderRoot::Default || (IsRootWebRenderBridgeParent() && StaticPrefs::gfx_webrender_split_render_roots_AtStartup())) { - // Clear resources - wr::TransactionBuilder txn; - txn.SetLowPriority(true); - txn.ClearDisplayList(GetNextWrEpoch(), mPipelineId); - txn.Notify(wr::Checkpoint::SceneBuilt, - MakeUnique( - mCompositorBridge, GetLayersId(), - mChildLayersObserverEpoch, false)); - - Api(renderRoot)->SendTransaction(txn); + if (mRenderRoot) { + // Clear resources + wr::TransactionBuilder txn; + txn.SetLowPriority(true); + txn.ClearDisplayList(GetNextWrEpoch(), mPipelineId); + txn.Notify(wr::Checkpoint::SceneBuilt, + MakeUnique( + mCompositorBridge, GetLayersId(), + mChildLayersObserverEpoch, false)); + Api(renderRoot)->SendTransaction(txn); + } else { + if (RefPtr root = + GetRootWebRenderBridgeParent()) { + root->RemoveDeferredPipeline(mPipelineId); + } + } } } // Schedule generate frame to clean up Pipeline @@ -1702,7 +1969,7 @@ void WebRenderBridgeParent::ScheduleForcedGenerateFrame() { mozilla::ipc::IPCResult WebRenderBridgeParent::RecvCapture() { if (!mDestroyed) { - Api(wr::RenderRoot::Default)->Capture(); + mApis[wr::RenderRoot::Default]->Capture(); } return IPC_OK(); } @@ -1790,7 +2057,7 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetAsyncScrollOffset( return IPC_OK(); } mCompositorBridge->SetTestAsyncScrollOffset( - WRRootId(GetLayersId(), mRenderRoot), aScrollId, CSSPoint(aX, aY)); + WRRootId(GetLayersId(), *mRenderRoot), aScrollId, CSSPoint(aX, aY)); return IPC_OK(); } @@ -1799,7 +2066,7 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetAsyncZoom( if (mDestroyed) { return IPC_OK(); } - mCompositorBridge->SetTestAsyncZoom(WRRootId(GetLayersId(), mRenderRoot), + mCompositorBridge->SetTestAsyncZoom(WRRootId(GetLayersId(), *mRenderRoot), aScrollId, LayerToParentLayerScale(aZoom)); return IPC_OK(); @@ -1809,13 +2076,13 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvFlushApzRepaints() { if (mDestroyed) { return IPC_OK(); } - mCompositorBridge->FlushApzRepaints(WRRootId(GetLayersId(), mRenderRoot)); + mCompositorBridge->FlushApzRepaints(WRRootId(GetLayersId(), *mRenderRoot)); return IPC_OK(); } mozilla::ipc::IPCResult WebRenderBridgeParent::RecvGetAPZTestData( APZTestData* aOutData) { - mCompositorBridge->GetAPZTestData(WRRootId(GetLayersId(), mRenderRoot), + mCompositorBridge->GetAPZTestData(WRRootId(GetLayersId(), *mRenderRoot), aOutData); return IPC_OK(); } @@ -1899,7 +2166,7 @@ void WebRenderBridgeParent::CompositeToTarget(VsyncId aId, } if (mSkippedComposite || wr::RenderThread::Get()->TooManyPendingFrames( - Api(wr::RenderRoot::Default)->GetId())) { + mApis[wr::RenderRoot::Default]->GetId())) { // Render thread is busy, try next time. mSkippedComposite = true; mSkippedCompositeId = aId; @@ -2015,11 +2282,11 @@ void WebRenderBridgeParent::MaybeGenerateFrame(VsyncId aId, SetAPZSampleTime(); wr::RenderThread::Get()->IncPendingFrameCount( - Api(wr::RenderRoot::Default)->GetId(), aId, start, framesGenerated); + mApis[wr::RenderRoot::Default]->GetId(), aId, start, framesGenerated); #if defined(ENABLE_FRAME_LATENCY_LOG) auto startTime = TimeStamp::Now(); - Api(wr::RenderRoot::Default)->SetFrameStartTime(startTime); + mApis[wr::RenderRoot::Default]->SetFrameStartTime(startTime); #endif MOZ_ASSERT(framesGenerated > 0); @@ -2169,7 +2436,7 @@ TransactionId WebRenderBridgeParent::FlushTransactionIdsForEpoch( transactionId.mSkippedComposites, transactionId.mTxnURL)); wr::RenderThread::Get()->NotifySlowFrame( - Api(wr::RenderRoot::Default)->GetId()); + mApis[wr::RenderRoot::Default]->GetId()); } } @@ -2259,7 +2526,7 @@ void WebRenderBridgeParent::Pause() { return; } - Api(wr::RenderRoot::Default)->Pause(); + mApis[wr::RenderRoot::Default]->Pause(); #endif mPaused = true; } @@ -2271,7 +2538,7 @@ bool WebRenderBridgeParent::Resume() { return false; } - if (!Api(wr::RenderRoot::Default)->Resume()) { + if (!mApis[wr::RenderRoot::Default]->Resume()) { return false; } #endif @@ -2409,10 +2676,10 @@ TextureFactoryIdentifier WebRenderBridgeParent::GetTextureFactoryIdentifier() { return TextureFactoryIdentifier( LayersBackend::LAYERS_WR, XRE_GetProcessType(), - Api(wr::RenderRoot::Default)->GetMaxTextureSize(), false, - Api(wr::RenderRoot::Default)->GetUseANGLE(), - Api(wr::RenderRoot::Default)->GetUseDComp(), false, false, false, - Api(wr::RenderRoot::Default)->GetSyncHandle()); + mApis[wr::RenderRoot::Default]->GetMaxTextureSize(), false, + mApis[wr::RenderRoot::Default]->GetUseANGLE(), + mApis[wr::RenderRoot::Default]->GetUseDComp(), false, false, false, + mApis[wr::RenderRoot::Default]->GetSyncHandle()); } wr::Epoch WebRenderBridgeParent::GetNextWrEpoch() { diff --git a/gfx/layers/wr/WebRenderBridgeParent.h b/gfx/layers/wr/WebRenderBridgeParent.h index 9fa4bd2c5cb0..ac6beff4c129 100644 --- a/gfx/layers/wr/WebRenderBridgeParent.h +++ b/gfx/layers/wr/WebRenderBridgeParent.h @@ -19,6 +19,7 @@ #include "mozilla/layers/PWebRenderBridgeParent.h" #include "mozilla/layers/UiCompositorControllerParent.h" #include "mozilla/layers/WebRenderCompositionRecorder.h" +#include "mozilla/HashTable.h" #include "mozilla/Maybe.h" #include "mozilla/Result.h" #include "mozilla/UniquePtr.h" @@ -123,21 +124,20 @@ class WebRenderBridgeParent final mozilla::ipc::IPCResult RecvSetDisplayList( nsTArray&& aDisplayLists, nsTArray&& aToDestroy, const uint64_t& aFwdTransactionId, - const TransactionId& aTransactionId, const wr::IdNamespace& aIdNamespace, - const bool& aContainsSVGGroup, const VsyncId& aVsyncId, - const TimeStamp& aVsyncStartTime, const TimeStamp& aRefreshStartTime, - const TimeStamp& aTxnStartTime, const nsCString& aTxnURL, - const TimeStamp& aFwdTime, - nsTArray&& aPayloads) override; - mozilla::ipc::IPCResult RecvEmptyTransaction( - const FocusTarget& aFocusTarget, const uint32_t& aPaintSequenceNumber, - nsTArray&& aRenderRootUpdates, - nsTArray&& aToDestroy, const uint64_t& aFwdTransactionId, - const TransactionId& aTransactionId, const wr::IdNamespace& aIdNamespace, + const TransactionId& aTransactionId, const bool& aContainsSVGGroup, const VsyncId& aVsyncId, const TimeStamp& aVsyncStartTime, const TimeStamp& aRefreshStartTime, const TimeStamp& aTxnStartTime, const nsCString& aTxnURL, const TimeStamp& aFwdTime, nsTArray&& aPayloads) override; + mozilla::ipc::IPCResult RecvEmptyTransaction( + const FocusTarget& aFocusTarget, + nsTArray&& aRenderRootUpdates, + nsTArray&& aToDestroy, const uint64_t& aFwdTransactionId, + const TransactionId& aTransactionId, const VsyncId& aVsyncId, + const TimeStamp& aVsyncStartTime, const TimeStamp& aRefreshStartTime, + const TimeStamp& aTxnStartTime, const nsCString& aTxnURL, + const TimeStamp& aFwdTime, + nsTArray&& aPayloads) override; mozilla::ipc::IPCResult RecvSetFocusTarget( const FocusTarget& aFocusTarget) override; mozilla::ipc::IPCResult RecvParentCommands( @@ -270,6 +270,29 @@ class WebRenderBridgeParent final */ void ForceIsFirstPaint() { mIsFirstPaint = true; } + void PushDeferredPipelineData(RenderRootDeferredData&& aDeferredData); + + /** + * If we attempt to process information for a particular pipeline before we + * can determine what RenderRoot it belongs to, then we defer that data until + * we can. This handles processing that deferred data. + */ + bool MaybeHandleDeferredPipelineData( + wr::RenderRoot aRenderRoot, const nsTArray& aPipelineIds, + const TimeStamp& aTxnStartTime); + + /** + * See MaybeHandleDeferredPipelineData - this is the implementation of that for + * a single pipeline. + */ + bool MaybeHandleDeferredPipelineDataForPipeline( + wr::RenderRoot aRenderRoot, wr::PipelineId aPipelineId, + const TimeStamp& aTxnStartTime); + + bool HandleDeferredPipelineData( + nsTArray& aDeferredData, + const TimeStamp& aTxnStartTime); + bool IsRootWebRenderBridgeParent() const; LayersId GetLayersId() const; WRRootId GetWRRootId() const; @@ -281,14 +304,14 @@ class WebRenderBridgeParent final class ScheduleSharedSurfaceRelease; explicit WebRenderBridgeParent(const wr::PipelineId& aPipelineId); - virtual ~WebRenderBridgeParent() = default; + virtual ~WebRenderBridgeParent(); wr::WebRenderAPI* Api(wr::RenderRoot aRenderRoot) { if (IsRootWebRenderBridgeParent()) { return mApis[aRenderRoot]; } else { MOZ_ASSERT(aRenderRoot == wr::RenderRoot::Default); - return mApis[mRenderRoot]; + return mApis[*mRenderRoot]; } } @@ -303,14 +326,25 @@ class WebRenderBridgeParent final return aRenderRoot; } else { MOZ_ASSERT(aRenderRoot == wr::RenderRoot::Default); - return mRenderRoot; + return *mRenderRoot; } } + // Returns whether a given render root is valid for this WRBP to receive as + // input from the WRBC. + bool RenderRootIsValid(wr::RenderRoot aRenderRoot); + + void RemoveDeferredPipeline(wr::PipelineId aPipelineId); + bool ProcessEmptyTransactionUpdates(RenderRootUpdates& aUpdates, - uint32_t aPaintSequenceNumber, bool* aScheduleComposite); + bool ProcessRenderRootDisplayListData(RenderRootDisplayListData& aDisplayList, + wr::Epoch aWrEpoch, + const TimeStamp& aTxnStartTime, + bool aValidTransaction, + bool aObserveLayersUpdate); + bool SetDisplayList(wr::RenderRoot aRenderRoot, const LayoutDeviceRect& aRect, const wr::LayoutSize& aContentSize, ipc::ByteBuf&& aDL, const wr::BuiltDisplayListDescriptor& aDLDesc, @@ -462,6 +496,25 @@ class WebRenderBridgeParent final // need to be able to null these out in a thread-safe way from // ClearResources, and there's no way to do that with an nsTArray. wr::RenderRootArray> mApis; + // This is a map from pipeline id to render root, that tracks the render + // roots of all subpipelines (including nested subpipelines, e.g. in the + // Fission case) attached to this WebRenderBridgeParent. This is only + // populated on the root WRBP. It is used to resolve the render root for the + // subpipelines, since they may not know where they are attached in the + // parent display list and therefore may not know their render root. + nsDataHashtable mPipelineRenderRoots; + // This is a hashset of child pipelines for this WRBP. This allows us to + // iterate through all the children of a non-root WRBP and add them to + // the root's mPipelineRenderRoots, and potentially resolve any of their + // deferred updates. + nsTHashtable mChildPipelines; + // This is a map from pipeline id to a list of deferred data. This is only + // populated on the root WRBP. The data contained within is deferred because + // the sub-WRBP that received it did not know which renderroot it belonged + // to. Once that is resolved by the root WRBP getting the right display list + // update, the deferred data is processed. + nsDataHashtable> + mPipelineDeferredUpdates; RefPtr mAsyncImageManager; RefPtr mCompositorScheduler; RefPtr mAnimStorage; @@ -496,7 +549,7 @@ class WebRenderBridgeParent final Mutex mRenderRootRectMutex; wr::NonDefaultRenderRootArray mRenderRootRects; - wr::RenderRoot mRenderRoot; + Maybe mRenderRoot; bool mPaused; bool mDestroyed; bool mReceivedDisplayList; diff --git a/gfx/layers/wr/WebRenderLayerManager.cpp b/gfx/layers/wr/WebRenderLayerManager.cpp index 48c05bd42324..80be1ac472d7 100644 --- a/gfx/layers/wr/WebRenderLayerManager.cpp +++ b/gfx/layers/wr/WebRenderLayerManager.cpp @@ -209,7 +209,7 @@ bool WebRenderLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags) { !mWebRenderCommandBuilder.NeedsEmptyTransaction()) { bool haveScrollUpdates = false; for (auto renderRoot : wr::kRenderRoots) { - if (!mPendingScrollUpdates[renderRoot].empty()) { + if (!mPendingScrollUpdates[renderRoot].IsEmpty()) { haveScrollUpdates = true; break; } @@ -251,25 +251,26 @@ bool WebRenderLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags) { for (auto& stateManager : mStateManagers) { auto renderRoot = stateManager.GetRenderRoot(); if (stateManager.mAsyncResourceUpdates || - !mPendingScrollUpdates[renderRoot].empty() || + !mPendingScrollUpdates[renderRoot].IsEmpty() || WrBridge()->HasWebRenderParentCommands(renderRoot)) { auto updates = renderRootUpdates.AppendElement(); updates->mRenderRoot = renderRoot; + updates->mPaintSequenceNumber = mPaintSequenceNumber; if (stateManager.mAsyncResourceUpdates) { stateManager.mAsyncResourceUpdates->Flush(updates->mResourceUpdates, updates->mSmallShmems, updates->mLargeShmems); } updates->mScrollUpdates = std::move(mPendingScrollUpdates[renderRoot]); - for (const auto& entry : updates->mScrollUpdates) { - nsLayoutUtils::NotifyPaintSkipTransaction(/*scroll id=*/entry.first); + for (auto it = updates->mScrollUpdates.Iter(); !it.Done(); it.Next()) { + nsLayoutUtils::NotifyPaintSkipTransaction(/*scroll id=*/it.Key()); } } } Maybe nothing; WrBridge()->EndEmptyTransaction(mFocusTarget, renderRootUpdates, - mPaintSequenceNumber, mLatestTransactionId, + mLatestTransactionId, mTransactionIdAllocator->GetVsyncId(), mTransactionIdAllocator->GetVsyncStart(), refreshStart, mTransactionStart, mURL); diff --git a/gfx/layers/wr/WebRenderScrollData.cpp b/gfx/layers/wr/WebRenderScrollData.cpp index 45f49467ae34..bb3be4f2c7c8 100644 --- a/gfx/layers/wr/WebRenderScrollData.cpp +++ b/gfx/layers/wr/WebRenderScrollData.cpp @@ -158,13 +158,14 @@ WebRenderLayerManager* WebRenderScrollData::GetManager() const { size_t WebRenderScrollData::AddMetadata(const ScrollMetadata& aMetadata) { ScrollableLayerGuid::ViewID scrollId = aMetadata.GetMetrics().GetScrollId(); - auto insertResult = mScrollIdMap.insert(std::make_pair(scrollId, 0)); - if (insertResult.second) { - // Insertion took place, therefore it's a scrollId we hadn't seen before - insertResult.first->second = mScrollMetadatas.Length(); + auto p = mScrollIdMap.lookupForAdd(scrollId); + if (!p) { + // It's a scrollId we hadn't seen before + bool ok = mScrollIdMap.add(p, scrollId, mScrollMetadatas.Length()); + MOZ_RELEASE_ASSERT(ok); mScrollMetadatas.AppendElement(aMetadata); } // else we didn't insert, because it already existed - return insertResult.first->second; + return p->value(); } size_t WebRenderScrollData::AddLayerData( @@ -193,8 +194,8 @@ const ScrollMetadata& WebRenderScrollData::GetScrollMetadata( Maybe WebRenderScrollData::HasMetadataFor( const ScrollableLayerGuid::ViewID& aScrollId) const { - auto it = mScrollIdMap.find(aScrollId); - return (it == mScrollIdMap.end() ? Nothing() : Some(it->second)); + auto ptr = mScrollIdMap.lookup(aScrollId); + return (ptr ? Some(ptr->value()) : Nothing()); } void WebRenderScrollData::SetIsFirstPaint() { mIsFirstPaint = true; } @@ -210,12 +211,11 @@ uint32_t WebRenderScrollData::GetPaintSequenceNumber() const { return mPaintSequenceNumber; } -void WebRenderScrollData::ApplyUpdates(const ScrollUpdatesMap& aUpdates, +void WebRenderScrollData::ApplyUpdates(ScrollUpdatesMap& aUpdates, uint32_t aPaintSequenceNumber) { - for (const auto& update : aUpdates) { - if (Maybe index = HasMetadataFor(update.first)) { - mScrollMetadatas[*index].GetMetrics().UpdatePendingScrollInfo( - update.second); + for (auto it = aUpdates.Iter(); !it.Done(); it.Next()) { + if (Maybe index = HasMetadataFor(it.Key())) { + mScrollMetadatas[*index].GetMetrics().UpdatePendingScrollInfo(it.Data()); } } mPaintSequenceNumber = aPaintSequenceNumber; @@ -234,7 +234,8 @@ bool WebRenderScrollData::RepopulateMap() { for (size_t i = 0; i < mScrollMetadatas.Length(); i++) { ScrollableLayerGuid::ViewID scrollId = mScrollMetadatas[i].GetMetrics().GetScrollId(); - mScrollIdMap.emplace(scrollId, i); + bool ok = mScrollIdMap.putNew(scrollId, i); + MOZ_RELEASE_ASSERT(ok); } return true; } diff --git a/gfx/layers/wr/WebRenderScrollData.h b/gfx/layers/wr/WebRenderScrollData.h index cc5dd9d16a88..ef2de96dc89c 100644 --- a/gfx/layers/wr/WebRenderScrollData.h +++ b/gfx/layers/wr/WebRenderScrollData.h @@ -21,6 +21,7 @@ #include "mozilla/layers/RenderRootBoundary.h" #include "mozilla/layers/WebRenderMessageUtils.h" #include "mozilla/webrender/WebRenderTypes.h" +#include "mozilla/HashTable.h" #include "mozilla/Maybe.h" #include "nsTArrayForwardDeclare.h" @@ -199,8 +200,7 @@ class WebRenderScrollData final { void SetPaintSequenceNumber(uint32_t aPaintSequenceNumber); uint32_t GetPaintSequenceNumber() const; - void ApplyUpdates(const ScrollUpdatesMap& aUpdates, - uint32_t aPaintSequenceNumber); + void ApplyUpdates(ScrollUpdatesMap& aUpdates, uint32_t aPaintSequenceNumber); friend struct IPC::ParamTraits; @@ -223,7 +223,7 @@ class WebRenderScrollData final { // valid on both the child and parent. // The key into this map is the scrollId of a ScrollMetadata, and the value is // an index into the mScrollMetadatas array. - std::map mScrollIdMap; + HashMap mScrollIdMap; // A list of all the unique ScrollMetadata objects from the layer tree. Each // ScrollMetadata in this list must have a unique scroll id. diff --git a/gfx/webrender_bindings/WebRenderAPI.cpp b/gfx/webrender_bindings/WebRenderAPI.cpp index 20ec48920186..bdd17217a97d 100644 --- a/gfx/webrender_bindings/WebRenderAPI.cpp +++ b/gfx/webrender_bindings/WebRenderAPI.cpp @@ -816,6 +816,8 @@ void DisplayListBuilder::Finalize( &aOutTransaction.mDLDesc, &dl.inner); aOutTransaction.mDL.emplace(dl.inner.data, dl.inner.length, dl.inner.capacity); + aOutTransaction.mRemotePipelineIds = + std::move(SubBuilder(aOutTransaction.mRenderRoot).mRemotePipelineIds); dl.inner.capacity = 0; dl.inner.data = nullptr; } @@ -1104,6 +1106,7 @@ void DisplayListBuilder::PushIFrame(const wr::LayoutRect& aBounds, bool aIsBackfaceVisible, PipelineId aPipeline, bool aIgnoreMissingPipeline) { + mRemotePipelineIds.AppendElement(aPipeline); wr_dp_push_iframe(mWrState, aBounds, MergeClipLeaf(aBounds), aIsBackfaceVisible, &mCurrentSpaceAndClipChain, aPipeline, aIgnoreMissingPipeline); diff --git a/gfx/webrender_bindings/WebRenderAPI.h b/gfx/webrender_bindings/WebRenderAPI.h index e28f231232c9..95bdb7bc882a 100644 --- a/gfx/webrender_bindings/WebRenderAPI.h +++ b/gfx/webrender_bindings/WebRenderAPI.h @@ -638,6 +638,7 @@ class DisplayListBuilder final { wr::PipelineId mPipelineId; wr::LayoutSize mContentSize; + nsTArray mRemotePipelineIds; RenderRoot mRenderRoot; bool mSendSubBuilderDisplayList;