author | Nicolas Silva <nsilva@mozilla.com> |
Thu, 07 Jan 2016 11:17:40 +0100 | |
changeset 278876 | ed482fa2c0c636c8e009d6e50cd66c64c25775e5 |
parent 278875 | 524b2e90d33ffcff023463497f9f5baa347f7826 |
child 278877 | 82ddde197552207ce661dfa61233dbaeacb71e80 |
push id | 69922 |
push user | nsilva@mozilla.com |
push date | Thu, 07 Jan 2016 10:17:58 +0000 |
treeherder | mozilla-inbound@ed482fa2c0c6 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | sotaro |
bugs | 1221056 |
milestone | 46.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/gfx/layers/IPDLActor.h +++ b/gfx/layers/IPDLActor.h @@ -2,16 +2,17 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef MOZILLA_LAYERS_IPDLACTOR_H #define MOZILLA_LAYERS_IPDLACTOR_H #include "mozilla/ipc/ProtocolUtils.h" +#include "mozilla/layers/CompositableForwarder.h" #include "mozilla/unused.h" namespace mozilla { namespace layers { /// A base class to facilitate the deallocation of IPDL actors. /// /// This class implements a simple deallocation protocol that avoids races @@ -43,43 +44,54 @@ public: /// Check the return of CanSend before sending any message! bool CanSend() const { return !mDestroyed; } /// The normal way to destroy the actor. /// /// This will asynchronously send a Destroy message to the parent actor, whom /// will send the delete message. - void Destroy() + void Destroy(CompositableForwarder* aFwd = nullptr) { MOZ_ASSERT(!mDestroyed); if (!mDestroyed) { mDestroyed = true; DestroyManagees(); - this->SendDestroy(); + if (!aFwd || !aFwd->DestroyInTransaction(this, false)) { + this->SendDestroy(); + } } } /// The ugly and slow way to destroy the actor. /// /// This will block until the Parent actor has handled the Destroy message, /// and then start the asynchronous handshake (and destruction will already /// be done on the parent side, when the async part happens). - void DestroySynchronously() + void DestroySynchronously(CompositableForwarder* aFwd = nullptr) { MOZ_PERFORMANCE_WARNING("gfx", "IPDL actor requires synchronous deallocation"); MOZ_ASSERT(!mDestroyed); if (!mDestroyed) { DestroyManagees(); mDestroyed = true; - this->SendDestroySync(); - this->SendDestroy(); + if (!aFwd || !aFwd->DestroyInTransaction(this, true)) { + this->SendDestroySync(); + this->SendDestroy(); + } } } + /// If the transaction that was supposed to destroy the texture fails for + /// whatever reason, fallback to destroying the actor synchronously. + static bool DestroyFallback(Protocol* aActor) + { + return aActor->SendDestroySync(); + } + /// Override this if the protocol manages other protocols, and destroy the /// managees from there virtual void DestroyManagees() {} private: bool mDestroyed; };
--- a/gfx/layers/client/ClientLayerManager.cpp +++ b/gfx/layers/client/ClientLayerManager.cpp @@ -640,18 +640,16 @@ ClientLayerManager::ForwardTransaction(b if (!sent) { // Clear the transaction id so that it doesn't get returned // unless we forwarded to somewhere that doesn't actually // have a compositor. mTransactionIdAllocator->RevokeTransactionId(mLatestTransactionId); } - mForwarder->RemoveTexturesIfNecessary(); - mForwarder->RemoveCompositablesIfNecessary(); mForwarder->SendPendingAsyncMessges(); mPhase = PHASE_NONE; // this may result in Layers being deleted, which results in // PLayer::Send__delete__() and DeallocShmem() mKeepAlive.Clear(); TabChild* window = mWidget->GetOwningTabChild();
--- a/gfx/layers/client/ClientTiledPaintedLayer.cpp +++ b/gfx/layers/client/ClientTiledPaintedLayer.cpp @@ -407,17 +407,16 @@ void ClientTiledPaintedLayer::RenderLayer() { LayerManager::DrawPaintedLayerCallback callback = ClientManager()->GetPaintedLayerCallback(); void *data = ClientManager()->GetPaintedLayerCallbackData(); IntSize layerSize = mVisibleRegion.ToUnknownRegion().GetBounds().Size(); if (mContentClient && !mContentClient->SupportsLayerSize(layerSize, ClientManager())) { - ClientManager()->AsShadowForwarder()->HoldUntilTransaction(mContentClient); mContentClient = nullptr; mValidRegion.SetEmpty(); } if (!mContentClient) { if (mCreationHint == LayerManager::NONE && SingleTiledContentClient::ClientSupportsLayerSize(layerSize, ClientManager()) && gfxPrefs::LayersSingleTileEnabled()) {
--- a/gfx/layers/client/CompositableClient.cpp +++ b/gfx/layers/client/CompositableClient.cpp @@ -175,25 +175,32 @@ CompositableClient::IsConnected() const } void CompositableClient::Destroy() { if (!IsConnected()) { return; } - // Send pending AsyncMessages before deleting CompositableChild. - // They might have dependency to the mCompositableChild. + + // Send pending AsyncMessages before deleting CompositableChild since the former + // might have references to the latter. mForwarder->SendPendingAsyncMessges(); - // Destroy CompositableChild. + mCompositableChild->mCompositableClient = nullptr; - mCompositableChild->Destroy(); + mCompositableChild->Destroy(mForwarder); mCompositableChild = nullptr; } +bool +CompositableClient::DestroyFallback(PCompositableChild* aActor) +{ + return aActor->SendDestroySync(); +} + uint64_t CompositableClient::GetAsyncID() const { if (mCompositableChild) { return mCompositableChild->mAsyncID; } return 0; // zero is always an invalid async ID }
--- a/gfx/layers/client/CompositableClient.h +++ b/gfx/layers/client/CompositableClient.h @@ -150,16 +150,18 @@ public: /** * Establishes the connection with compositor side through IPDL */ virtual bool Connect(ImageContainer* aImageContainer = nullptr); void Destroy(); + static bool DestroyFallback(PCompositableChild* aActor); + bool IsConnected() const; PCompositableChild* GetIPDLActor() const; // should only be called by a CompositableForwarder virtual void SetIPDLActor(CompositableChild* aChild); CompositableForwarder* GetForwarder() const
--- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -295,23 +295,23 @@ DeallocateTextureClient(TextureDeallocPa // race causing this function to be called concurrently which is bad! gfxCriticalError() << "Racy texture deallocation"; return; } if (params.syncDeallocation) { MOZ_PERFORMANCE_WARNING("gfx", "TextureClient/Host pair requires synchronous deallocation"); - actor->DestroySynchronously(); + actor->DestroySynchronously(actor->GetForwarder()); DestroyTextureData(params.data, params.allocator, params.clientDeallocation, actor->mMainThreadOnly); } else { actor->mTextureData = params.data; actor->mOwnsTextureData = params.clientDeallocation; - actor->Destroy(); + actor->Destroy(actor->GetForwarder()); // DestroyTextureData will be called by TextureChild::ActorDestroy } } void TextureClient::Destroy(bool aForceSync) { MOZ_ASSERT(!IsLocked()); @@ -342,16 +342,24 @@ void TextureClient::Destroy(bool aForceS // client side, but having asynchronous deallocate in some of the cases will // be a worthwhile optimization. params.syncDeallocation = !!(mFlags & TextureFlags::DEALLOCATE_CLIENT) || aForceSync; DeallocateTextureClient(params); } } bool +TextureClient::DestroyFallback(PTextureChild* aActor) +{ + // should not end up here so crash debug builds. + MOZ_ASSERT(false); + return aActor->SendDestroySync(); +} + +bool TextureClient::Lock(OpenMode aMode) { MOZ_ASSERT(IsValid()); MOZ_ASSERT(!mIsLocked); if (mIsLocked) { return mOpenMode == aMode; }
--- a/gfx/layers/client/TextureClient.h +++ b/gfx/layers/client/TextureClient.h @@ -416,16 +416,18 @@ public: * * TextureChild is an implementation detail of TextureClient that is not * exposed to the rest of the code base. CreateIPDLActor and DestroyIPDLActor * are for use with the managing IPDL protocols only (so that they can * implement AllocPextureChild and DeallocPTextureChild). */ static PTextureChild* CreateIPDLActor(); static bool DestroyIPDLActor(PTextureChild* actor); + // call this if the transaction that was supposed to destroy the actor failed. + static bool DestroyFallback(PTextureChild* actor); /** * Get the TextureClient corresponding to the actor passed in parameter. */ static TextureClient* AsTextureClient(PTextureChild* actor); gfx::IntSize GetSize() const;
--- a/gfx/layers/composite/CompositableHost.cpp +++ b/gfx/layers/composite/CompositableHost.cpp @@ -222,16 +222,22 @@ CompositableHost::DumpTextureHost(std::s } RefPtr<gfx::DataSourceSurface> dSurf = aTexture->GetAsSurface(); if (!dSurf) { return; } aStream << gfxUtils::GetAsDataURI(dSurf).get(); } +void +CompositableHost::ReceivedDestroy(PCompositableParent* aActor) +{ + static_cast<CompositableParent*>(aActor)->RecvDestroy(); +} + namespace CompositableMap { typedef std::map<uint64_t, PCompositableParent*> CompositableMap_t; static CompositableMap_t* sCompositableMap = nullptr; bool IsCreated() { return sCompositableMap != nullptr; } PCompositableParent* Get(uint64_t aID)
--- a/gfx/layers/composite/CompositableHost.h +++ b/gfx/layers/composite/CompositableHost.h @@ -171,16 +171,19 @@ public: aFlags & FORCE_DETACH) { SetLayer(nullptr); mAttached = false; mKeepAttached = false; } } bool IsAttached() { return mAttached; } + static void + ReceivedDestroy(PCompositableParent* aActor); + virtual void Dump(std::stringstream& aStream, const char* aPrefix="", bool aDumpHtml=false) { } static void DumpTextureHost(std::stringstream& aStream, TextureHost* aTexture); virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() { return nullptr; } virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) = 0;
--- a/gfx/layers/composite/TextureHost.cpp +++ b/gfx/layers/composite/TextureHost.cpp @@ -830,16 +830,22 @@ TextureParent::Destroy() // Clear recycle callback. mTextureHost->ClearRecycleCallback(); mWaitForClientRecycle = nullptr; mTextureHost->mActor = nullptr; mTextureHost = nullptr; } +void +TextureHost::ReceivedDestroy(PTextureParent* aActor) +{ + static_cast<TextureParent*>(aActor)->RecvDestroy(); +} + bool TextureParent::RecvRecycleTexture(const TextureFlags& aTextureFlags) { if (!mTextureHost) { return true; } mTextureHost->RecycleTexture(aTextureFlags); return true;
--- a/gfx/layers/composite/TextureHost.h +++ b/gfx/layers/composite/TextureHost.h @@ -458,16 +458,18 @@ public: TextureFlags aFlags); static bool DestroyIPDLActor(PTextureParent* actor); /** * Destroy the TextureChild/Parent pair. */ static bool SendDeleteIPDLActor(PTextureParent* actor); + static void ReceivedDestroy(PTextureParent* actor); + /** * Get the TextureHost corresponding to the actor passed in parameter. */ static TextureHost* AsTextureHost(PTextureParent* actor); /** * Return a pointer to the IPDLActor. *
--- a/gfx/layers/ipc/CompositableForwarder.h +++ b/gfx/layers/ipc/CompositableForwarder.h @@ -79,16 +79,19 @@ public: const nsIntRegion& aUpdatedRegion) = 0; #ifdef MOZ_WIDGET_GONK virtual void UseOverlaySource(CompositableClient* aCompositabl, const OverlaySource& aOverlay, const gfx::IntRect& aPictureRect) = 0; #endif + virtual bool DestroyInTransaction(PTextureChild* aTexture, bool synchronously) = 0; + virtual bool DestroyInTransaction(PCompositableChild* aCompositable, bool synchronously) = 0; + /** * Tell the CompositableHost on the compositor side to remove the texture * from the CompositableHost. * This function does not delete the TextureHost corresponding to the * TextureClient passed in parameter. * When the TextureClient has TEXTURE_DEALLOCATE_CLIENT flag, * the transaction becomes synchronous. */ @@ -103,50 +106,16 @@ public: * TextureClient passed in parameter. * It is used when the TextureClient recycled. * Only ImageBridge implements it. */ virtual void RemoveTextureFromCompositableAsync(AsyncTransactionTracker* aAsyncTransactionTracker, CompositableClient* aCompositable, TextureClient* aTexture) {} - /** - * Holds a reference to a TextureClient until after the next - * compositor transaction, and then drops it. - */ - virtual void HoldUntilTransaction(TextureClient* aClient) - { - if (aClient) { - mTexturesToRemove.AppendElement(aClient); - } - } - - /** - * Forcibly remove texture data from TextureClient - * This function needs to be called after a tansaction with Compositor. - */ - virtual void RemoveTexturesIfNecessary() - { - mTexturesToRemove.Clear(); - } - - /** - * The same as above, but for CompositableClients. - */ - void HoldUntilTransaction(CompositableClient* aClient) - { - if (aClient) { - mCompositableClientsToRemove.AppendElement(aClient); - } - } - void RemoveCompositablesIfNecessary() - { - mCompositableClientsToRemove.Clear(); - } - struct TimedTextureClient { TimedTextureClient() : mTextureClient(nullptr), mFrameID(0), mProducerID(0) {} TextureClient* mTextureClient; TimeStamp mTimeStamp; nsIntRect mPictureRect; int32_t mFrameID;
--- a/gfx/layers/ipc/CompositableTransactionParent.cpp +++ b/gfx/layers/ipc/CompositableTransactionParent.cpp @@ -228,18 +228,43 @@ CompositableParentManager::ReceiveCompos MOZ_ASSERT(false, "bad type"); } } return true; } void +CompositableParentManager::DestroyActor(const OpDestroy& aOp) +{ + switch (aOp.type()) { + case OpDestroy::TPTextureParent: { + auto actor = aOp.get_PTextureParent(); + TextureHost::ReceivedDestroy(actor); + break; + } + case OpDestroy::TPCompositableParent: { + auto actor = aOp.get_PCompositableParent(); + CompositableHost::ReceivedDestroy(actor); + break; + } + default: { + MOZ_ASSERT(false, "unsupported type"); + } + } +} + +void CompositableParentManager::SendPendingAsyncMessages() { + for (auto& actor : mDestroyedTextures) { + TextureHost::SendDeleteIPDLActor(actor); + } + mDestroyedTextures.clear(); + if (mPendingAsyncMessage.empty()) { return; } // Some type of AsyncParentMessageData message could have // one file descriptor (e.g. OpDeliverFence). // A number of file descriptors per gecko ipc message have a limitation // on OS_POSIX (MACOSX or LINUX).
--- a/gfx/layers/ipc/CompositableTransactionParent.h +++ b/gfx/layers/ipc/CompositableTransactionParent.h @@ -41,25 +41,28 @@ public: virtual base::ProcessId GetChildProcessId() = 0; protected: /** * Handle the IPDL messages that affect PCompositable actors. */ bool ReceiveCompositableUpdate(const CompositableOperation& aEdit, EditReplyVector& replyv); + void DestroyActor(const OpDestroy& aOp); + bool IsOnCompositorSide() const override { return true; } /** * Return true if this protocol is asynchronous with respect to the content * thread (ImageBridge for instance). */ virtual bool IsAsync() const { return false; } virtual void ReplyRemoveTexture(const OpReplyRemoveTexture& aReply) {} std::vector<AsyncParentMessageData> mPendingAsyncMessage; + std::vector<PTextureParent*> mDestroyedTextures; }; } // namespace layers } // namespace mozilla #endif
--- a/gfx/layers/ipc/ImageBridgeChild.cpp +++ b/gfx/layers/ipc/ImageBridgeChild.cpp @@ -51,16 +51,17 @@ namespace layers { using base::Thread; using base::ProcessId; using namespace mozilla::ipc; using namespace mozilla::gfx; using namespace mozilla::media; typedef std::vector<CompositableOperation> OpVector; +typedef nsTArray<OpDestroy> OpDestroyVector; struct CompositableTransaction { CompositableTransaction() : mSwapRequired(false) , mFinished(true) {} ~CompositableTransaction() @@ -76,33 +77,59 @@ struct CompositableTransaction MOZ_ASSERT(mFinished); mFinished = false; } void End() { mFinished = true; mSwapRequired = false; mOperations.clear(); + mDestroyedActors.Clear(); } bool IsEmpty() const { - return mOperations.empty(); + return mOperations.empty() && mDestroyedActors.IsEmpty(); } void AddNoSwapEdit(const CompositableOperation& op) { MOZ_ASSERT(!Finished(), "forgot BeginTransaction?"); mOperations.push_back(op); } void AddEdit(const CompositableOperation& op) { AddNoSwapEdit(op); + MarkSyncTransaction(); + } + void MarkSyncTransaction() + { mSwapRequired = true; } + void FallbackDestroyActors() + { + for (auto& actor : mDestroyedActors) { + switch (actor.type()) { + case OpDestroy::TPTextureChild: { + DebugOnly<bool> ok = TextureClient::DestroyFallback(actor.get_PTextureChild()); + MOZ_ASSERT(ok); + break; + } + case OpDestroy::TPCompositableChild: { + DebugOnly<bool> ok = CompositableClient::DestroyFallback(actor.get_PCompositableChild()); + MOZ_ASSERT(ok); + break; + } + default: MOZ_CRASH(); + } + } + mDestroyedActors.Clear(); + } + OpVector mOperations; + OpDestroyVector mDestroyedActors; bool mSwapRequired; bool mFinished; }; struct AutoEndTransaction { explicit AutoEndTransaction(CompositableTransaction* aTxn) : mTxn(aTxn) {} ~AutoEndTransaction() { mTxn->End(); } CompositableTransaction* mTxn; @@ -173,16 +200,22 @@ ImageBridgeChild::UseOverlaySource(Compo static StaticRefPtr<ImageBridgeChild> sImageBridgeChildSingleton; static StaticRefPtr<ImageBridgeParent> sImageBridgeParentSingleton; static Thread *sImageBridgeChildThread = nullptr; void ReleaseImageBridgeParentSingleton() { sImageBridgeParentSingleton = nullptr; } +void +ImageBridgeChild::FallbackDestroyActors() { + if (mTxn && !mTxn->mDestroyedActors.IsEmpty()) { + mTxn->FallbackDestroyActors(); + } +} // dispatched function static void ImageBridgeShutdownStep1(ReentrantMonitor *aBarrier, bool *aDone) { ReentrantMonitorAutoEnter autoMon(*aBarrier); MOZ_ASSERT(InImageBridgeChildThread(), "Should be in ImageBridgeChild thread."); @@ -199,16 +232,18 @@ static void ImageBridgeShutdownStep1(Ree InfallibleTArray<PTextureChild*> textures; sImageBridgeChildSingleton->ManagedPTextureChild(textures); for (int i = textures.Length() - 1; i >= 0; --i) { RefPtr<TextureClient> client = TextureClient::AsTextureClient(textures[i]); if (client) { client->Destroy(); } } + sImageBridgeChildSingleton->FallbackDestroyActors(); + sImageBridgeChildSingleton->SendWillStop(); sImageBridgeChildSingleton->MarkShutDown(); // From now on, no message can be sent through the image bridge from the // client side except the final Stop message. } *aDone = true; aBarrier->NotifyAll(); @@ -602,38 +637,23 @@ void ImageBridgeChild::FlushAllImages(Im void ImageBridgeChild::BeginTransaction() { MOZ_ASSERT(!mShuttingDown); MOZ_ASSERT(mTxn->Finished(), "uncommitted txn?"); mTxn->Begin(); } -class MOZ_STACK_CLASS AutoRemoveTexturesFromImageBridge -{ -public: - explicit AutoRemoveTexturesFromImageBridge(ImageBridgeChild* aImageBridge) - : mImageBridge(aImageBridge) {} - - ~AutoRemoveTexturesFromImageBridge() - { - mImageBridge->RemoveTexturesIfNecessary(); - } -private: - ImageBridgeChild* mImageBridge; -}; - void ImageBridgeChild::EndTransaction() { MOZ_ASSERT(!mShuttingDown); MOZ_ASSERT(!mTxn->Finished(), "forgot BeginTransaction?"); AutoEndTransaction _(mTxn); - AutoRemoveTexturesFromImageBridge autoRemoveTextures(this); if (mTxn->IsEmpty()) { return; } AutoInfallibleTArray<CompositableOperation, 10> cset; cset.SetCapacity(mTxn->mOperations.size()); if (!mTxn->mOperations.empty()) { @@ -642,25 +662,27 @@ ImageBridgeChild::EndTransaction() if (!IsSameProcess()) { ShadowLayerForwarder::PlatformSyncBeforeUpdate(); } AutoInfallibleTArray<EditReply, 10> replies; if (mTxn->mSwapRequired) { - if (!SendUpdate(cset, &replies)) { + if (!SendUpdate(cset, mTxn->mDestroyedActors, &replies)) { NS_WARNING("could not send async texture transaction"); + mTxn->FallbackDestroyActors(); return; } } else { // If we don't require a swap we can call SendUpdateNoSwap which // assumes that aReplies is empty (DEBUG assertion) - if (!SendUpdateNoSwap(cset)) { + if (!SendUpdateNoSwap(cset, mTxn->mDestroyedActors)) { NS_WARNING("could not send async texture transaction (no swap)"); + mTxn->FallbackDestroyActors(); return; } } for (nsTArray<EditReply>::size_type i = 0; i < replies.Length(); ++i) { NS_RUNTIMEABORT("not reached"); } SendPendingAsyncMessges(); } @@ -1091,16 +1113,45 @@ PTextureChild* ImageBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData, LayersBackend aLayersBackend, TextureFlags aFlags) { MOZ_ASSERT(!mShuttingDown); return SendPTextureConstructor(aSharedData, aLayersBackend, aFlags); } +static bool +IBCAddOpDestroy(CompositableTransaction* aTxn, const OpDestroy& op, bool synchronously) +{ + if (aTxn->Finished()) { + return false; + } + + aTxn->mDestroyedActors.AppendElement(op); + + if (synchronously) { + aTxn->MarkSyncTransaction(); + } + + return true; +} + +bool +ImageBridgeChild::DestroyInTransaction(PTextureChild* aTexture, bool synchronously) +{ + return IBCAddOpDestroy(mTxn, OpDestroy(aTexture), synchronously); +} + +bool +ImageBridgeChild::DestroyInTransaction(PCompositableChild* aCompositable, bool synchronously) +{ + return IBCAddOpDestroy(mTxn, OpDestroy(aCompositable), synchronously); +} + + void ImageBridgeChild::RemoveTextureFromCompositable(CompositableClient* aCompositable, TextureClient* aTexture) { MOZ_ASSERT(!mShuttingDown); MOZ_ASSERT(aTexture); MOZ_ASSERT(aTexture->IsSharedWithCompositor()); MOZ_ASSERT(aCompositable->IsConnected()); @@ -1109,18 +1160,16 @@ ImageBridgeChild::RemoveTextureFromCompo } if (aTexture->GetFlags() & TextureFlags::DEALLOCATE_CLIENT) { mTxn->AddEdit(OpRemoveTexture(nullptr, aCompositable->GetIPDLActor(), nullptr, aTexture->GetIPDLActor())); } else { mTxn->AddNoSwapEdit(OpRemoveTexture(nullptr, aCompositable->GetIPDLActor(), nullptr, aTexture->GetIPDLActor())); } - // Hold texture until transaction complete. - HoldUntilTransaction(aTexture); } void ImageBridgeChild::RemoveTextureFromCompositableAsync(AsyncTransactionTracker* aAsyncTransactionTracker, CompositableClient* aCompositable, TextureClient* aTexture) { MOZ_ASSERT(!mShuttingDown);
--- a/gfx/layers/ipc/ImageBridgeChild.h +++ b/gfx/layers/ipc/ImageBridgeChild.h @@ -257,16 +257,19 @@ public: TextureClient* aClientOnBlack, TextureClient* aClientOnWhite) override; #ifdef MOZ_WIDGET_GONK virtual void UseOverlaySource(CompositableClient* aCompositable, const OverlaySource& aOverlay, const nsIntRect& aPictureRect) override; #endif + virtual bool DestroyInTransaction(PTextureChild* aTexture, bool synchronously) override; + virtual bool DestroyInTransaction(PCompositableChild* aCompositable, bool synchronously) override; + virtual void RemoveTextureFromCompositable(CompositableClient* aCompositable, TextureClient* aTexture) override; virtual void RemoveTextureFromCompositableAsync(AsyncTransactionTracker* aAsyncTransactionTracker, CompositableClient* aCompositable, TextureClient* aTexture) override; virtual void UseTiledLayerBuffer(CompositableClient* aCompositable, @@ -313,16 +316,18 @@ public: LayersBackend aLayersBackend, TextureFlags aFlags) override; virtual bool IsSameProcess() const override; virtual void SendPendingAsyncMessges() override; void MarkShutDown(); + + void FallbackDestroyActors(); protected: ImageBridgeChild(); bool DispatchAllocShmemInternal(size_t aSize, SharedMemory::SharedMemoryType aType, Shmem* aShmem, bool aUnsafe); CompositableTransaction* mTxn;
--- a/gfx/layers/ipc/ImageBridgeParent.cpp +++ b/gfx/layers/ipc/ImageBridgeParent.cpp @@ -124,47 +124,52 @@ public: { mImageBridge->SendPendingAsyncMessages(); } private: ImageBridgeParent* mImageBridge; }; bool -ImageBridgeParent::RecvUpdate(EditArray&& aEdits, EditReplyArray* aReply) +ImageBridgeParent::RecvUpdate(EditArray&& aEdits, OpDestroyArray&& aToDestroy, + EditReplyArray* aReply) { AutoImageBridgeParentAsyncMessageSender autoAsyncMessageSender(this); EditReplyVector replyv; for (EditArray::index_type i = 0; i < aEdits.Length(); ++i) { if (!ReceiveCompositableUpdate(aEdits[i], replyv)) { return false; } } + for (const auto& op : aToDestroy) { + DestroyActor(op); + } + aReply->SetCapacity(replyv.size()); if (replyv.size() > 0) { aReply->AppendElements(&replyv.front(), replyv.size()); } if (!IsSameProcess()) { // Ensure that any pending operations involving back and front // buffers have completed, so that neither process stomps on the // other's buffer contents. LayerManagerComposite::PlatformSyncBeforeReplyUpdate(); } return true; } bool -ImageBridgeParent::RecvUpdateNoSwap(EditArray&& aEdits) +ImageBridgeParent::RecvUpdateNoSwap(EditArray&& aEdits, OpDestroyArray&& aToDestroy) { InfallibleTArray<EditReply> noReplies; - bool success = RecvUpdate(Move(aEdits), &noReplies); + bool success = RecvUpdate(Move(aEdits), Move(aToDestroy), &noReplies); MOZ_ASSERT(noReplies.Length() == 0, "RecvUpdateNoSwap requires a sync Update to carry Edits"); return success; } static void ConnectImageBridgeInParentProcess(ImageBridgeParent* aBridge, Transport* aTransport, base::ProcessId aOtherPid)
--- a/gfx/layers/ipc/ImageBridgeParent.h +++ b/gfx/layers/ipc/ImageBridgeParent.h @@ -38,16 +38,17 @@ namespace layers { * It's purpose is mainly to setup the IPDL connection. Most of the * interesting stuff is in ImageContainerParent. */ class ImageBridgeParent final : public PImageBridgeParent, public CompositableParentManager { public: typedef InfallibleTArray<CompositableOperation> EditArray; + typedef InfallibleTArray<OpDestroy> OpDestroyArray; typedef InfallibleTArray<EditReply> EditReplyArray; typedef InfallibleTArray<AsyncChildMessageData> AsyncChildMessageArray; ImageBridgeParent(MessageLoop* aLoop, Transport* aTransport, ProcessId aChildProcessId); ~ImageBridgeParent(); virtual void ActorDestroy(ActorDestroyReason aWhy) override; @@ -62,18 +63,19 @@ public: virtual base::ProcessId GetChildProcessId() override { return OtherPid(); } // PImageBridge virtual bool RecvImageBridgeThreadId(const PlatformThreadId& aThreadId) override; - virtual bool RecvUpdate(EditArray&& aEdits, EditReplyArray* aReply) override; - virtual bool RecvUpdateNoSwap(EditArray&& aEdits) override; + virtual bool RecvUpdate(EditArray&& aEdits, OpDestroyArray&& aToDestroy, + EditReplyArray* aReply) override; + virtual bool RecvUpdateNoSwap(EditArray&& aEdits, OpDestroyArray&& aToDestroy) override; virtual bool IsAsync() const override { return true; } PCompositableParent* AllocPCompositableParent(const TextureInfo& aInfo, PImageContainerParent* aImageContainer, uint64_t*) override; bool DeallocPCompositableParent(PCompositableParent* aActor) override;
--- a/gfx/layers/ipc/LayerTransactionParent.cpp +++ b/gfx/layers/ipc/LayerTransactionParent.cpp @@ -182,27 +182,29 @@ LayerTransactionParent::Destroy() RefPtr<TextureHost> tex = TextureHost::AsTextureHost(textures[i]); tex->DeallocateDeviceData(); } mDestroyed = true; } bool LayerTransactionParent::RecvUpdateNoSwap(InfallibleTArray<Edit>&& cset, + InfallibleTArray<OpDestroy>&& aToDestroy, const uint64_t& aTransactionId, const TargetConfig& targetConfig, PluginsArray&& aPlugins, const bool& isFirstPaint, const bool& scheduleComposite, const uint32_t& paintSequenceNumber, const bool& isRepeatTransaction, const mozilla::TimeStamp& aTransactionStart, const int32_t& aPaintSyncId) { - return RecvUpdate(Move(cset), aTransactionId, targetConfig, Move(aPlugins), isFirstPaint, + return RecvUpdate(Move(cset), Move(aToDestroy), + aTransactionId, targetConfig, Move(aPlugins), isFirstPaint, scheduleComposite, paintSequenceNumber, isRepeatTransaction, aTransactionStart, aPaintSyncId, nullptr); } class MOZ_STACK_CLASS AutoLayerTransactionParentAsyncMessageSender { public: explicit AutoLayerTransactionParentAsyncMessageSender(LayerTransactionParent* aLayerTransaction) @@ -214,16 +216,17 @@ public: ImageBridgeParent::SendPendingAsyncMessages(mLayerTransaction->GetChildProcessId()); } private: LayerTransactionParent* mLayerTransaction; }; bool LayerTransactionParent::RecvUpdate(InfallibleTArray<Edit>&& cset, + InfallibleTArray<OpDestroy>&& aToDestroy, const uint64_t& aTransactionId, const TargetConfig& targetConfig, PluginsArray&& aPlugins, const bool& isFirstPaint, const bool& scheduleComposite, const uint32_t& paintSequenceNumber, const bool& isRepeatTransaction, const mozilla::TimeStamp& aTransactionStart, @@ -236,16 +239,20 @@ LayerTransactionParent::RecvUpdate(Infal #ifdef COMPOSITOR_PERFORMANCE_WARNING TimeStamp updateStart = TimeStamp::Now(); #endif MOZ_LAYERS_LOG(("[ParentSide] received txn with %d edits", cset.Length())); if (mDestroyed || !layer_manager() || layer_manager()->IsDestroyed()) { + for (const auto& op : aToDestroy) { + DestroyActor(op); + } + return true; } EditReplyVector replyv; AutoLayerTransactionParentAsyncMessageSender autoAsyncMessageSender(this); { AutoResolveRefLayers resolve(mShadowLayersManager->GetCompositionManager(this)); @@ -588,16 +595,20 @@ LayerTransactionParent::RecvUpdate(Infal host->SetCompositorID(mLayerManager->GetCompositor()->GetCompositorID()); break; } default: NS_RUNTIMEABORT("not reached"); } } + for (const auto& op : aToDestroy) { + DestroyActor(op); + } + mShadowLayersManager->ShadowLayersUpdated(this, aTransactionId, targetConfig, aPlugins, isFirstPaint, scheduleComposite, paintSequenceNumber, isRepeatTransaction, aPaintSyncId); { AutoResolveRefLayers resolve(mShadowLayersManager->GetCompositionManager(this)); layer_manager()->EndTransaction(TimeStamp(), LayerManager::END_NO_IMMEDIATE_REDRAW);
--- a/gfx/layers/ipc/LayerTransactionParent.h +++ b/gfx/layers/ipc/LayerTransactionParent.h @@ -35,16 +35,17 @@ class ShadowLayerParent; class CompositableParent; class ShadowLayersManager; class LayerTransactionParent final : public PLayerTransactionParent, public CompositableParentManager { typedef mozilla::layout::RenderFrameParent RenderFrameParent; typedef InfallibleTArray<Edit> EditArray; + typedef InfallibleTArray<OpDestroy> OpDestroyArray; typedef InfallibleTArray<EditReply> EditReplyArray; typedef InfallibleTArray<AsyncChildMessageData> AsyncChildMessageArray; typedef InfallibleTArray<PluginWindowData> PluginsArray; public: LayerTransactionParent(LayerManagerComposite* aManager, ShadowLayersManager* aLayersManager, uint64_t aId); @@ -88,28 +89,30 @@ public: } virtual void ReplyRemoveTexture(const OpReplyRemoveTexture& aReply) override; protected: virtual bool RecvShutdown() override; virtual bool RecvUpdate(EditArray&& cset, + OpDestroyArray&& aToDestroy, const uint64_t& aTransactionId, const TargetConfig& targetConfig, PluginsArray&& aPlugins, const bool& isFirstPaint, const bool& scheduleComposite, const uint32_t& paintSequenceNumber, const bool& isRepeatTransaction, const mozilla::TimeStamp& aTransactionStart, const int32_t& aPaintSyncId, EditReplyArray* reply) override; virtual bool RecvUpdateNoSwap(EditArray&& cset, + OpDestroyArray&& aToDestroy, const uint64_t& aTransactionId, const TargetConfig& targetConfig, PluginsArray&& aPlugins, const bool& isFirstPaint, const bool& scheduleComposite, const uint32_t& paintSequenceNumber, const bool& isRepeatTransaction, const mozilla::TimeStamp& aTransactionStart,
--- a/gfx/layers/ipc/LayersMessages.ipdlh +++ b/gfx/layers/ipc/LayersMessages.ipdlh @@ -466,16 +466,22 @@ union Edit { OpRaiseToTopChild; OpAttachCompositable; OpAttachAsyncCompositable; CompositableOperation; }; +// Operations related to destroying resources, always handled after the other +// operations for safety. +union OpDestroy { + PTexture; + PCompositable; +}; // Replies to operations struct OpContentBufferSwap { PCompositable compositable; nsIntRegion frontUpdatedRegion; };
--- a/gfx/layers/ipc/PImageBridge.ipdl +++ b/gfx/layers/ipc/PImageBridge.ipdl @@ -37,18 +37,20 @@ sync protocol PImageBridge child: async ParentAsyncMessages(AsyncParentMessageData[] aMessages); async DidComposite(ImageCompositeNotification[] aNotifications); parent: async ImageBridgeThreadId(PlatformThreadId aTreahdId); - sync Update(CompositableOperation[] ops) returns (EditReply[] reply); - async UpdateNoSwap(CompositableOperation[] ops); + sync Update(CompositableOperation[] ops, OpDestroy[] toDestroy) + returns (EditReply[] reply); + + async UpdateNoSwap(CompositableOperation[] ops, OpDestroy[] toDestroy); // First step of the destruction sequence. This puts ImageBridge // in a state in which it can't send asynchronous messages // so as to not race with the upcomming Stop message and destruction. // In the child side, the Stop message is not sent right after WillStop, // it is scheduled in the ImageBridgeChild's message queue in order to ensure // that all of the messages from the parent side have been received and processed // before sending Stop, and that after Stop returns, there is no message in
--- a/gfx/layers/ipc/PLayerTransaction.ipdl +++ b/gfx/layers/ipc/PLayerTransaction.ipdl @@ -50,26 +50,28 @@ child: parent: async PLayer(); async PCompositable(TextureInfo aTextureInfo); async PTexture(SurfaceDescriptor aSharedData, LayersBackend aBackend, TextureFlags aTextureFlags); // The isFirstPaint flag can be used to indicate that this is the first update // for a particular document. - sync Update(Edit[] cset, uint64_t id, TargetConfig targetConfig, + sync Update(Edit[] cset, OpDestroy[] toDestroy, + uint64_t id, TargetConfig targetConfig, PluginWindowData[] plugins, bool isFirstPaint, bool scheduleComposite, uint32_t paintSequenceNumber, bool isRepeatTransaction, TimeStamp transactionStart, int32_t paintSyncId) returns (EditReply[] reply); // We don't need to send a sync transaction if // no transaction operate require a swap. - async UpdateNoSwap(Edit[] cset, uint64_t id, TargetConfig targetConfig, + async UpdateNoSwap(Edit[] cset, OpDestroy[] toDestroy, + uint64_t id, TargetConfig targetConfig, PluginWindowData[] plugins, bool isFirstPaint, bool scheduleComposite, uint32_t paintSequenceNumber, bool isRepeatTransaction, TimeStamp transactionStart, int32_t paintSyncId); // Testing APIs // Enter test mode, set the sample time to sampleTime, and resample
--- a/gfx/layers/ipc/ShadowLayers.cpp +++ b/gfx/layers/ipc/ShadowLayers.cpp @@ -12,16 +12,17 @@ #include "ISurfaceAllocator.h" // for IsSurfaceDescriptorValid #include "Layers.h" // for Layer #include "RenderTrace.h" // for RenderTraceScope #include "ShadowLayerChild.h" // for ShadowLayerChild #include "gfx2DGlue.h" // for Moz2D transition helpers #include "gfxPlatform.h" // for gfxImageFormat, gfxPlatform #include "gfxSharedImageSurface.h" // for gfxSharedImageSurface #include "ipc/IPCMessageUtils.h" // for gfxContentType, null_t +#include "IPDLActor.h" #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc #include "mozilla/gfx/Point.h" // for IntSize #include "mozilla/layers/CompositableClient.h" // for CompositableClient, etc #include "mozilla/layers/LayersMessages.h" // for Edit, etc #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc #include "mozilla/layers/LayersTypes.h" // for MOZ_LAYERS_LOG #include "mozilla/layers/LayerTransactionChild.h" #include "ShadowLayerUtils.h" @@ -43,16 +44,17 @@ using namespace mozilla::gfx; using namespace mozilla::gl; using namespace mozilla::ipc; class ClientTiledLayerBuffer; typedef nsTArray<SurfaceDescriptor> BufferArray; typedef std::vector<Edit> EditVector; typedef std::set<ShadowableLayer*> ShadowableLayerSet; +typedef nsTArray<OpDestroy> OpDestroyVector; class Transaction { public: Transaction() : mTargetRotation(ROTATION_0) , mSwapRequired(false) , mOpen(false) @@ -113,33 +115,56 @@ public: MOZ_ASSERT(!Finished(), "forgot BeginTransaction?"); mMutants.insert(aLayer); } void End() { mCset.clear(); mPaints.clear(); mMutants.clear(); + mDestroyedActors.Clear(); mOpen = false; mSwapRequired = false; mRotationChanged = false; } bool Empty() const { - return mCset.empty() && mPaints.empty() && mMutants.empty(); + return mCset.empty() && mPaints.empty() && mMutants.empty() + && mDestroyedActors.IsEmpty(); } bool RotationChanged() const { return mRotationChanged; } bool Finished() const { return !mOpen && Empty(); } bool Opened() const { return mOpen; } + void FallbackDestroyActors() + { + for (auto& actor : mDestroyedActors) { + switch (actor.type()) { + case OpDestroy::TPTextureChild: { + DebugOnly<bool> ok = TextureClient::DestroyFallback(actor.get_PTextureChild()); + MOZ_ASSERT(ok); + break; + } + case OpDestroy::TPCompositableChild: { + DebugOnly<bool> ok = CompositableClient::DestroyFallback(actor.get_PCompositableChild()); + MOZ_ASSERT(ok); + break; + } + default: MOZ_CRASH(); + } + } + mDestroyedActors.Clear(); + } + EditVector mCset; EditVector mPaints; + OpDestroyVector mDestroyedActors; ShadowableLayerSet mMutants; gfx::IntRect mTargetBounds; ScreenRotation mTargetRotation; dom::ScreenOrientationInternal mTargetOrientation; bool mSwapRequired; private: bool mOpen; @@ -170,16 +195,19 @@ ShadowLayerForwarder::ShadowLayerForward , mPaintSyncId(0) { mTxn = new Transaction(); } ShadowLayerForwarder::~ShadowLayerForwarder() { MOZ_ASSERT(mTxn->Finished(), "unfinished transaction?"); + if (!mTxn->mDestroyedActors.IsEmpty()) { + mTxn->FallbackDestroyActors(); + } delete mTxn; if (mShadowManager) { mShadowManager->SetForwarder(nullptr); mShadowManager->Destroy(); } } void @@ -410,16 +438,43 @@ ShadowLayerForwarder::UseOverlaySource(C MOZ_ASSERT(aCompositable); MOZ_ASSERT(aCompositable->IsConnected()); mTxn->AddEdit(OpUseOverlaySource(nullptr, aCompositable->GetIPDLActor(), aOverlay, aPictureRect)); } #endif +static bool +AddOpDestroy(Transaction* aTxn, const OpDestroy& op, bool synchronously) +{ + if (!aTxn->Opened()) { + return false; + } + + aTxn->mDestroyedActors.AppendElement(op); + if (synchronously) { + aTxn->MarkSyncTransaction(); + } + + return true; +} + +bool +ShadowLayerForwarder::DestroyInTransaction(PTextureChild* aTexture, bool synchronously) +{ + return AddOpDestroy(mTxn, OpDestroy(aTexture), synchronously); +} + +bool +ShadowLayerForwarder::DestroyInTransaction(PCompositableChild* aCompositable, bool synchronously) +{ + return AddOpDestroy(mTxn, OpDestroy(aCompositable), synchronously); +} + void ShadowLayerForwarder::RemoveTextureFromCompositable(CompositableClient* aCompositable, TextureClient* aTexture) { MOZ_ASSERT(aCompositable); MOZ_ASSERT(aTexture); MOZ_ASSERT(aCompositable->IsConnected()); MOZ_ASSERT(aTexture->GetIPDLActor()); @@ -428,18 +483,16 @@ ShadowLayerForwarder::RemoveTextureFromC return; } mTxn->AddEdit(OpRemoveTexture(nullptr, aCompositable->GetIPDLActor(), nullptr, aTexture->GetIPDLActor())); if (aTexture->GetFlags() & TextureFlags::DEALLOCATE_CLIENT) { mTxn->MarkSyncTransaction(); } - // Hold texture until transaction complete. - HoldUntilTransaction(aTexture); } void ShadowLayerForwarder::RemoveTextureFromCompositableAsync(AsyncTransactionTracker* aAsyncTransactionTracker, CompositableClient* aCompositable, TextureClient* aTexture) { MOZ_ASSERT(aCompositable); @@ -642,35 +695,39 @@ ShadowLayerForwarder::EndTransaction(Inf } profiler_tracing("Paint", "Rasterize", TRACING_INTERVAL_END); if (mTxn->mSwapRequired) { MOZ_LAYERS_LOG(("[LayersForwarder] sending transaction...")); RenderTraceScope rendertrace3("Forward Transaction", "000093"); if (!HasShadowManager() || !mShadowManager->IPCOpen() || - !mShadowManager->SendUpdate(cset, aId, targetConfig, mPluginWindowData, + !mShadowManager->SendUpdate(cset, mTxn->mDestroyedActors, + aId, targetConfig, mPluginWindowData, mIsFirstPaint, aScheduleComposite, aPaintSequenceNumber, aIsRepeatTransaction, aTransactionStart, mPaintSyncId, aReplies)) { MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!")); + mTxn->FallbackDestroyActors(); return false; } } else { // If we don't require a swap we can call SendUpdateNoSwap which // assumes that aReplies is empty (DEBUG assertion) MOZ_LAYERS_LOG(("[LayersForwarder] sending no swap transaction...")); RenderTraceScope rendertrace3("Forward NoSwap Transaction", "000093"); if (!HasShadowManager() || !mShadowManager->IPCOpen() || - !mShadowManager->SendUpdateNoSwap(cset, aId, targetConfig, mPluginWindowData, + !mShadowManager->SendUpdateNoSwap(cset, mTxn->mDestroyedActors, + aId, targetConfig, mPluginWindowData, mIsFirstPaint, aScheduleComposite, aPaintSequenceNumber, aIsRepeatTransaction, aTransactionStart, mPaintSyncId)) { MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!")); + mTxn->FallbackDestroyActors(); return false; } } *aSent = true; mIsFirstPaint = false; mPaintSyncId = 0; MOZ_LAYERS_LOG(("[LayersForwarder] ... done"));
--- a/gfx/layers/ipc/ShadowLayers.h +++ b/gfx/layers/ipc/ShadowLayers.h @@ -209,16 +209,19 @@ public: ShadowableLayer* aMaskLayer); /** * See CompositableForwarder::UseTiledLayerBuffer */ virtual void UseTiledLayerBuffer(CompositableClient* aCompositable, const SurfaceDescriptorTiles& aTileLayerDescriptor) override; + virtual bool DestroyInTransaction(PTextureChild* aTexture, bool synchronously) override; + virtual bool DestroyInTransaction(PCompositableChild* aCompositable, bool synchronously) override; + virtual void RemoveTextureFromCompositable(CompositableClient* aCompositable, TextureClient* aTexture) override; virtual void RemoveTextureFromCompositableAsync(AsyncTransactionTracker* aAsyncTransactionTracker, CompositableClient* aCompositable, TextureClient* aTexture) override; /**