diff --git a/gfx/layers/ipc/PWebRenderBridge.ipdl b/gfx/layers/ipc/PWebRenderBridge.ipdl index 2b17dcacb13d..8c27a4a91123 100644 --- a/gfx/layers/ipc/PWebRenderBridge.ipdl +++ b/gfx/layers/ipc/PWebRenderBridge.ipdl @@ -50,9 +50,10 @@ parent: IdNamespace aIdNamespace, bool containsSVGGroup, TimeStamp refreshStartTime, TimeStamp txnStartTime, TimeStamp fwdTime); async EmptyTransaction(FocusTarget focusTarget, ScrollUpdatesMap scrollUpdates, uint32_t aPaintSequenceNumber, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, TransactionId transactionId, + OpUpdateResource[] aResourceUpdates, RefCountedShmem[] aSmallShmems, Shmem[] aLargeShmems, IdNamespace aIdNamespace, TimeStamp refreshStartTime, TimeStamp txnStartTime, TimeStamp fwdTime); async SetFocusTarget(FocusTarget focusTarget); - async UpdateResources(OpUpdateResource[] aResourceUpdates, RefCountedShmem[] aSmallShmems, Shmem[] aLargeShmems); + async UpdateResources(OpUpdateResource[] aResourceUpdates, RefCountedShmem[] aSmallShmems, Shmem[] aLargeShmems, bool scheduleComposite); async ParentCommands(WebRenderParentCommand[] commands); sync GetSnapshot(PTexture texture); async SetLayersObserverEpoch(LayersObserverEpoch childEpoch); diff --git a/gfx/layers/wr/IpcResourceUpdateQueue.cpp b/gfx/layers/wr/IpcResourceUpdateQueue.cpp index 101ce22e5c5f..e171b664e0ba 100644 --- a/gfx/layers/wr/IpcResourceUpdateQueue.cpp +++ b/gfx/layers/wr/IpcResourceUpdateQueue.cpp @@ -30,6 +30,30 @@ ShmSegmentsWriter::~ShmSegmentsWriter() Clear(); } +ShmSegmentsWriter::ShmSegmentsWriter(ShmSegmentsWriter&& aOther) noexcept + : mSmallAllocs(std::move(aOther.mSmallAllocs)) + , mLargeAllocs(std::move(aOther.mLargeAllocs)) + , mShmAllocator(aOther.mShmAllocator) + , mCursor(aOther.mCursor) + , mChunkSize(aOther.mChunkSize) +{ + aOther.mCursor = 0; +} + +ShmSegmentsWriter& +ShmSegmentsWriter::operator=(ShmSegmentsWriter&& aOther) noexcept +{ + MOZ_ASSERT(IsEmpty(), "Will forget existing updates!"); + Clear(); + mSmallAllocs = std::move(aOther.mSmallAllocs); + mLargeAllocs = std::move(aOther.mLargeAllocs); + mShmAllocator = aOther.mShmAllocator; + mCursor = aOther.mCursor; + mChunkSize = aOther.mChunkSize; + aOther.mCursor = 0; + return *this; +} + layers::OffsetRange ShmSegmentsWriter::Write(Range aBytes) { @@ -246,9 +270,23 @@ ShmSegmentsReader::Read(const layers::OffsetRange& aRange, wr::Vec& aIn IpcResourceUpdateQueue::IpcResourceUpdateQueue(layers::WebRenderBridgeChild* aAllocator, size_t aChunkSize) -: mWriter(std::move(aAllocator), aChunkSize) +: mWriter(aAllocator, aChunkSize) {} +IpcResourceUpdateQueue::IpcResourceUpdateQueue(IpcResourceUpdateQueue&& aOther) noexcept + : mWriter(std::move(aOther.mWriter)) + , mUpdates(std::move(aOther.mUpdates)) +{ } + +IpcResourceUpdateQueue& +IpcResourceUpdateQueue::operator=(IpcResourceUpdateQueue&& aOther) noexcept +{ + MOZ_ASSERT(IsEmpty(), "Will forget existing updates!"); + mWriter = std::move(aOther.mWriter); + mUpdates = std::move(aOther.mUpdates); + return *this; +} + bool IpcResourceUpdateQueue::AddImage(ImageKey key, const ImageDescriptor& aDescriptor, Range aBytes) diff --git a/gfx/layers/wr/IpcResourceUpdateQueue.h b/gfx/layers/wr/IpcResourceUpdateQueue.h index e86b1c640306..97b6cf127880 100644 --- a/gfx/layers/wr/IpcResourceUpdateQueue.h +++ b/gfx/layers/wr/IpcResourceUpdateQueue.h @@ -24,6 +24,12 @@ public: ShmSegmentsWriter(layers::WebRenderBridgeChild* aAllocator, size_t aChunkSize); ~ShmSegmentsWriter(); + ShmSegmentsWriter(ShmSegmentsWriter&& aOther) noexcept; + ShmSegmentsWriter& operator=(ShmSegmentsWriter&& aOther) noexcept; + + ShmSegmentsWriter(const ShmSegmentsWriter& aOther) = delete; + ShmSegmentsWriter& operator=(const ShmSegmentsWriter& aOther) = delete; + layers::OffsetRange Write(Range aBytes); template @@ -32,7 +38,7 @@ public: return Write(Range((uint8_t*)aValues.begin().get(), aValues.length() * sizeof(T))); } - void Flush(nsTArray& aSmallAllocs, nsTArray& aLargeAllocs); + void Flush(nsTArray& aSmallAllocs, nsTArray& aLargeAllocs); void Clear(); bool IsEmpty() const; @@ -44,7 +50,7 @@ protected: layers::OffsetRange AllocLargeChunk(size_t aSize); nsTArray mSmallAllocs; - nsTArray mLargeAllocs; + nsTArray mLargeAllocs; layers::WebRenderBridgeChild* mShmAllocator; size_t mCursor; size_t mChunkSize; @@ -53,7 +59,7 @@ protected: class ShmSegmentsReader { public: ShmSegmentsReader(const nsTArray& aSmallShmems, - const nsTArray& aLargeShmems); + const nsTArray& aLargeShmems); bool Read(const layers::OffsetRange& aRange, wr::Vec& aInto); @@ -61,7 +67,7 @@ protected: bool ReadLarge(const layers::OffsetRange& aRange, wr::Vec& aInto); const nsTArray& mSmallAllocs; - const nsTArray& mLargeAllocs; + const nsTArray& mLargeAllocs; size_t mChunkSize; }; @@ -75,6 +81,12 @@ public: // So we pick 64k - 2 * 4k - 16 = 57328 bytes as the default alloc size. explicit IpcResourceUpdateQueue(layers::WebRenderBridgeChild* aAllocator, size_t aChunkSize = 57328); + IpcResourceUpdateQueue(IpcResourceUpdateQueue&& aOther) noexcept; + IpcResourceUpdateQueue& operator=(IpcResourceUpdateQueue&& aOther) noexcept; + + IpcResourceUpdateQueue(const IpcResourceUpdateQueue& aOther) = delete; + IpcResourceUpdateQueue& operator=(const IpcResourceUpdateQueue& aOther) = delete; + bool AddImage(wr::ImageKey aKey, const ImageDescriptor& aDescriptor, Range aBytes); @@ -126,12 +138,12 @@ public: void Flush(nsTArray& aUpdates, nsTArray& aSmallAllocs, - nsTArray& aLargeAllocs); + nsTArray& aLargeAllocs); bool IsEmpty() const; - static void ReleaseShmems(ipc::IProtocol*, nsTArray& aShmems); - static void ReleaseShmems(ipc::IProtocol*, nsTArray& aShmems); + static void ReleaseShmems(mozilla::ipc::IProtocol*, nsTArray& aShms); + static void ReleaseShmems(mozilla::ipc::IProtocol*, nsTArray& aShms); protected: ShmSegmentsWriter mWriter; nsTArray mUpdates; diff --git a/gfx/layers/wr/WebRenderBridgeChild.cpp b/gfx/layers/wr/WebRenderBridgeChild.cpp index 0f12c171cbd7..6a3881dcd878 100644 --- a/gfx/layers/wr/WebRenderBridgeChild.cpp +++ b/gfx/layers/wr/WebRenderBridgeChild.cpp @@ -96,7 +96,8 @@ WebRenderBridgeChild::BeginTransaction() } void -WebRenderBridgeChild::UpdateResources(wr::IpcResourceUpdateQueue& aResources) +WebRenderBridgeChild::UpdateResources(wr::IpcResourceUpdateQueue& aResources, + bool aScheduleComposite /* = false */) { if (!IPCOpen()) { aResources.Clear(); @@ -112,7 +113,8 @@ WebRenderBridgeChild::UpdateResources(wr::IpcResourceUpdateQueue& aResources) nsTArray largeShmems; aResources.Flush(resourceUpdates, smallShmems, largeShmems); - this->SendUpdateResources(resourceUpdates, std::move(smallShmems), largeShmems); + this->SendUpdateResources(resourceUpdates, smallShmems, + largeShmems, aScheduleComposite); } void @@ -146,7 +148,7 @@ WebRenderBridgeChild::EndTransaction(const wr::LayoutSize& aContentSize, this->SendSetDisplayList(aSize, mParentCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId, aContentSize, dlData, aDL.dl_desc, aScrollData, - std::move(resourceUpdates), std::move(smallShmems), largeShmems, + resourceUpdates, smallShmems, largeShmems, mIdNamespace, aContainsSVGGroup, aRefreshStartTime, aTxnStartTime, fwdTime); mParentCommands.Clear(); @@ -157,6 +159,7 @@ WebRenderBridgeChild::EndTransaction(const wr::LayoutSize& aContentSize, void WebRenderBridgeChild::EndEmptyTransaction(const FocusTarget& aFocusTarget, const ScrollUpdatesMap& aUpdates, + Maybe& aResources, uint32_t aPaintSequenceNumber, TransactionId aTransactionId, const mozilla::TimeStamp& aRefreshStartTime, @@ -170,9 +173,18 @@ WebRenderBridgeChild::EndEmptyTransaction(const FocusTarget& aFocusTarget, fwdTime = TimeStamp::Now(); #endif + nsTArray resourceUpdates; + nsTArray smallShmems; + nsTArray largeShmems; + if (aResources) { + aResources->Flush(resourceUpdates, smallShmems, largeShmems); + aResources.reset(); + } + this->SendEmptyTransaction(aFocusTarget, aUpdates, aPaintSequenceNumber, mParentCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId, + resourceUpdates, smallShmems, largeShmems, mIdNamespace, aRefreshStartTime, aTxnStartTime, fwdTime); mParentCommands.Clear(); mDestroyedActors.Clear(); diff --git a/gfx/layers/wr/WebRenderBridgeChild.h b/gfx/layers/wr/WebRenderBridgeChild.h index 430d0357b1df..5fa77f26dc27 100644 --- a/gfx/layers/wr/WebRenderBridgeChild.h +++ b/gfx/layers/wr/WebRenderBridgeChild.h @@ -66,7 +66,8 @@ public: void AddWebRenderParentCommand(const WebRenderParentCommand& aCmd); - void UpdateResources(wr::IpcResourceUpdateQueue& aResources); + void UpdateResources(wr::IpcResourceUpdateQueue& aResources, + bool aScheduleComposite = false); void BeginTransaction(); void EndTransaction(const wr::LayoutSize& aContentSize, wr::BuiltDisplayList& dl, @@ -79,6 +80,7 @@ public: const mozilla::TimeStamp& aTxnStartTime); void EndEmptyTransaction(const FocusTarget& aFocusTarget, const ScrollUpdatesMap& aUpdates, + Maybe& aResources, uint32_t aPaintSequenceNumber, TransactionId aTransactionId, const mozilla::TimeStamp& aRefreshStartTime, diff --git a/gfx/layers/wr/WebRenderBridgeParent.cpp b/gfx/layers/wr/WebRenderBridgeParent.cpp index 21b1cae7c317..ef03d8fcce35 100644 --- a/gfx/layers/wr/WebRenderBridgeParent.cpp +++ b/gfx/layers/wr/WebRenderBridgeParent.cpp @@ -624,25 +624,34 @@ WebRenderBridgeParent::UpdateExternalImage(wr::ExternalImageId aExtId, mozilla::ipc::IPCResult WebRenderBridgeParent::RecvUpdateResources(nsTArray&& aResourceUpdates, nsTArray&& aSmallShmems, - nsTArray&& aLargeShmems) + nsTArray&& aLargeShmems, + const bool& aScheduleComposite) { if (mDestroyed) { + wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems); + wr::IpcResourceUpdateQueue::ReleaseShmems(this, aLargeShmems); return IPC_OK(); } wr::TransactionBuilder txn; txn.SetLowPriority(!IsRootWebRenderBridgeParent()); - if (!UpdateResources(aResourceUpdates, aSmallShmems, aLargeShmems, txn)) { - wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems); - wr::IpcResourceUpdateQueue::ReleaseShmems(this, aLargeShmems); - IPC_FAIL(this, "Invalid WebRender resource data shmem or address."); + bool success = + UpdateResources(aResourceUpdates, aSmallShmems, aLargeShmems, txn); + wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems); + wr::IpcResourceUpdateQueue::ReleaseShmems(this, aLargeShmems); + + if (!success) { + return IPC_FAIL(this, "Invalid WebRender resource data shmem or address."); + } + + if (aScheduleComposite) { + txn.InvalidateRenderedFrame(); + ScheduleGenerateFrame(); } mApi->SendTransaction(txn); - wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems); - wr::IpcResourceUpdateQueue::ReleaseShmems(this, aLargeShmems); return IPC_OK(); } @@ -910,6 +919,9 @@ WebRenderBridgeParent::RecvEmptyTransaction(const FocusTarget& aFocusTarget, InfallibleTArray&& aToDestroy, const uint64_t& aFwdTransactionId, const TransactionId& aTransactionId, + nsTArray&& aResourceUpdates, + nsTArray&& aSmallShmems, + nsTArray&& aLargeShmems, const wr::IdNamespace& aIdNamespace, const TimeStamp& aRefreshStartTime, const TimeStamp& aTxnStartTime, @@ -941,10 +953,18 @@ WebRenderBridgeParent::RecvEmptyTransaction(const FocusTarget& aFocusTarget, scheduleComposite = true; } + wr::TransactionBuilder txn; + txn.SetLowPriority(!IsRootWebRenderBridgeParent()); + if (!aResourceUpdates.IsEmpty()) { + scheduleComposite = true; + } + + if (!UpdateResources(aResourceUpdates, aSmallShmems, aLargeShmems, txn)) { + return IPC_FAIL(this, "Failed to deserialize resource updates"); + } + if (!aCommands.IsEmpty()) { mAsyncImageManager->SetCompositionTime(TimeStamp::Now()); - wr::TransactionBuilder txn; - txn.SetLowPriority(!IsRootWebRenderBridgeParent()); wr::Epoch wrEpoch = GetNextWrEpoch(); txn.UpdateEpoch(mPipelineId, wrEpoch); if (!ProcessWebRenderParentCommands(aCommands, txn)) { @@ -962,10 +982,13 @@ WebRenderBridgeParent::RecvEmptyTransaction(const FocusTarget& aFocusTarget, ); } - mApi->SendTransaction(txn); scheduleComposite = true; } + if (!txn.IsEmpty()) { + mApi->SendTransaction(txn); + } + bool sendDidComposite = true; if (scheduleComposite || !mPendingTransactionIds.empty()) { // If we are going to kick off a new composite as a result of this @@ -1001,6 +1024,8 @@ WebRenderBridgeParent::RecvEmptyTransaction(const FocusTarget& aFocusTarget, } } + wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems); + wr::IpcResourceUpdateQueue::ReleaseShmems(this, aLargeShmems); return IPC_OK(); } diff --git a/gfx/layers/wr/WebRenderBridgeParent.h b/gfx/layers/wr/WebRenderBridgeParent.h index 88c035a0d1f2..6067c2901e69 100644 --- a/gfx/layers/wr/WebRenderBridgeParent.h +++ b/gfx/layers/wr/WebRenderBridgeParent.h @@ -78,7 +78,8 @@ public: mozilla::ipc::IPCResult RecvDeleteCompositorAnimations(InfallibleTArray&& aIds) override; mozilla::ipc::IPCResult RecvUpdateResources(nsTArray&& aUpdates, nsTArray&& aSmallShmems, - nsTArray&& aLargeShmems) override; + nsTArray&& aLargeShmems, + const bool& aScheduleComposite) override; mozilla::ipc::IPCResult RecvSetDisplayList(const gfx::IntSize& aSize, InfallibleTArray&& aCommands, InfallibleTArray&& aToDestroy, @@ -103,6 +104,9 @@ public: InfallibleTArray&& aToDestroy, const uint64_t& aFwdTransactionId, const TransactionId& aTransactionId, + nsTArray&& aResourceUpdates, + nsTArray&& aSmallShmems, + nsTArray&& aLargeShmems, const wr::IdNamespace& aIdNamespace, const TimeStamp& aRefreshStartTime, const TimeStamp& aTxnStartTime, diff --git a/gfx/layers/wr/WebRenderLayerManager.cpp b/gfx/layers/wr/WebRenderLayerManager.cpp index bb9ffd492364..5032de481cd3 100644 --- a/gfx/layers/wr/WebRenderLayerManager.cpp +++ b/gfx/layers/wr/WebRenderLayerManager.cpp @@ -14,7 +14,6 @@ #include "mozilla/dom/TabGroup.h" #include "mozilla/gfx/DrawEventRecorder.h" #include "mozilla/layers/CompositorBridgeChild.h" -#include "mozilla/layers/IpcResourceUpdateQueue.h" #include "mozilla/layers/StackingContextHelper.h" #include "mozilla/layers/TextureClient.h" #include "mozilla/layers/WebRenderBridgeChild.h" @@ -248,7 +247,8 @@ WebRenderLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags) } WrBridge()->EndEmptyTransaction(mFocusTarget, mPendingScrollUpdates, - mPaintSequenceNumber, mLatestTransactionId, refreshStart, mTransactionStart); + mAsyncResourceUpdates, mPaintSequenceNumber, mLatestTransactionId, + refreshStart, mTransactionStart); ClearPendingScrollInfoUpdate(); mTransactionStart = TimeStamp(); @@ -343,6 +343,19 @@ WebRenderLayerManager::EndTransactionWithoutLayer(nsDisplayList* aDisplayList, mLatestTransactionId = mTransactionIdAllocator->GetTransactionId(/*aThrottle*/ true); TimeStamp refreshStart = mTransactionIdAllocator->GetTransactionStart(); + if (mAsyncResourceUpdates) { + if (resourceUpdates.IsEmpty()) { + resourceUpdates = std::move(mAsyncResourceUpdates.ref()); + } else { + // If we can't just swap the queue, we need to take the slow path and + // send the update as a separate message. We don't need to schedule a + // composite however because that will happen with EndTransaction. + WrBridge()->UpdateResources(mAsyncResourceUpdates.ref(), + /* aScheduleComposite */ false); + } + mAsyncResourceUpdates.reset(); + } + for (const auto& key : mImageKeysToDelete) { resourceUpdates.DeleteImage(key); } @@ -706,5 +719,39 @@ WebRenderLayerManager::CreatePersistentBufferProvider(const gfx::IntSize& aSize, return LayerManager::CreatePersistentBufferProvider(aSize, aFormat); } +wr::IpcResourceUpdateQueue& +WebRenderLayerManager::AsyncResourceUpdates() +{ + MOZ_ASSERT(NS_IsMainThread()); + + if (!mAsyncResourceUpdates) { + mAsyncResourceUpdates.emplace(WrBridge()); + + RefPtr task = NewRunnableMethod( + "WebRenderLayerManager::FlushAsyncResourceUpdates", + this, &WebRenderLayerManager::FlushAsyncResourceUpdates); + NS_DispatchToMainThread(task.forget()); + } + + return mAsyncResourceUpdates.ref(); +} + +void +WebRenderLayerManager::FlushAsyncResourceUpdates() +{ + MOZ_ASSERT(NS_IsMainThread()); + + if (!mAsyncResourceUpdates) { + return; + } + + if (!IsDestroyed() && WrBridge()) { + WrBridge()->UpdateResources(mAsyncResourceUpdates.ref(), + /* aScheduleComposite */ true); + } + + mAsyncResourceUpdates.reset(); +} + } // namespace layers } // namespace mozilla diff --git a/gfx/layers/wr/WebRenderLayerManager.h b/gfx/layers/wr/WebRenderLayerManager.h index 44cee04c82d8..a5ac1e5525af 100644 --- a/gfx/layers/wr/WebRenderLayerManager.h +++ b/gfx/layers/wr/WebRenderLayerManager.h @@ -12,9 +12,11 @@ #include "gfxPrefs.h" #include "Layers.h" +#include "mozilla/Maybe.h" #include "mozilla/MozPromise.h" #include "mozilla/layers/APZTestData.h" #include "mozilla/layers/FocusTarget.h" +#include "mozilla/layers/IpcResourceUpdateQueue.h" #include "mozilla/layers/StackingContextHelper.h" #include "mozilla/layers/TransactionIdAllocator.h" #include "mozilla/layers/WebRenderCommandBuilder.h" @@ -133,6 +135,9 @@ public: void DiscardImages(); void DiscardLocalImages(); + wr::IpcResourceUpdateQueue& AsyncResourceUpdates(); + void FlushAsyncResourceUpdates(); + // Methods to manage the compositor animation ids. Active animations are still // going, and when they end we discard them and remove them from the active // list. @@ -219,6 +224,8 @@ private: WebRenderCommandBuilder mWebRenderCommandBuilder; size_t mLastDisplayListSize; + + Maybe mAsyncResourceUpdates; }; } // namespace layers