Bug 1393031 - Use the ResourceUpdateQueue API on the content side. r=jrmuizel
authorNicolas Silva <nsilva@mozilla.com>
Mon, 04 Sep 2017 13:59:36 +0200
changeset 428336 36260b6ee764ec4250d6f6e1a307070337470dc7
parent 428335 44463d7234864ab61c9f6eb6605220d4f6e8c775
child 428337 959919f16fe222ce8ca38581ccd232f82dfc2784
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1393031
milestone57.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
Bug 1393031 - Use the ResourceUpdateQueue API on the content side. r=jrmuizel
gfx/layers/ipc/PWebRenderBridge.ipdl
gfx/layers/wr/WebRenderBridgeChild.cpp
gfx/layers/wr/WebRenderBridgeChild.h
gfx/layers/wr/WebRenderBridgeParent.cpp
gfx/layers/wr/WebRenderBridgeParent.h
gfx/layers/wr/WebRenderLayerManager.cpp
gfx/layers/wr/WebRenderLayerManager.h
gfx/layers/wr/WebRenderPaintedLayerBlob.cpp
gfx/webrender_bindings/WebRenderAPI.cpp
gfx/webrender_bindings/WebRenderAPI.h
gfx/webrender_bindings/src/bindings.rs
gfx/webrender_bindings/webrender_ffi_generated.h
widget/cocoa/nsChildView.mm
--- a/gfx/layers/ipc/PWebRenderBridge.ipdl
+++ b/gfx/layers/ipc/PWebRenderBridge.ipdl
@@ -42,40 +42,28 @@ parent:
   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);
-  async UpdateResources(ByteBuffer aUpdates);
-  async AddImage(ImageKey aImageKey, IntSize aSize, uint32_t aStride,
-                 SurfaceFormat aFormat, ByteBuffer aBytes);
-  async AddBlobImage(ImageKey aImageKey, IntSize aSize, uint32_t aStride,
-                     SurfaceFormat aFormat, ByteBuffer aBytes);
-  async UpdateImage(ImageKey aImageKey, IntSize aSize,
-                   SurfaceFormat aFormat, ByteBuffer aBytes);
-  async DeleteImage(ImageKey aImageKey);
   async DeleteCompositorAnimations(uint64_t[] aIds);
-  async AddRawFont(FontKey aFontKey, ByteBuffer aBytes, uint32_t aFontIndex);
-  async DeleteFont(FontKey aFontKey);
-  async AddFontInstance(FontInstanceKey aInstanceKey, FontKey aFontKey, float aGlyphSize,
-                        MaybeFontInstanceOptions aOptions, MaybeFontInstancePlatformOptions aPlatformOptions);
-  async DeleteFontInstance(FontInstanceKey aInstanceKey);
   async SetDisplayList(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
                        LayoutSize aContentSize, ByteBuffer aDL, BuiltDisplayListDescriptor aDLDesc,
                        WebRenderScrollData aScrollData,
                        ByteBuffer aResourceUpdates,
                        IdNamespace aIdNamespace, TimeStamp txnStartTime, TimeStamp fwdTime);
   sync SetDisplayListSync(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
                           LayoutSize aContentSize, ByteBuffer aDL, BuiltDisplayListDescriptor aDLDesc,
                           WebRenderScrollData aScrollData,
                           ByteBuffer aResourceUpdates,
                           IdNamespace aIdNamespace, TimeStamp txnStartTime, TimeStamp fwdTime);
+  async UpdateResources(ByteBuffer aResourceUpdates);
   async ParentCommands(WebRenderParentCommand[] commands);
   sync GetSnapshot(PTexture texture);
   async AddPipelineIdForCompositable(PipelineId aImageId, CompositableHandle aHandle, bool aAsync);
   async RemovePipelineIdForCompositable(PipelineId aPipelineId);
   async AddExternalImageIdForCompositable(ExternalImageId aImageId, CompositableHandle aHandle);
   async RemoveExternalImageId(ExternalImageId aImageId);
   async SetLayerObserverEpoch(uint64_t layerObserverEpoch);
   async ClearCachedResources();
--- a/gfx/layers/wr/WebRenderBridgeChild.cpp
+++ b/gfx/layers/wr/WebRenderBridgeChild.cpp
@@ -93,16 +93,27 @@ WebRenderBridgeChild::ClearReadLocks()
       }
     }
   }
 
   mReadLocks.Clear();
 }
 
 void
+WebRenderBridgeChild::UpdateResources(wr::ResourceUpdateQueue& aResources)
+{
+  if (!IPCOpen()) {
+    aResources.Clear();
+    return;
+  }
+  wr::ByteBuffer serializedUpdates(Move(aResources.Serialize()));
+  this->SendUpdateResources(serializedUpdates);
+}
+
+void
 WebRenderBridgeChild::EndTransaction(wr::DisplayListBuilder &aBuilder,
                                      const gfx::IntSize& aSize,
                                      bool aIsSync,
                                      uint64_t aTransactionId,
                                      const WebRenderScrollData& aScrollData,
                                      const mozilla::TimeStamp& aTxnStartTime)
 {
   MOZ_ASSERT(!mDestroyed);
@@ -113,30 +124,28 @@ WebRenderBridgeChild::EndTransaction(wr:
   aBuilder.Finalize(contentSize, dl);
   ByteBuffer dlData(Move(dl.dl));
 
   TimeStamp fwdTime;
 #if defined(ENABLE_FRAME_LATENCY_LOG)
   fwdTime = TimeStamp::Now();
 #endif
 
-  // TODO(nical)
-  wr::ResourceUpdateQueue updates;
-  wr::ByteBuffer serializedUpdates(Move(updates.Serialize()));
+  wr::ByteBuffer resourceUpdates(Move(aBuilder.Resources().Serialize()));
 
   if (aIsSync) {
     this->SendSetDisplayListSync(aSize, mParentCommands, mDestroyedActors,
                                  GetFwdTransactionId(), aTransactionId,
                                  contentSize, dlData, dl.dl_desc, aScrollData,
-                                 serializedUpdates, mIdNamespace, aTxnStartTime, fwdTime);
+                                 resourceUpdates, mIdNamespace, aTxnStartTime, fwdTime);
   } else {
     this->SendSetDisplayList(aSize, mParentCommands, mDestroyedActors,
                              GetFwdTransactionId(), aTransactionId,
                              contentSize, dlData, dl.dl_desc, aScrollData,
-                             serializedUpdates, mIdNamespace, aTxnStartTime, fwdTime);
+                             resourceUpdates, mIdNamespace, aTxnStartTime, fwdTime);
   }
 
   mParentCommands.Clear();
   mDestroyedActors.Clear();
   mIsInTransaction = false;
 }
 
 void
@@ -258,65 +267,70 @@ WebRenderBridgeChild::GetFontKeyForScale
   wr::FontInstanceKey instanceKey = { wr::IdNamespace { 0 }, 0 };
   if (mFontInstanceKeys.Get(aScaledFont, &instanceKey)) {
     return instanceKey;
   }
 
   RefPtr<gfx::UnscaledFont> unscaled = aScaledFont->GetUnscaledFont();
   MOZ_ASSERT(unscaled);
 
+  wr::ResourceUpdateQueue resources;
+
   wr::FontKey fontKey = { wr::IdNamespace { 0 }, 0};
   if (!mFontKeys.Get(unscaled, &fontKey)) {
     FontFileData data;
     if (!unscaled->GetFontFileData(WriteFontFileData, &data) ||
         !data.mFontBuffer.mData) {
       return instanceKey;
     }
 
     fontKey.mNamespace = GetNamespace();
     fontKey.mHandle = GetNextResourceId();
 
-    SendAddRawFont(fontKey, data.mFontBuffer, data.mFontIndex);
+    resources.AddRawFont(fontKey, data.mFontBuffer.AsSlice(), data.mFontIndex);
 
     mFontKeys.Put(unscaled, fontKey);
   }
 
   instanceKey.mNamespace = GetNamespace();
   instanceKey.mHandle = GetNextResourceId();
 
-  SendAddFontInstance(instanceKey, fontKey, aScaledFont->GetSize(), Nothing(), Nothing());
+  resources.AddFontInstance(instanceKey, fontKey, aScaledFont->GetSize(), nullptr, nullptr);
+  UpdateResources(resources);
 
   mFontInstanceKeys.Put(aScaledFont, instanceKey);
 
   return instanceKey;
 }
 
 void
 WebRenderBridgeChild::RemoveExpiredFontKeys()
 {
   uint32_t counter = gfx::ScaledFont::DeletionCounter();
+  wr::ResourceUpdateQueue resources;
   if (mFontInstanceKeysDeleted != counter) {
     mFontInstanceKeysDeleted = counter;
     for (auto iter = mFontInstanceKeys.Iter(); !iter.Done(); iter.Next()) {
       if (!iter.Key()) {
-        SendDeleteFontInstance(iter.Data());
+        resources.DeleteFontInstance(iter.Data());
         iter.Remove();
       }
     }
   }
   counter = gfx::UnscaledFont::DeletionCounter();
   if (mFontKeysDeleted != counter) {
     mFontKeysDeleted = counter;
     for (auto iter = mFontKeys.Iter(); !iter.Done(); iter.Next()) {
       if (!iter.Key()) {
-        SendDeleteFont(iter.Data());
+        resources.DeleteFont(iter.Data());
         iter.Remove();
       }
     }
   }
+  UpdateResources(resources);
 }
 
 CompositorBridgeChild*
 WebRenderBridgeChild::GetCompositorBridgeChild()
 {
   return static_cast<CompositorBridgeChild*>(Manager());
 }
 
--- a/gfx/layers/wr/WebRenderBridgeChild.h
+++ b/gfx/layers/wr/WebRenderBridgeChild.h
@@ -13,16 +13,17 @@
 namespace mozilla {
 
 namespace widget {
 class CompositorWidget;
 }
 
 namespace wr {
 class DisplayListBuilder;
+class ResourceUpdateQueue;
 }
 
 namespace layers {
 
 class CompositableClient;
 class CompositorBridgeChild;
 class StackingContextHelper;
 class TextureForwarder;
@@ -59,21 +60,22 @@ class WebRenderBridgeChild final : publi
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebRenderBridgeChild, override)
 
 public:
   explicit WebRenderBridgeChild(const wr::PipelineId& aPipelineId);
 
   void AddWebRenderParentCommand(const WebRenderParentCommand& aCmd);
   void AddWebRenderParentCommands(const nsTArray<WebRenderParentCommand>& aCommands);
 
+  void UpdateResources(wr::ResourceUpdateQueue& aResources);
   bool BeginTransaction(const  gfx::IntSize& aSize);
   void EndTransaction(wr::DisplayListBuilder &aBuilder, const gfx::IntSize& aSize,
-             bool aIsSync, uint64_t aTransactionId,
-             const WebRenderScrollData& aScrollData,
-             const mozilla::TimeStamp& aTxnStartTime);
+                      bool aIsSync, uint64_t aTransactionId,
+                      const WebRenderScrollData& aScrollData,
+                      const mozilla::TimeStamp& aTxnStartTime);
   void ProcessWebRenderParentCommands();
 
   CompositorBridgeChild* GetCompositorBridgeChild();
 
   wr::PipelineId GetPipeline() { return mPipelineId; }
 
   // KnowsCompositor
   TextureForwarder* GetTextureForwarder() override;
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -223,185 +223,16 @@ WebRenderBridgeParent::Destroy()
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvUpdateResources(const wr::ByteBuffer& aUpdates)
 {
   wr::ResourceUpdateQueue updates = wr::ResourceUpdateQueue::Deserialize(aUpdates.AsSlice());
   mApi->UpdateResources(updates);
 }
 
- mozilla::ipc::IPCResult
-WebRenderBridgeParent::RecvAddImage(const wr::ImageKey& aImageKey,
-                                    const gfx::IntSize& aSize,
-                                    const uint32_t& aStride,
-                                    const gfx::SurfaceFormat& aFormat,
-                                    const ByteBuffer& aBuffer)
-{
-  if (mDestroyed) {
-    return IPC_OK();
-  }
-
-  // Check if key is obsoleted.
-  if (aImageKey.mNamespace != mIdNamespace) {
-    return IPC_OK();
-  }
-
-  MOZ_ASSERT(mApi);
-
-  wr::ImageDescriptor descriptor(aSize, aStride, aFormat);
-  mApi->Resources().AddImage(aImageKey, descriptor, aBuffer.AsSlice());
-
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
-WebRenderBridgeParent::RecvAddBlobImage(const wr::ImageKey& aImageKey,
-                                        const gfx::IntSize& aSize,
-                                        const uint32_t& aStride,
-                                        const gfx::SurfaceFormat& aFormat,
-                                        const ByteBuffer& aBuffer)
-{
-  if (mDestroyed) {
-    return IPC_OK();
-  }
-
-  // Check if key is obsoleted.
-  if (aImageKey.mNamespace != mIdNamespace) {
-    return IPC_OK();
-  }
-
-  MOZ_ASSERT(mApi);
-
-  wr::ImageDescriptor descriptor(aSize, aStride, aFormat);
-  mApi->Resources().AddBlobImage(aImageKey, descriptor, aBuffer.AsSlice());
-
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
-WebRenderBridgeParent::RecvAddRawFont(const wr::FontKey& aFontKey,
-                                      const ByteBuffer& aBuffer,
-                                      const uint32_t& aFontIndex)
-{
-  if (mDestroyed) {
-    return IPC_OK();
-  }
-
-  // Check if key is obsoleted.
-  if (aFontKey.mNamespace != mIdNamespace) {
-    return IPC_OK();
-  }
-
-  MOZ_ASSERT(mApi);
-
-  auto slice = aBuffer.AsSlice();
-  mApi->Resources().AddRawFont(aFontKey, slice, aFontIndex);
-
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
-WebRenderBridgeParent::RecvDeleteFont(const wr::FontKey& aFontKey)
-{
-  if (mDestroyed) {
-    return IPC_OK();
-  }
-  MOZ_ASSERT(mApi);
-
-  // Check if key is obsoleted.
-  if (aFontKey.mNamespace != mIdNamespace) {
-    return IPC_OK();
-  }
-
-  mApi->Resources().DeleteFont(aFontKey);
-
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
-WebRenderBridgeParent::RecvAddFontInstance(const wr::FontInstanceKey& aInstanceKey,
-                                           const wr::FontKey& aFontKey,
-                                           const float& aGlyphSize,
-                                           const MaybeFontInstanceOptions& aOptions,
-                                           const MaybeFontInstancePlatformOptions& aPlatformOptions)
-{
-  if (mDestroyed) {
-    return IPC_OK();
-  }
-
-  // Check if key is obsoleted.
-  if (aInstanceKey.mNamespace != mIdNamespace) {
-    return IPC_OK();
-  }
-
-  MOZ_ASSERT(mApi);
-  mApi->Resources().AddFontInstance(aInstanceKey, aFontKey, aGlyphSize,
-                                    aOptions.ptrOr(nullptr), aPlatformOptions.ptrOr(nullptr));
-
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
-WebRenderBridgeParent::RecvDeleteFontInstance(const wr::FontInstanceKey& aInstanceKey)
-{
-  if (mDestroyed) {
-    return IPC_OK();
-  }
-  MOZ_ASSERT(mApi);
-
-  // Check if key is obsoleted.
-  if (aInstanceKey.mNamespace != mIdNamespace) {
-    return IPC_OK();
-  }
-
-  mApi->Resources().DeleteFontInstance(aInstanceKey);
-
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
-WebRenderBridgeParent::RecvUpdateImage(const wr::ImageKey& aImageKey,
-                                       const gfx::IntSize& aSize,
-                                       const gfx::SurfaceFormat& aFormat,
-                                       const ByteBuffer& aBuffer)
-{
-  if (mDestroyed) {
-    return IPC_OK();
-  }
-  MOZ_ASSERT(mApi);
-
-  // Check if key is obsoleted.
-  if (aImageKey.mNamespace != mIdNamespace) {
-    return IPC_OK();
-  }
-
-  wr::ImageDescriptor descriptor(aSize, aFormat);
-  mApi->Resources().UpdateImageBuffer(aImageKey, descriptor, aBuffer.AsSlice());
-
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
-WebRenderBridgeParent::RecvDeleteImage(const wr::ImageKey& aImageKey)
-{
-  if (mDestroyed) {
-    return IPC_OK();
-  }
-  MOZ_ASSERT(mApi);
-
-  // Check if key is obsoleted.
-  if (aImageKey.mNamespace != mIdNamespace) {
-    return IPC_OK();
-  }
-
-  mKeysToDelete.push_back(aImageKey);
-
-  return IPC_OK();
-}
-
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvDeleteCompositorAnimations(InfallibleTArray<uint64_t>&& aIds)
 {
   if (mDestroyed) {
     return IPC_OK();
   }
 
   for (uint32_t i = 0; i < aIds.Length(); i++) {
--- a/gfx/layers/wr/WebRenderBridgeParent.h
+++ b/gfx/layers/wr/WebRenderBridgeParent.h
@@ -67,43 +67,18 @@ 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 RecvShutdownSync() override;
-  mozilla::ipc::IPCResult RecvUpdateResources(const wr::ByteBuffer& aUpdates) override;
-  mozilla::ipc::IPCResult RecvAddImage(const wr::ImageKey& aImageKey,
-                                       const gfx::IntSize& aSize,
-                                       const uint32_t& aStride,
-                                       const gfx::SurfaceFormat& aFormat,
-                                       const ByteBuffer& aBuffer) override;
-  mozilla::ipc::IPCResult RecvAddBlobImage(const wr::ImageKey& aImageKey,
-                                           const gfx::IntSize& aSize,
-                                           const uint32_t& aStride,
-                                           const gfx::SurfaceFormat& aFormat,
-                                           const ByteBuffer& aBuffer) override;
-  mozilla::ipc::IPCResult RecvUpdateImage(const wr::ImageKey& aImageKey,
-                                          const gfx::IntSize& aSize,
-                                          const gfx::SurfaceFormat& aFormat,
-                                          const ByteBuffer& aBuffer) override;
-  mozilla::ipc::IPCResult RecvDeleteImage(const wr::ImageKey& a1) override;
   mozilla::ipc::IPCResult RecvDeleteCompositorAnimations(InfallibleTArray<uint64_t>&& aIds) override;
-  mozilla::ipc::IPCResult RecvAddRawFont(const wr::FontKey& aFontKey,
-                                         const ByteBuffer& aBuffer,
-                                         const uint32_t& aFontIndex) override;
-  mozilla::ipc::IPCResult RecvDeleteFont(const wr::FontKey& aFontKey) override;
-  mozilla::ipc::IPCResult RecvAddFontInstance(const wr::FontInstanceKey& aInstanceKey,
-                                              const wr::FontKey& aFontKey,
-                                              const float& aGlyphSize,
-                                              const MaybeFontInstanceOptions& aOptions,
-                                              const MaybeFontInstancePlatformOptions& aPlatformOptions) override;
-  mozilla::ipc::IPCResult RecvDeleteFontInstance(const wr::FontInstanceKey& aInstanceKey) override;
+  mozilla::ipc::IPCResult RecvUpdateResources(const ByteBuffer& aUpdates) override;
   mozilla::ipc::IPCResult RecvSetDisplayList(const gfx::IntSize& aSize,
                                              InfallibleTArray<WebRenderParentCommand>&& aCommands,
                                              InfallibleTArray<OpDestroy>&& aToDestroy,
                                              const uint64_t& aFwdTransactionId,
                                              const uint64_t& aTransactionId,
                                              const wr::LayoutSize& aContentSize,
                                              const wr::ByteBuffer& dl,
                                              const wr::BuiltDisplayListDescriptor& dlDesc,
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -98,17 +98,17 @@ WebRenderLayerManager::DoDestroy(bool aI
   }
 
   mWidget->CleanupWebRenderWindowOverlay(WrBridge());
 
   LayerManager::Destroy();
 
   if (WrBridge()) {
     // Just clear ImageKeys, they are deleted during WebRenderAPI destruction.
-    mImageKeysToDelete.clear();
+    mImageKeysToDelete.Clear();
     // CompositorAnimations are cleared by WebRenderBridgeParent.
     mDiscardedCompositorAnimationsIds.Clear();
     WrBridge()->Destroy(aIsSync);
   }
 
   mLastCanvasDatas.Clear();
 
   if (mTransactionIdAllocator) {
@@ -574,19 +574,20 @@ WebRenderLayerManager::GenerateFallbackD
       RefPtr<gfx::DrawEventRecorderMemory> recorder = MakeAndAddRef<gfx::DrawEventRecorderMemory>();
       // TODO: should use 'format' to replace gfx::SurfaceFormat::B8G8R8X8. Currently blob image doesn't support A8 format.
       RefPtr<gfx::DrawTarget> dummyDt =
         gfx::Factory::CreateDrawTarget(gfx::BackendType::SKIA, gfx::IntSize(1, 1), gfx::SurfaceFormat::B8G8R8X8);
       RefPtr<gfx::DrawTarget> dt = gfx::Factory::CreateRecordingDrawTarget(recorder, dummyDt, imageSize.ToUnknownSize());
       PaintItemByDrawTarget(aItem, dt, aImageRect, aOffset, aDisplayListBuilder);
       recorder->Finish();
 
-      wr::ByteBuffer bytes(recorder->mOutputStream.mLength, (uint8_t*)recorder->mOutputStream.mData);
+      Range<uint8_t> bytes((uint8_t*)recorder->mOutputStream.mData, recorder->mOutputStream.mLength);
       wr::ImageKey key = WrBridge()->GetNextImageKey();
-      WrBridge()->SendAddBlobImage(key, imageSize.ToUnknownSize(), 0, dt->GetFormat(), bytes);
+      wr::ImageDescriptor descriptor(imageSize.ToUnknownSize(), 0, dt->GetFormat());
+      aBuilder.Resources().AddBlobImage(key, descriptor, bytes);
       fallbackData->SetKey(key);
     } else {
       fallbackData->CreateImageClientIfNeeded();
       RefPtr<ImageClient> imageClient = fallbackData->GetImageClient();
       RefPtr<ImageContainer> imageContainer = LayerManager::CreateImageContainer();
 
       {
         UpdateImageHelper helper(imageContainer, imageClient, imageSize.ToUnknownSize(), format);
@@ -904,28 +905,23 @@ WebRenderLayerManager::MakeSnapshotIfReq
   dt->FillRect(dst, pattern);
 
   mTarget = nullptr;
 }
 
 void
 WebRenderLayerManager::AddImageKeyForDiscard(wr::ImageKey key)
 {
-  mImageKeysToDelete.push_back(key);
+  mImageKeysToDelete.DeleteImage(key);
 }
 
 void
 WebRenderLayerManager::DiscardImages()
 {
-  if (WrBridge()->IPCOpen()) {
-    for (auto key : mImageKeysToDelete) {
-      WrBridge()->SendDeleteImage(key);
-    }
-  }
-  mImageKeysToDelete.clear();
+  WrBridge()->UpdateResources(mImageKeysToDelete);
 }
 
 void
 WebRenderLayerManager::AddCompositorAnimationsIdForDiscard(uint64_t aId)
 {
   mDiscardedCompositorAnimationsIds.AppendElement(aId);
 }
 
@@ -940,17 +936,17 @@ WebRenderLayerManager::DiscardCompositor
 }
 
 void
 WebRenderLayerManager::DiscardLocalImages()
 {
   // Removes images but doesn't tell the parent side about them
   // This is useful in empty / failed transactions where we created
   // image keys but didn't tell the parent about them yet.
-  mImageKeysToDelete.clear();
+  mImageKeysToDelete.Clear();
 }
 
 void
 WebRenderLayerManager::Mutated(Layer* aLayer)
 {
   LayerManager::Mutated(aLayer);
   AddMutatedLayer(aLayer);
 }
--- a/gfx/layers/wr/WebRenderLayerManager.h
+++ b/gfx/layers/wr/WebRenderLayerManager.h
@@ -236,17 +236,17 @@ private:
   bool EndTransactionInternal(DrawPaintedLayerCallback aCallback,
                               void* aCallbackData,
                               EndTransactionFlags aFlags,
                               nsDisplayList* aDisplayList = nullptr,
                               nsDisplayListBuilder* aDisplayListBuilder = nullptr);
 
 private:
   nsIWidget* MOZ_NON_OWNING_REF mWidget;
-  std::vector<wr::ImageKey> mImageKeysToDelete;
+  wr::ResourceUpdateQueue mImageKeysToDelete;
   nsTArray<uint64_t> mDiscardedCompositorAnimationsIds;
 
   /* PaintedLayer callbacks; valid at the end of a transaciton,
    * while rendering */
   DrawPaintedLayerCallback mPaintedLayerCallback;
   void *mPaintedLayerCallbackData;
 
   RefPtr<WebRenderBridgeChild> mWrChild;
--- a/gfx/layers/wr/WebRenderPaintedLayerBlob.cpp
+++ b/gfx/layers/wr/WebRenderPaintedLayerBlob.cpp
@@ -68,23 +68,24 @@ WebRenderPaintedLayerBlob::RenderLayer(w
     }
 
     recorder->Finish();
 
     AddToValidRegion(regionToPaint);
 
     wr::ByteBuffer bytes(recorder->mOutputStream.mLength, (uint8_t*)recorder->mOutputStream.mData);
 
-    //XXX: We should switch to updating the blob image instead of adding a new one
-    //     That will get rid of this discard bit
     if (mImageKey.isSome()) {
-      WrManager()->AddImageKeyForDiscard(mImageKey.value());
+      //XXX: We should switch to updating the blob image instead of adding a new one
+      aBuilder.Resources().DeleteImage(mImageKey.value());
     }
     mImageKey = Some(GenerateImageKey());
-    WrBridge()->SendAddBlobImage(mImageKey.value(), imageSize, 0, dt->GetFormat(), bytes);
+
+    wr::ImageDescriptor descriptor(imageSize, 0, dt->GetFormat());
+    aBuilder.Resources().AddBlobImage(mImageKey.value(), descriptor, bytes.AsSlice());
     mImageBounds = visibleRegion.GetBounds();
   }
 
   ScrollingLayersHelper scroller(this, aBuilder, aSc);
   StackingContextHelper sc(aSc, aBuilder, this);
   LayerRect rect = Bounds();
   DumpLayerInfo("PaintedLayer", rect);
 
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -478,16 +478,22 @@ ResourceUpdateQueue
 ResourceUpdateQueue::Deserialize(Range<uint8_t> aData)
 {
   auto slice = wr::RangeToByteSlice(aData);
   ResourceUpdateQueue result(wr_resource_updates_deserialize(slice));
   return result;
 }
 
 void
+ResourceUpdateQueue::Clear()
+{
+  wr_resource_updates_clear(mUpdates);
+}
+
+void
 ResourceUpdateQueue::AddImage(ImageKey key, const ImageDescriptor& aDescriptor,
                               Range<uint8_t> aBytes)
 {
   wr_resource_updates_add_image(mUpdates,
                                 key,
                                 &aDescriptor,
                                 RangeToByteSlice(aBytes));
 }
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -105,16 +105,18 @@ public:
   void AddFontInstance(wr::FontInstanceKey aKey,
                        wr::FontKey aFontKey,
                        float aGlyphSize,
                        const wr::FontInstanceOptions* aOptions,
                        const wr::FontInstancePlatformOptions* aPlatformOptions);
 
   void DeleteFontInstance(wr::FontInstanceKey aKey);
 
+  void Clear();
+
   // Try to avoid using this when possible.
   wr::ResourceUpdates* Raw() { return mUpdates; }
 
 protected:
   ResourceUpdateQueue(wr::ResourceUpdates* aUpdates)
   : mUpdates(aUpdates) {}
 
   wr::ResourceUpdates* mUpdates;
@@ -363,32 +365,36 @@ public:
                      const wr::LayoutRect& aBoxBounds,
                      const wr::LayoutVector2D& aOffset,
                      const wr::ColorF& aColor,
                      const float& aBlurRadius,
                      const float& aSpreadRadius,
                      const float& aBorderRadius,
                      const wr::BoxShadowClipMode& aClipMode);
 
+  ResourceUpdateQueue& Resources() { return mResourceUpdates; }
+
   // Returns the clip id that was most recently pushed with PushClip and that
   // has not yet been popped with PopClip. Return Nothing() if the clip stack
   // is empty.
   Maybe<wr::WrClipId> TopmostClipId();
   // Same as TopmostClipId() but for scroll layers.
   layers::FrameMetrics::ViewID TopmostScrollId();
   // Returns the scroll id that was pushed just before the given scroll id. This
   // function returns Nothing() if the given scrollid has not been encountered,
   // or if it is the rootmost scroll id (and therefore has no ancestor).
   Maybe<layers::FrameMetrics::ViewID> ParentScrollIdFor(layers::FrameMetrics::ViewID aScrollId);
 
   // Try to avoid using this when possible.
   wr::WrState* Raw() { return mWrState; }
 protected:
   wr::WrState* mWrState;
 
+  ResourceUpdateQueue mResourceUpdates;
+
   // Track the stack of clip ids and scroll layer ids that have been pushed
   // (by PushClip and PushScrollLayer, respectively) and are still active.
   // This is helpful for knowing e.g. what the ancestor scroll id of a particular
   // scroll id is, and doing other "queries" of current state.
   std::vector<wr::WrClipId> mClipIdStack;
   std::vector<layers::FrameMetrics::ViewID> mScrollIdStack;
 
   // Track the parent scroll id of each scroll id that we encountered. A
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -952,16 +952,21 @@ pub extern "C" fn wr_resource_updates_de
 }
 
 #[no_mangle]
 pub extern "C" fn wr_resource_updates_new() -> *mut ResourceUpdates {
     let updates = Box::new(ResourceUpdates::new());
     Box::into_raw(updates)
 }
 
+#[no_mangle]
+pub extern "C" fn wr_resource_updates_clear(resources: &mut ResourceUpdates) {
+    resources.updates.clear();
+}
+
 /// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
 #[no_mangle]
 pub extern "C" fn wr_resource_updates_delete(updates: *mut ResourceUpdates) {
     unsafe {
         Box::from_raw(updates);
     }
 }
 
--- a/gfx/webrender_bindings/webrender_ffi_generated.h
+++ b/gfx/webrender_bindings/webrender_ffi_generated.h
@@ -1201,16 +1201,20 @@ WR_INLINE
 void wr_resource_updates_add_raw_font(ResourceUpdates *aResources,
                                       WrFontKey aKey,
                                       uint8_t *aFontBuffer,
                                       size_t aBufferSize,
                                       uint32_t aIndex)
 WR_FUNC;
 
 WR_INLINE
+void wr_resource_updates_clear(ResourceUpdates *aResources)
+WR_FUNC;
+
+WR_INLINE
 void wr_resource_updates_delete(ResourceUpdates *aUpdates)
 WR_DESTRUCTOR_SAFE_FUNC;
 
 WR_INLINE
 void wr_resource_updates_delete_font(ResourceUpdates *aResources,
                                      WrFontKey aKey)
 WR_FUNC;
 
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -2103,36 +2103,40 @@ nsChildView::AddWindowOverlayWebRenderCo
         mTitlebarImageSize != size) {
       // Delete wr::ImageKey. wr::ImageKey does not support size change.
       CleanupWebRenderWindowOverlay(aWrBridge);
       MOZ_ASSERT(mTitlebarImageKey.isNothing());
     }
 
     if (!mTitlebarImageKey) {
       mTitlebarImageKey = Some(aWrBridge->GetNextImageKey());
-      aWrBridge->SendAddImage(*mTitlebarImageKey, size, stride, format, buffer);
+      wr::ImageDescriptor descriptor(size, stride, format);
+      aBuilder.Resources().AddImage(*mTitlebarImageKey, descriptor, buffer);
       mTitlebarImageSize = size;
       updatedTitlebarRegion.SetEmpty();
     }
 
     if (!updatedTitlebarRegion.IsEmpty()) {
-      aWrBridge->SendUpdateImage(*mTitlebarImageKey, size, format, buffer);
+      wr::ImageDescriptor descriptor(size, stride, format);
+      aBuilder.Resources().UpdateImage(*mTitlebarImageKey, descriptor, buffer);
     }
 
     wr::LayoutRect rect = wr::ToLayoutRect(mTitlebarRect);
     aBuilder.PushImage(wr::LayoutRect{ { 0, 0 }, { float(size.width), float(size.height) } },
                        rect, wr::ImageRendering::Auto, *mTitlebarImageKey);
   }
 }
 
 void
 nsChildView::CleanupWebRenderWindowOverlay(layers::WebRenderBridgeChild* aWrBridge)
 {
   if (mTitlebarImageKey) {
-    aWrBridge->SendDeleteImage(*mTitlebarImageKey);
+    ResourceUpdateQueue resources;
+    resources.DeleteImage(*mTitlebarImageKey);
+    aWrBridge->UpdateResources(resources);
     mTitlebarImageKey = Nothing();
   }
 }
 
 bool
 nsChildView::PreRender(WidgetRenderingContext* aContext)
 {
   UniquePtr<GLManager> manager(GLManager::CreateGLManager(aContext->mLayerManager));