diff --git a/gfx/ipc/GfxMessageUtils.h b/gfx/ipc/GfxMessageUtils.h index 77bec6a3cbcc..82f4c8c00cbe 100644 --- a/gfx/ipc/GfxMessageUtils.h +++ b/gfx/ipc/GfxMessageUtils.h @@ -728,6 +728,19 @@ struct ParamTraits } }; +template<> +struct ParamTraits +{ + typedef mozilla::layers::ReadLockHandle paramType; + + static void Write(Message* msg, const paramType& param) { + WriteParam(msg, param.mHandle); + } + static bool Read(const Message* msg, PickleIterator* iter, paramType* result) { + return ReadParam(msg, iter, &result->mHandle); + } +}; + // Helper class for reading bitfields. // If T has bitfields members, derive ParamTraits from BitfieldHelper. template diff --git a/gfx/layers/LayersTypes.h b/gfx/layers/LayersTypes.h index 900a7af89a70..f9ac335c1c9b 100644 --- a/gfx/layers/LayersTypes.h +++ b/gfx/layers/LayersTypes.h @@ -274,6 +274,32 @@ private: uint64_t mHandle; }; +class ReadLockHandle +{ + friend struct IPC::ParamTraits; +public: + ReadLockHandle() : mHandle(0) + {} + ReadLockHandle(const ReadLockHandle& aOther) : mHandle(aOther.mHandle) + {} + explicit ReadLockHandle(uint64_t aHandle) : mHandle(aHandle) + {} + bool IsValid() const { + return mHandle != 0; + } + explicit operator bool() const { + return IsValid(); + } + bool operator ==(const ReadLockHandle& aOther) const { + return mHandle == aOther.mHandle; + } + uint64_t Value() const { + return mHandle; + } +private: + uint64_t mHandle; +}; + enum class ScrollDirection : uint32_t { NONE, VERTICAL, diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp index 2456da97ff22..fb9d6ba51882 100644 --- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -582,7 +582,7 @@ TextureClient::EnableReadLock() } } -void +bool TextureClient::SerializeReadLock(ReadLockDescriptor& aDescriptor) { if (mReadLock && mUpdated) { @@ -591,8 +591,10 @@ TextureClient::SerializeReadLock(ReadLockDescriptor& aDescriptor) mReadLock->ReadLock(); mReadLock->Serialize(aDescriptor, GetAllocator()->GetParentPid()); mUpdated = false; + return true; } else { aDescriptor = null_t(); + return false; } } diff --git a/gfx/layers/client/TextureClient.h b/gfx/layers/client/TextureClient.h index 764f0c5c2452..5b176e5b0a26 100644 --- a/gfx/layers/client/TextureClient.h +++ b/gfx/layers/client/TextureClient.h @@ -651,7 +651,7 @@ public: bool TryReadLock(); void ReadUnlock(); - void SerializeReadLock(ReadLockDescriptor& aDescriptor); + bool SerializeReadLock(ReadLockDescriptor& aDescriptor); private: static void TextureClientRecycleCallback(TextureClient* aClient, void* aClosure); diff --git a/gfx/layers/composite/TextureHost.cpp b/gfx/layers/composite/TextureHost.cpp index f352d0da5d44..cc8ae604454a 100644 --- a/gfx/layers/composite/TextureHost.cpp +++ b/gfx/layers/composite/TextureHost.cpp @@ -559,6 +559,18 @@ TextureHost::DeserializeReadLock(const ReadLockDescriptor& aDesc, mReadLock = lock.forget(); } +void +TextureHost::SetReadLock(TextureReadLock* aReadLock) +{ + if (!aReadLock) { + return; + } + // If mReadLock is not null it means we haven't unlocked it yet and the content + // side should not have been able to write into this texture and send a new lock! + MOZ_ASSERT(!mReadLock); + mReadLock = aReadLock; +} + void TextureHost::ReadUnlock() { diff --git a/gfx/layers/composite/TextureHost.h b/gfx/layers/composite/TextureHost.h index 68959954e433..c81383c066dc 100644 --- a/gfx/layers/composite/TextureHost.h +++ b/gfx/layers/composite/TextureHost.h @@ -578,6 +578,7 @@ public: void DeserializeReadLock(const ReadLockDescriptor& aDesc, ISurfaceAllocator* aAllocator); + void SetReadLock(TextureReadLock* aReadLock); TextureReadLock* GetReadLock() { return mReadLock; } diff --git a/gfx/layers/ipc/CompositableForwarder.h b/gfx/layers/ipc/CompositableForwarder.h index 83ec79058b6d..d2fa1d6a4e3c 100644 --- a/gfx/layers/ipc/CompositableForwarder.h +++ b/gfx/layers/ipc/CompositableForwarder.h @@ -114,6 +114,8 @@ public: MOZ_ASSERT(InForwarderThread()); } + static uint32_t GetMaxFileDescriptorsPerMessage(); + protected: nsTArray > mTexturesToRemove; nsTArray> mCompositableClientsToRemove; diff --git a/gfx/layers/ipc/CompositableTransactionParent.cpp b/gfx/layers/ipc/CompositableTransactionParent.cpp index 13e1188c708e..37455bc2dca5 100644 --- a/gfx/layers/ipc/CompositableTransactionParent.cpp +++ b/gfx/layers/ipc/CompositableTransactionParent.cpp @@ -160,7 +160,7 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation t->mPictureRect = timedTexture.picture(); t->mFrameID = timedTexture.frameID(); t->mProducerID = timedTexture.producerID(); - t->mTexture->DeserializeReadLock(timedTexture.sharedLock(), this); + t->mTexture->SetReadLock(FindReadLock(timedTexture.sharedLock())); } if (textures.Length() > 0) { compositable->UseTextureHost(textures); @@ -185,8 +185,8 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation const OpUseComponentAlphaTextures& op = aEdit.detail().get_OpUseComponentAlphaTextures(); RefPtr texOnBlack = TextureHost::AsTextureHost(op.textureOnBlackParent()); RefPtr texOnWhite = TextureHost::AsTextureHost(op.textureOnWhiteParent()); - texOnBlack->DeserializeReadLock(op.sharedLockBlack(), this); - texOnWhite->DeserializeReadLock(op.sharedLockWhite(), this); + texOnBlack->SetReadLock(FindReadLock(op.sharedLockBlack())); + texOnWhite->SetReadLock(FindReadLock(op.sharedLockWhite())); MOZ_ASSERT(texOnBlack && texOnWhite); compositable->UseComponentAlphaTextures(texOnBlack, texOnWhite); @@ -283,6 +283,29 @@ CompositableParentManager::ReleaseCompositable(const CompositableHandle& aHandle host->Detach(nullptr, CompositableHost::FORCE_DETACH); } +bool +CompositableParentManager::AddReadLocks(ReadLockArray&& aReadLocks) +{ + for (ReadLockInit& r : aReadLocks) { + if (mReadLocks.find(r.handle().Value()) != mReadLocks.end()) { + NS_ERROR("Duplicate read lock handle!"); + return false; + } + mReadLocks[r.handle().Value()] = TextureReadLock::Deserialize(r.sharedLock(), this); + } + return true; +} + +TextureReadLock* +CompositableParentManager::FindReadLock(const ReadLockHandle& aHandle) +{ + auto iter = mReadLocks.find(aHandle.Value()); + if (iter == mReadLocks.end()) { + return nullptr; + } + return iter->second.get(); +} + } // namespace layers } // namespace mozilla diff --git a/gfx/layers/ipc/CompositableTransactionParent.h b/gfx/layers/ipc/CompositableTransactionParent.h index ad236b7a162e..47da2456562b 100644 --- a/gfx/layers/ipc/CompositableTransactionParent.h +++ b/gfx/layers/ipc/CompositableTransactionParent.h @@ -12,6 +12,7 @@ #include "mozilla/Attributes.h" // for override #include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator #include "mozilla/layers/LayersMessages.h" // for EditReply, etc +#include "mozilla/layers/TextureClient.h" #include "CompositableHost.h" namespace mozilla { @@ -24,6 +25,8 @@ namespace layers { class CompositableParentManager : public HostIPCAllocator { public: + typedef InfallibleTArray ReadLockArray; + CompositableParentManager() {} void DestroyActor(const OpDestroy& aOp); @@ -41,6 +44,9 @@ public: const TextureInfo& aInfo); RefPtr FindCompositable(const CompositableHandle& aHandle); + bool AddReadLocks(ReadLockArray&& aReadLocks); + TextureReadLock* FindReadLock(const ReadLockHandle& aLockHandle); + protected: /** * Handle the IPDL messages that affect PCompositable actors. @@ -55,6 +61,22 @@ protected: * Mapping form IDs to CompositableHosts. */ std::map> mCompositables; + std::map> mReadLocks; + +}; + +struct AutoClearReadLocks { + explicit AutoClearReadLocks(std::map>& aReadLocks) + : mReadLocks(aReadLocks) + + {} + + ~AutoClearReadLocks() + { + mReadLocks.clear(); + } + + std::map>& mReadLocks; }; } // namespace layers diff --git a/gfx/layers/ipc/ISurfaceAllocator.cpp b/gfx/layers/ipc/ISurfaceAllocator.cpp index 57da4d9cd8a7..45c23db34c56 100644 --- a/gfx/layers/ipc/ISurfaceAllocator.cpp +++ b/gfx/layers/ipc/ISurfaceAllocator.cpp @@ -11,6 +11,7 @@ #include "mozilla/layers/ImageBridgeParent.h" // for ImageBridgeParent #include "mozilla/layers/TextureHost.h" // for TextureHost #include "mozilla/layers/TextureForwarder.h" +#include "mozilla/layers/CompositableForwarder.h" namespace mozilla { namespace layers { @@ -19,6 +20,17 @@ NS_IMPL_ISUPPORTS(GfxMemoryImageReporter, nsIMemoryReporter) mozilla::Atomic GfxMemoryImageReporter::sAmount(0); +/* static */ uint32_t +CompositableForwarder::GetMaxFileDescriptorsPerMessage() { +#if defined(OS_POSIX) + static const uint32_t kMaxFileDescriptors = FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE; +#else + // default number that works everywhere else + static const uint32_t kMaxFileDescriptors = 250; +#endif + return kMaxFileDescriptors; +} + mozilla::ipc::SharedMemory::SharedMemoryType OptimalShmemType() { return ipc::SharedMemory::SharedMemoryType::TYPE_BASIC; diff --git a/gfx/layers/ipc/ImageBridgeChild.cpp b/gfx/layers/ipc/ImageBridgeChild.cpp index 107d95810be2..b18eab486b83 100644 --- a/gfx/layers/ipc/ImageBridgeChild.cpp +++ b/gfx/layers/ipc/ImageBridgeChild.cpp @@ -58,11 +58,13 @@ using namespace mozilla::media; typedef std::vector OpVector; typedef nsTArray OpDestroyVector; +typedef nsTArray ReadLockVector; struct CompositableTransaction { CompositableTransaction() - : mFinished(true) + : mReadLockSequenceNumber(0) + , mFinished(true) {} ~CompositableTransaction() { @@ -76,12 +78,15 @@ struct CompositableTransaction { MOZ_ASSERT(mFinished); mFinished = false; + mReadLockSequenceNumber = 0; + mReadLocks.AppendElement(); } void End() { mFinished = true; mOperations.clear(); mDestroyedActors.Clear(); + mReadLocks.Clear(); } bool IsEmpty() const { @@ -93,8 +98,21 @@ struct CompositableTransaction mOperations.push_back(op); } + ReadLockHandle AddReadLock(const ReadLockDescriptor& aReadLock) + { + ReadLockHandle handle(++mReadLockSequenceNumber); + if (mReadLocks.LastElement().Length() >= CompositableForwarder::GetMaxFileDescriptorsPerMessage()) { + mReadLocks.AppendElement(); + } + mReadLocks.LastElement().AppendElement(ReadLockInit(aReadLock, handle)); + return handle; + } + OpVector mOperations; OpDestroyVector mDestroyedActors; + nsTArray mReadLocks; + uint64_t mReadLockSequenceNumber; + bool mFinished; }; @@ -123,10 +141,13 @@ ImageBridgeChild::UseTextures(CompositableClient* aCompositable, } ReadLockDescriptor readLock; - t.mTextureClient->SerializeReadLock(readLock); + ReadLockHandle readLockHandle; + if (t.mTextureClient->SerializeReadLock(readLock)) { + readLockHandle = mTxn->AddReadLock(readLock); + } textures.AppendElement(TimedTexture(nullptr, t.mTextureClient->GetIPDLActor(), - readLock, + readLockHandle, t.mTimeStamp, t.mPictureRect, t.mFrameID, t.mProducerID)); @@ -142,32 +163,7 @@ ImageBridgeChild::UseComponentAlphaTextures(CompositableClient* aCompositable, TextureClient* aTextureOnBlack, TextureClient* aTextureOnWhite) { - MOZ_ASSERT(aCompositable); - MOZ_ASSERT(aTextureOnWhite); - MOZ_ASSERT(aTextureOnBlack); - MOZ_ASSERT(aCompositable->IsConnected()); - MOZ_ASSERT(aTextureOnWhite->GetIPDLActor()); - MOZ_ASSERT(aTextureOnBlack->GetIPDLActor()); - MOZ_ASSERT(aTextureOnBlack->GetSize() == aTextureOnWhite->GetSize()); - - ReadLockDescriptor readLockW; - ReadLockDescriptor readLockB; - aTextureOnBlack->SerializeReadLock(readLockB); - aTextureOnWhite->SerializeReadLock(readLockW); - - HoldUntilCompositableRefReleasedIfNecessary(aTextureOnBlack); - HoldUntilCompositableRefReleasedIfNecessary(aTextureOnWhite); - - mTxn->AddNoSwapEdit( - CompositableOperation( - aCompositable->GetIPCHandle(), - OpUseComponentAlphaTextures( - nullptr, aTextureOnBlack->GetIPDLActor(), - nullptr, aTextureOnWhite->GetIPDLActor(), - readLockB, readLockW - ) - ) - ); + MOZ_CRASH("should not be called"); } void @@ -543,6 +539,15 @@ ImageBridgeChild::EndTransaction() ShadowLayerForwarder::PlatformSyncBeforeUpdate(); } + for (ReadLockVector& locks : mTxn->mReadLocks) { + if (locks.Length()) { + if (!SendInitReadLocks(locks)) { + NS_WARNING("[LayersForwarder] WARNING: sending read locks failed!"); + return; + } + } + } + if (!SendUpdate(cset, mTxn->mDestroyedActors, GetFwdTransactionId())) { NS_WARNING("could not send async texture transaction"); return; diff --git a/gfx/layers/ipc/ImageBridgeParent.cpp b/gfx/layers/ipc/ImageBridgeParent.cpp index 9b8ac922bbfe..a419cdfb4db8 100644 --- a/gfx/layers/ipc/ImageBridgeParent.cpp +++ b/gfx/layers/ipc/ImageBridgeParent.cpp @@ -152,6 +152,15 @@ private: InfallibleTArray* mToDestroy; }; +mozilla::ipc::IPCResult +ImageBridgeParent::RecvInitReadLocks(ReadLockArray&& aReadLocks) +{ + if (!AddReadLocks(Move(aReadLocks))) { + return IPC_FAIL_NO_REASON(this); + } + return IPC_OK(); +} + mozilla::ipc::IPCResult ImageBridgeParent::RecvUpdate(EditArray&& aEdits, OpDestroyArray&& aToDestroy, const uint64_t& aFwdTransactionId) @@ -160,6 +169,7 @@ ImageBridgeParent::RecvUpdate(EditArray&& aEdits, OpDestroyArray&& aToDestroy, // to early-return from RecvUpdate without doing so. AutoImageBridgeParentAsyncMessageSender autoAsyncMessageSender(this, &aToDestroy); UpdateFwdTransactionId(aFwdTransactionId); + AutoClearReadLocks clearLocks(mReadLocks); for (EditArray::index_type i = 0; i < aEdits.Length(); ++i) { if (!ReceiveCompositableUpdate(aEdits[i])) { diff --git a/gfx/layers/ipc/ImageBridgeParent.h b/gfx/layers/ipc/ImageBridgeParent.h index d457069488ec..1067a9d1285c 100644 --- a/gfx/layers/ipc/ImageBridgeParent.h +++ b/gfx/layers/ipc/ImageBridgeParent.h @@ -70,6 +70,7 @@ public: // PImageBridge virtual mozilla::ipc::IPCResult RecvImageBridgeThreadId(const PlatformThreadId& aThreadId) override; + virtual mozilla::ipc::IPCResult RecvInitReadLocks(ReadLockArray&& aReadLocks) override; virtual mozilla::ipc::IPCResult RecvUpdate(EditArray&& aEdits, OpDestroyArray&& aToDestroy, const uint64_t& aFwdTransactionId) override; diff --git a/gfx/layers/ipc/LayerTransactionParent.cpp b/gfx/layers/ipc/LayerTransactionParent.cpp index 1c53a1610682..ae4436b29f67 100644 --- a/gfx/layers/ipc/LayerTransactionParent.cpp +++ b/gfx/layers/ipc/LayerTransactionParent.cpp @@ -132,6 +132,15 @@ LayerTransactionParent::RecvPaintTime(const uint64_t& aTransactionId, return IPC_OK(); } +mozilla::ipc::IPCResult +LayerTransactionParent::RecvInitReadLocks(ReadLockArray&& aReadLocks) +{ + if (!AddReadLocks(Move(aReadLocks))) { + return IPC_FAIL_NO_REASON(this); + } + return IPC_OK(); +} + mozilla::ipc::IPCResult LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo) { @@ -146,6 +155,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo) MOZ_LAYERS_LOG(("[ParentSide] received txn with %" PRIuSIZE " edits", aInfo.cset().Length())); UpdateFwdTransactionId(aInfo.fwdTransactionId()); + AutoClearReadLocks clearLocks(mReadLocks); if (mDestroyed || !layer_manager() || layer_manager()->IsDestroyed()) { for (const auto& op : aInfo.toDestroy()) { diff --git a/gfx/layers/ipc/LayerTransactionParent.h b/gfx/layers/ipc/LayerTransactionParent.h index ce8054fc7312..43e48c6fa817 100644 --- a/gfx/layers/ipc/LayerTransactionParent.h +++ b/gfx/layers/ipc/LayerTransactionParent.h @@ -43,6 +43,7 @@ class LayerTransactionParent final : public PLayerTransactionParent, typedef InfallibleTArray EditArray; typedef InfallibleTArray OpDestroyArray; typedef InfallibleTArray PluginsArray; + typedef InfallibleTArray ReadLockArray; public: LayerTransactionParent(HostLayerManager* aManager, @@ -111,6 +112,7 @@ protected: virtual mozilla::ipc::IPCResult RecvPaintTime(const uint64_t& aTransactionId, const TimeDuration& aPaintTime) override; + virtual mozilla::ipc::IPCResult RecvInitReadLocks(ReadLockArray&& aReadLocks) override; virtual mozilla::ipc::IPCResult RecvUpdate(const TransactionInfo& aInfo) override; virtual mozilla::ipc::IPCResult RecvSetLayerObserverEpoch(const uint64_t& aLayerObserverEpoch) override; diff --git a/gfx/layers/ipc/LayersMessages.ipdlh b/gfx/layers/ipc/LayersMessages.ipdlh index 6d300130aba8..82ee48d4892f 100644 --- a/gfx/layers/ipc/LayersMessages.ipdlh +++ b/gfx/layers/ipc/LayersMessages.ipdlh @@ -50,6 +50,7 @@ using mozilla::layers::BorderCorners from "mozilla/layers/LayersTypes.h"; using mozilla::layers::BorderWidths from "mozilla/layers/LayersTypes.h"; using mozilla::layers::LayerHandle from "mozilla/layers/LayersTypes.h"; using mozilla::layers::CompositableHandle from "mozilla/layers/LayersTypes.h"; +using mozilla::layers::ReadLockHandle from "mozilla/layers/LayersTypes.h"; using mozilla::layers::SimpleLayerAttributes from "mozilla/layers/LayerAttributes.h"; using mozilla::CrossProcessSemaphoreHandle from "mozilla/ipc/CrossProcessSemaphore.h"; @@ -348,6 +349,11 @@ union ReadLockDescriptor { null_t; }; +struct ReadLockInit { + ReadLockDescriptor sharedLock; + ReadLockHandle handle; +}; + union MaybeTexture { PTexture; null_t; @@ -403,7 +409,7 @@ struct OpRemoveTexture { struct TimedTexture { PTexture texture; - ReadLockDescriptor sharedLock; + ReadLockHandle sharedLock; TimeStamp timeStamp; IntRect picture; uint32_t frameID; @@ -427,8 +433,8 @@ struct OpUseTexture { struct OpUseComponentAlphaTextures { PTexture textureOnBlack; PTexture textureOnWhite; - ReadLockDescriptor sharedLockBlack; - ReadLockDescriptor sharedLockWhite; + ReadLockHandle sharedLockBlack; + ReadLockHandle sharedLockWhite; }; union MaybeRegion { diff --git a/gfx/layers/ipc/PImageBridge.ipdl b/gfx/layers/ipc/PImageBridge.ipdl index e40d3b61a8ee..a66713425218 100644 --- a/gfx/layers/ipc/PImageBridge.ipdl +++ b/gfx/layers/ipc/PImageBridge.ipdl @@ -38,6 +38,11 @@ child: parent: async ImageBridgeThreadId(PlatformThreadId aTreahdId); + // Creates a set of mappings between TextureReadLocks and an associated + // ReadLockHandle that can be used in Update, and persist until the + // next Update call. + async InitReadLocks(ReadLockInit[] locks); + async Update(CompositableOperation[] ops, OpDestroy[] toDestroy, uint64_t fwdTransactionId); // First step of the destruction sequence. This puts ImageBridge diff --git a/gfx/layers/ipc/PLayerTransaction.ipdl b/gfx/layers/ipc/PLayerTransaction.ipdl index e0ba8cf7c58e..cc230762cd15 100644 --- a/gfx/layers/ipc/PLayerTransaction.ipdl +++ b/gfx/layers/ipc/PLayerTransaction.ipdl @@ -50,6 +50,11 @@ sync protocol PLayerTransaction { manager PCompositorBridge; parent: + // Creates a set of mappings between TextureReadLocks and an associated + // ReadLockHandle that can be used in Update, and persist until the + // next Update call. + async InitReadLocks(ReadLockInit[] locks); + // The isFirstPaint flag can be used to indicate that this is the first update // for a particular document. async Update(TransactionInfo txn); diff --git a/gfx/layers/ipc/PWebRenderBridge.ipdl b/gfx/layers/ipc/PWebRenderBridge.ipdl index 34d4a1839c93..83e00f0a3fed 100644 --- a/gfx/layers/ipc/PWebRenderBridge.ipdl +++ b/gfx/layers/ipc/PWebRenderBridge.ipdl @@ -32,6 +32,11 @@ parent: async NewCompositable(CompositableHandle handle, TextureInfo info); async ReleaseCompositable(CompositableHandle compositable); + // Creates a set of mappings between TextureReadLocks and an associated + // ReadLockHandle that can be used in Update, and persist until the + // next Update call. + async InitReadLocks(ReadLockInit[] locks); + sync Create(IntSize aSize); sync AddImage(ImageKey aImageKey, IntSize aSize, uint32_t aStride, SurfaceFormat aFormat, ByteBuffer aBytes); diff --git a/gfx/layers/ipc/ShadowLayers.cpp b/gfx/layers/ipc/ShadowLayers.cpp index 2099d23b20a0..aaf5fb24835e 100644 --- a/gfx/layers/ipc/ShadowLayers.cpp +++ b/gfx/layers/ipc/ShadowLayers.cpp @@ -54,12 +54,14 @@ typedef nsTArray BufferArray; typedef nsTArray EditVector; typedef nsTHashtable> ShadowableLayerSet; typedef nsTArray OpDestroyVector; +typedef nsTArray ReadLockVector; class Transaction { public: Transaction() - : mTargetRotation(ROTATION_0) + : mReadLockSequenceNumber(0) + , mTargetRotation(ROTATION_0) , mOpen(false) , mRotationChanged(false) {} @@ -78,6 +80,8 @@ public: } mTargetRotation = aRotation; mTargetOrientation = aOrientation; + mReadLockSequenceNumber = 0; + mReadLocks.AppendElement(); } void AddEdit(const Edit& aEdit) { @@ -104,6 +108,15 @@ public: MOZ_ASSERT(!Finished(), "forgot BeginTransaction?"); mSimpleMutants.PutEntry(aLayer); } + ReadLockHandle AddReadLock(const ReadLockDescriptor& aReadLock) + { + ReadLockHandle handle(++mReadLockSequenceNumber); + if (mReadLocks.LastElement().Length() >= CompositableForwarder::GetMaxFileDescriptorsPerMessage()) { + mReadLocks.AppendElement(); + } + mReadLocks.LastElement().AppendElement(ReadLockInit(aReadLock, handle)); + return handle; + } void End() { mCset.Clear(); @@ -111,6 +124,7 @@ public: mMutants.Clear(); mSimpleMutants.Clear(); mDestroyedActors.Clear(); + mReadLocks.Clear(); mOpen = false; mRotationChanged = false; } @@ -134,6 +148,8 @@ public: OpDestroyVector mDestroyedActors; ShadowableLayerSet mMutants; ShadowableLayerSet mSimpleMutants; + nsTArray mReadLocks; + uint64_t mReadLockSequenceNumber; gfx::IntRect mTargetBounds; ScreenRotation mTargetRotation; dom::ScreenOrientationInternal mTargetOrientation; @@ -420,9 +436,12 @@ ShadowLayerForwarder::UseTextures(CompositableClient* aCompositable, MOZ_ASSERT(t.mTextureClient->GetIPDLActor()); MOZ_RELEASE_ASSERT(t.mTextureClient->GetIPDLActor()->GetIPCChannel() == mShadowManager->GetIPCChannel()); ReadLockDescriptor readLock; - t.mTextureClient->SerializeReadLock(readLock); + ReadLockHandle readLockHandle; + if (t.mTextureClient->SerializeReadLock(readLock)) { + readLockHandle = mTxn->AddReadLock(readLock); + } textures.AppendElement(TimedTexture(nullptr, t.mTextureClient->GetIPDLActor(), - readLock, + readLockHandle, t.mTimeStamp, t.mPictureRect, t.mFrameID, t.mProducerID)); mClientLayerManager->GetCompositorBridgeChild()->HoldUntilCompositableRefReleasedIfNecessary(t.mTextureClient); @@ -451,10 +470,16 @@ ShadowLayerForwarder::UseComponentAlphaTextures(CompositableClient* aCompositabl MOZ_RELEASE_ASSERT(aTextureOnWhite->GetIPDLActor()->GetIPCChannel() == mShadowManager->GetIPCChannel()); MOZ_RELEASE_ASSERT(aTextureOnBlack->GetIPDLActor()->GetIPCChannel() == mShadowManager->GetIPCChannel()); - ReadLockDescriptor readLockW; ReadLockDescriptor readLockB; - aTextureOnBlack->SerializeReadLock(readLockB); - aTextureOnWhite->SerializeReadLock(readLockW); + ReadLockHandle readLockHandleB; + ReadLockDescriptor readLockW; + ReadLockHandle readLockHandleW; + if (aTextureOnBlack->SerializeReadLock(readLockB)) { + readLockHandleB = mTxn->AddReadLock(readLockB); + } + if (aTextureOnWhite->SerializeReadLock(readLockW)) { + readLockHandleW = mTxn->AddReadLock(readLockW); + } mClientLayerManager->GetCompositorBridgeChild()->HoldUntilCompositableRefReleasedIfNecessary(aTextureOnBlack); mClientLayerManager->GetCompositorBridgeChild()->HoldUntilCompositableRefReleasedIfNecessary(aTextureOnWhite); @@ -465,7 +490,7 @@ ShadowLayerForwarder::UseComponentAlphaTextures(CompositableClient* aCompositabl OpUseComponentAlphaTextures( nullptr, aTextureOnBlack->GetIPDLActor(), nullptr, aTextureOnWhite->GetIPDLActor(), - readLockB, readLockW) + readLockHandleB, readLockHandleW) ) ); } @@ -698,6 +723,15 @@ ShadowLayerForwarder::EndTransaction(const nsIntRegion& aRegionToClear, PlatformSyncBeforeUpdate(); } + for (ReadLockVector& locks : mTxn->mReadLocks) { + if (locks.Length()) { + if (!mShadowManager->SendInitReadLocks(locks)) { + MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending read locks failed!")); + return false; + } + } + } + MOZ_LAYERS_LOG(("[LayersForwarder] sending transaction...")); RenderTraceScope rendertrace3("Forward Transaction", "000093"); if (!mShadowManager->SendUpdate(info)) { diff --git a/gfx/layers/wr/WebRenderBridgeChild.cpp b/gfx/layers/wr/WebRenderBridgeChild.cpp index 36217ec792d1..dd210201849b 100644 --- a/gfx/layers/wr/WebRenderBridgeChild.cpp +++ b/gfx/layers/wr/WebRenderBridgeChild.cpp @@ -17,7 +17,8 @@ namespace mozilla { namespace layers { WebRenderBridgeChild::WebRenderBridgeChild(const wr::PipelineId& aPipelineId) - : mIsInTransaction(false) + : mReadLockSequenceNumber(0) + , mIsInTransaction(false) , mIdNamespace(0) , mResourceId(0) , mPipelineId(aPipelineId) @@ -82,6 +83,8 @@ WebRenderBridgeChild::DPBegin(const gfx::IntSize& aSize) UpdateFwdTransactionId(); this->SendDPBegin(aSize); mIsInTransaction = true; + mReadLockSequenceNumber = 0; + mReadLocks.AppendElement(); return true; } @@ -197,6 +200,15 @@ WebRenderBridgeChild::DPEnd(const gfx::IntSize& aSize, bool aIsSync, uint64_t aT MOZ_ASSERT(!mDestroyed); MOZ_ASSERT(mIsInTransaction); + for (nsTArray& locks : mReadLocks) { + if (locks.Length()) { + if (!SendInitReadLocks(locks)) { + NS_WARNING("WARNING: sending read locks failed!"); + return; + } + } + } + wr::BuiltDisplayList dl = ProcessWebrenderCommands(aSize, mCommands); ByteBuffer dlData(Move(dl.dl)); ByteBuffer auxData(Move(dl.aux)); @@ -212,6 +224,7 @@ WebRenderBridgeChild::DPEnd(const gfx::IntSize& aSize, bool aIsSync, uint64_t aT mCommands.Clear(); mParentCommands.Clear(); mDestroyedActors.Clear(); + mReadLocks.Clear(); mIsInTransaction = false; } @@ -376,9 +389,16 @@ WebRenderBridgeChild::UseTextures(CompositableClient* aCompositable, MOZ_ASSERT(t.mTextureClient->GetIPDLActor()); MOZ_RELEASE_ASSERT(t.mTextureClient->GetIPDLActor()->GetIPCChannel() == GetIPCChannel()); ReadLockDescriptor readLock; - t.mTextureClient->SerializeReadLock(readLock); + ReadLockHandle readLockHandle; + if (t.mTextureClient->SerializeReadLock(readLock)) { + readLockHandle = ReadLockHandle(++mReadLockSequenceNumber); + if (mReadLocks.LastElement().Length() >= GetMaxFileDescriptorsPerMessage()) { + mReadLocks.AppendElement(); + } + mReadLocks.LastElement().AppendElement(ReadLockInit(readLock, readLockHandle)); + } textures.AppendElement(TimedTexture(nullptr, t.mTextureClient->GetIPDLActor(), - readLock, + readLockHandle, t.mTimeStamp, t.mPictureRect, t.mFrameID, t.mProducerID)); GetCompositorBridgeChild()->HoldUntilCompositableRefReleasedIfNecessary(t.mTextureClient); diff --git a/gfx/layers/wr/WebRenderBridgeChild.h b/gfx/layers/wr/WebRenderBridgeChild.h index 49b918ab7ac2..85de0a3b730a 100644 --- a/gfx/layers/wr/WebRenderBridgeChild.h +++ b/gfx/layers/wr/WebRenderBridgeChild.h @@ -114,6 +114,8 @@ private: nsTArray mParentCommands; nsTArray mDestroyedActors; nsDataHashtable mCompositables; + nsTArray> mReadLocks; + uint64_t mReadLockSequenceNumber; bool mIsInTransaction; uint32_t mIdNamespace; uint32_t mResourceId; diff --git a/gfx/layers/wr/WebRenderBridgeParent.cpp b/gfx/layers/wr/WebRenderBridgeParent.cpp index b919206d618c..657b4829c512 100644 --- a/gfx/layers/wr/WebRenderBridgeParent.cpp +++ b/gfx/layers/wr/WebRenderBridgeParent.cpp @@ -226,6 +226,7 @@ WebRenderBridgeParent::HandleDPEnd(const gfx::IntSize& aSize, const WrAuxiliaryListsDescriptor& auxDesc) { UpdateFwdTransactionId(aFwdTransactionId); + AutoClearReadLocks clearLocks(mReadLocks); if (mDestroyed) { for (const auto& op : aToDestroy) { @@ -653,6 +654,15 @@ WebRenderBridgeParent::RecvReleaseCompositable(const CompositableHandle& aHandle return IPC_OK(); } +mozilla::ipc::IPCResult +WebRenderBridgeParent::RecvInitReadLocks(ReadLockArray&& aReadLocks) +{ + if (!AddReadLocks(Move(aReadLocks))) { + return IPC_FAIL_NO_REASON(this); + } + return IPC_OK(); +} + void WebRenderBridgeParent::SetWebRenderProfilerEnabled(bool aEnabled) { diff --git a/gfx/layers/wr/WebRenderBridgeParent.h b/gfx/layers/wr/WebRenderBridgeParent.h index 6799f72959ec..4c128b89215a 100644 --- a/gfx/layers/wr/WebRenderBridgeParent.h +++ b/gfx/layers/wr/WebRenderBridgeParent.h @@ -59,6 +59,8 @@ public: const TextureInfo& aInfo) override; mozilla::ipc::IPCResult RecvReleaseCompositable(const CompositableHandle& aHandle) override; + mozilla::ipc::IPCResult RecvInitReadLocks(ReadLockArray&& aReadLocks) override; + mozilla::ipc::IPCResult RecvCreate(const gfx::IntSize& aSize) override; mozilla::ipc::IPCResult RecvShutdown() override; mozilla::ipc::IPCResult RecvAddImage(const wr::ImageKey& aImageKey,