Backout Bug 1221056 - make the destroy messages for PTexture and PCompositable part of the current transaction when applicable. r=sotaro
authorJohan Lorenzo <jlorenzo@mozilla.com>
Wed, 06 Jan 2016 14:59:35 +0100
changeset 278766 ec25e284ca6fd536484fbb7252fbb1791b71d95f
parent 278628 9d6ffc7a08b6b47056eefe1e652710a3849adbf7
child 278767 9b1f767c564bb2c7325ec1ef81b54e4e81f7f30b
push id69865
push userryanvm@gmail.com
push dateWed, 06 Jan 2016 14:50:58 +0000
treeherdermozilla-inbound@d004c480a389 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssotaro
bugs1221056, 1237197
milestone46.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
Backout Bug 1221056 - make the destroy messages for PTexture and PCompositable part of the current transaction when applicable. r=sotaro For breaking Firefox OS boot startup (see bug 1237197)
gfx/layers/IPDLActor.h
gfx/layers/client/ClientLayerManager.cpp
gfx/layers/client/ClientTiledPaintedLayer.cpp
gfx/layers/client/CompositableClient.cpp
gfx/layers/client/CompositableClient.h
gfx/layers/client/TextureClient.cpp
gfx/layers/client/TextureClient.h
gfx/layers/composite/CompositableHost.cpp
gfx/layers/composite/CompositableHost.h
gfx/layers/composite/TextureHost.cpp
gfx/layers/composite/TextureHost.h
gfx/layers/ipc/CompositableForwarder.h
gfx/layers/ipc/CompositableTransactionParent.cpp
gfx/layers/ipc/CompositableTransactionParent.h
gfx/layers/ipc/ImageBridgeChild.cpp
gfx/layers/ipc/ImageBridgeChild.h
gfx/layers/ipc/ImageBridgeParent.cpp
gfx/layers/ipc/ImageBridgeParent.h
gfx/layers/ipc/LayerTransactionParent.cpp
gfx/layers/ipc/LayerTransactionParent.h
gfx/layers/ipc/LayersMessages.ipdlh
gfx/layers/ipc/PImageBridge.ipdl
gfx/layers/ipc/PLayerTransaction.ipdl
gfx/layers/ipc/ShadowLayers.cpp
gfx/layers/ipc/ShadowLayers.h
--- a/gfx/layers/IPDLActor.h
+++ b/gfx/layers/IPDLActor.h
@@ -2,17 +2,16 @@
  * 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
@@ -44,54 +43,43 @@ 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(CompositableForwarder* aFwd = nullptr)
+  void Destroy()
   {
     MOZ_ASSERT(!mDestroyed);
     if (!mDestroyed) {
       mDestroyed = true;
       DestroyManagees();
-      if (!aFwd || !aFwd->DestroyInTransaction(this, false)) {
-        this->SendDestroy();
-      }
+      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(CompositableForwarder* aFwd = nullptr)
+  void DestroySynchronously()
   {
     MOZ_PERFORMANCE_WARNING("gfx", "IPDL actor requires synchronous deallocation");
     MOZ_ASSERT(!mDestroyed);
     if (!mDestroyed) {
       DestroyManagees();
       mDestroyed = true;
-      if (!aFwd || !aFwd->DestroyInTransaction(this, true)) {
-        this->SendDestroySync();
-        this->SendDestroy();
-      }
+      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
@@ -639,16 +639,18 @@ 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,16 +407,17 @@ 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,28 +175,23 @@ CompositableClient::IsConnected() const
 }
 
 void
 CompositableClient::Destroy()
 {
   if (!IsConnected()) {
     return;
   }
-
-  mCompositableChild->mCompositableClient = nullptr;
-  mCompositableChild->Destroy(mForwarder);
-  mCompositableChild = nullptr;
-
+  // Send pending AsyncMessages before deleting CompositableChild.
+  // They might have dependency to the mCompositableChild.
   mForwarder->SendPendingAsyncMessges();
-}
-
-bool
-CompositableClient::DestroyFallback(PCompositableChild* aActor)
-{
-  return aActor->SendDestroySync();
+  // Destroy CompositableChild.
+  mCompositableChild->mCompositableClient = nullptr;
+  mCompositableChild->Destroy();
+  mCompositableChild = nullptr;
 }
 
 uint64_t
 CompositableClient::GetAsyncID() const
 {
   if (mCompositableChild) {
     return mCompositableChild->mAsyncID;
   }
--- a/gfx/layers/client/CompositableClient.h
+++ b/gfx/layers/client/CompositableClient.h
@@ -150,18 +150,16 @@ 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->GetForwarder());
+    actor->DestroySynchronously();
     DestroyTextureData(params.data, params.allocator, params.clientDeallocation,
                        actor->mMainThreadOnly);
   } else {
     actor->mTextureData = params.data;
     actor->mOwnsTextureData = params.clientDeallocation;
-    actor->Destroy(actor->GetForwarder());
+    actor->Destroy();
     // DestroyTextureData will be called by TextureChild::ActorDestroy
   }
 }
 
 void TextureClient::Destroy(bool aForceSync)
 {
   MOZ_ASSERT(!IsLocked());
 
@@ -342,24 +342,16 @@ 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
@@ -410,18 +410,16 @@ 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,22 +222,16 @@ 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,19 +171,16 @@ 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,22 +830,16 @@ 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,18 +458,16 @@ 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,19 +79,16 @@ 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.
    */
@@ -106,16 +103,50 @@ 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,43 +228,18 @@ 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,28 +41,25 @@ 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,17 +51,16 @@ 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()
@@ -77,59 +76,33 @@ struct CompositableTransaction
     MOZ_ASSERT(mFinished);
     mFinished = false;
   }
   void End()
   {
     mFinished = true;
     mSwapRequired = false;
     mOperations.clear();
-    mDestroyedActors.Clear();
   }
   bool IsEmpty() const
   {
-    return mOperations.empty() && mDestroyedActors.IsEmpty();
+    return mOperations.empty();
   }
   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;
@@ -200,22 +173,16 @@ 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.");
@@ -232,18 +199,16 @@ 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();
@@ -637,23 +602,38 @@ 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()) {
@@ -662,27 +642,25 @@ ImageBridgeChild::EndTransaction()
 
   if (!IsSameProcess()) {
     ShadowLayerForwarder::PlatformSyncBeforeUpdate();
   }
 
   AutoInfallibleTArray<EditReply, 10> replies;
 
   if (mTxn->mSwapRequired) {
-    if (!SendUpdate(cset, mTxn->mDestroyedActors, &replies)) {
+    if (!SendUpdate(cset, &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, mTxn->mDestroyedActors)) {
+    if (!SendUpdateNoSwap(cset)) {
       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();
 }
@@ -1113,45 +1091,16 @@ 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());
@@ -1160,16 +1109,18 @@ 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,19 +257,16 @@ 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,
@@ -316,18 +313,16 @@ 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,52 +124,47 @@ public:
   {
     mImageBridge->SendPendingAsyncMessages();
   }
 private:
   ImageBridgeParent* mImageBridge;
 };
 
 bool
-ImageBridgeParent::RecvUpdate(EditArray&& aEdits, OpDestroyArray&& aToDestroy,
-                              EditReplyArray* aReply)
+ImageBridgeParent::RecvUpdate(EditArray&& aEdits, 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, OpDestroyArray&& aToDestroy)
+ImageBridgeParent::RecvUpdateNoSwap(EditArray&& aEdits)
 {
   InfallibleTArray<EditReply> noReplies;
-  bool success = RecvUpdate(Move(aEdits), Move(aToDestroy), &noReplies);
+  bool success = RecvUpdate(Move(aEdits), &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,17 +38,16 @@ 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;
 
@@ -63,19 +62,18 @@ public:
 
   virtual base::ProcessId GetChildProcessId() override
   {
     return OtherPid();
   }
 
   // PImageBridge
   virtual bool RecvImageBridgeThreadId(const PlatformThreadId& aThreadId) override;
-  virtual bool RecvUpdate(EditArray&& aEdits, OpDestroyArray&& aToDestroy,
-                          EditReplyArray* aReply) override;
-  virtual bool RecvUpdateNoSwap(EditArray&& aEdits, OpDestroyArray&& aToDestroy) override;
+  virtual bool RecvUpdate(EditArray&& aEdits, EditReplyArray* aReply) override;
+  virtual bool RecvUpdateNoSwap(EditArray&& aEdits) 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,29 +182,27 @@ 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), Move(aToDestroy),
-      aTransactionId, targetConfig, Move(aPlugins), isFirstPaint,
+  return RecvUpdate(Move(cset), aTransactionId, targetConfig, Move(aPlugins), isFirstPaint,
       scheduleComposite, paintSequenceNumber, isRepeatTransaction,
       aTransactionStart, aPaintSyncId, nullptr);
 }
 
 class MOZ_STACK_CLASS AutoLayerTransactionParentAsyncMessageSender
 {
 public:
   explicit AutoLayerTransactionParentAsyncMessageSender(LayerTransactionParent* aLayerTransaction)
@@ -216,17 +214,16 @@ 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,
@@ -239,20 +236,16 @@ 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));
@@ -595,20 +588,16 @@ 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,17 +35,16 @@ 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);
@@ -89,30 +88,28 @@ 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,22 +466,16 @@ 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,20 +37,18 @@ sync protocol PImageBridge
 child:
   async ParentAsyncMessages(AsyncParentMessageData[] aMessages);
 
   async DidComposite(ImageCompositeNotification[] aNotifications);
 
 parent:
   async ImageBridgeThreadId(PlatformThreadId aTreahdId);
 
-  sync Update(CompositableOperation[] ops, OpDestroy[] toDestroy)
-    returns (EditReply[] reply);
-
-  async UpdateNoSwap(CompositableOperation[] ops, OpDestroy[] toDestroy);
+  sync Update(CompositableOperation[] ops) returns (EditReply[] reply);
+  async UpdateNoSwap(CompositableOperation[] ops);
 
   // 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,28 +50,26 @@ 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, OpDestroy[] toDestroy,
-              uint64_t id, TargetConfig targetConfig,
+  sync Update(Edit[] cset, 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, OpDestroy[] toDestroy,
-                     uint64_t id, TargetConfig targetConfig,
+  async UpdateNoSwap(Edit[] cset, 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,17 +12,16 @@
 #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"
@@ -44,17 +43,16 @@ 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)
@@ -115,56 +113,33 @@ 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()
-           && mDestroyedActors.IsEmpty();
+    return mCset.empty() && mPaints.empty() && mMutants.empty();
   }
   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;
@@ -195,19 +170,16 @@ 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
@@ -438,43 +410,16 @@ 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());
@@ -483,16 +428,18 @@ 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);
@@ -695,39 +642,35 @@ 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, mTxn->mDestroyedActors,
-                                    aId, targetConfig, mPluginWindowData,
+        !mShadowManager->SendUpdate(cset, 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, mTxn->mDestroyedActors,
-                                          aId, targetConfig, mPluginWindowData,
+        !mShadowManager->SendUpdateNoSwap(cset, 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,19 +209,16 @@ 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;
 
   /**