Bug 1393031 - Expose webrender resource updates in the C++ wrapper. r=sotaro
authorNicolas Silva <nsilva@mozilla.com>
Mon, 04 Sep 2017 13:59:12 +0200
changeset 378848 73cbc76a296bd9558d3ec3bee9dfb1ec26c08337
parent 378847 6238f14363f27df8cc8d570e7e4d8dce25299ba1
child 378849 684dd3236401702bac2c609066191b85e7368646
push id32443
push userarchaeopteryx@coole-files.de
push dateTue, 05 Sep 2017 09:41:20 +0000
treeherdermozilla-central@3ecda4678c49 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssotaro
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 - Expose webrender resource updates in the C++ wrapper. r=sotaro
gfx/layers/composite/TextureHost.cpp
gfx/layers/d3d11/TextureD3D11.cpp
gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp
gfx/layers/wr/AsyncImagePipelineManager.cpp
gfx/layers/wr/WebRenderBridgeParent.cpp
gfx/webrender_bindings/WebRenderAPI.cpp
gfx/webrender_bindings/WebRenderAPI.h
gfx/webrender_bindings/src/bindings.rs
gfx/webrender_bindings/webrender_ffi_generated.h
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -591,38 +591,38 @@ BufferTextureHost::AddWRImage(wr::WebRen
                               const wr::ExternalImageId& aExtID)
 {
   if (GetFormat() != gfx::SurfaceFormat::YUV) {
     MOZ_ASSERT(aImageKeys.length() == 1);
 
     wr::ImageDescriptor descriptor(GetSize(),
                                    ImageDataSerializer::ComputeRGBStride(GetFormat(), GetSize().width),
                                    GetFormat());
-    aAPI->AddExternalImageBuffer(aImageKeys[0], descriptor, aExtID);
+    aAPI->Resources().AddExternalImageBuffer(aImageKeys[0], descriptor, aExtID);
   } else {
     MOZ_ASSERT(aImageKeys.length() == 3);
 
     const layers::YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
     wr::ImageDescriptor yDescriptor(desc.ySize(), desc.ySize().width, gfx::SurfaceFormat::A8);
     wr::ImageDescriptor cbcrDescriptor(desc.cbCrSize(), desc.cbCrSize().width, gfx::SurfaceFormat::A8);
-    aAPI->AddExternalImage(aImageKeys[0],
-                           yDescriptor,
-                           aExtID,
-                           wr::WrExternalImageBufferType::ExternalBuffer,
-                           0);
-    aAPI->AddExternalImage(aImageKeys[1],
-                           cbcrDescriptor,
-                           aExtID,
-                           wr::WrExternalImageBufferType::ExternalBuffer,
-                           1);
-    aAPI->AddExternalImage(aImageKeys[2],
-                           cbcrDescriptor,
-                           aExtID,
-                           wr::WrExternalImageBufferType::ExternalBuffer,
-                           2);
+    aAPI->Resources().AddExternalImage(aImageKeys[0],
+                                       yDescriptor,
+                                       aExtID,
+                                       wr::WrExternalImageBufferType::ExternalBuffer,
+                                       0);
+    aAPI->Resources().AddExternalImage(aImageKeys[1],
+                                       cbcrDescriptor,
+                                       aExtID,
+                                       wr::WrExternalImageBufferType::ExternalBuffer,
+                                       1);
+    aAPI->Resources().AddExternalImage(aImageKeys[2],
+                                       cbcrDescriptor,
+                                       aExtID,
+                                       wr::WrExternalImageBufferType::ExternalBuffer,
+                                       2);
   }
 }
 
 void
 BufferTextureHost::PushExternalImage(wr::DisplayListBuilder& aBuilder,
                                      const wr::LayoutRect& aBounds,
                                      const wr::LayoutRect& aClip,
                                      wr::ImageRendering aFilter,
--- a/gfx/layers/d3d11/TextureD3D11.cpp
+++ b/gfx/layers/d3d11/TextureD3D11.cpp
@@ -1072,38 +1072,38 @@ DXGITextureHostD3D11::AddWRImage(wr::Web
   switch (mFormat) {
     case gfx::SurfaceFormat::R8G8B8X8:
     case gfx::SurfaceFormat::R8G8B8A8:
     case gfx::SurfaceFormat::B8G8R8A8:
     case gfx::SurfaceFormat::B8G8R8X8: {
       MOZ_ASSERT(aImageKeys.length() == 1);
 
       wr::ImageDescriptor descriptor(GetSize(), GetFormat());
-      aAPI->AddExternalImage(aImageKeys[0],
-                             descriptor,
-                             aExtID,
-                             wr::WrExternalImageBufferType::Texture2DHandle,
-                             0);
+      aAPI->Resources().AddExternalImage(aImageKeys[0],
+                                         descriptor,
+                                         aExtID,
+                                         wr::WrExternalImageBufferType::Texture2DHandle,
+                                         0);
       break;
     }
     case gfx::SurfaceFormat::NV12: {
       MOZ_ASSERT(aImageKeys.length() == 2);
 
       wr::ImageDescriptor descriptor0(GetSize(), gfx::SurfaceFormat::A8);
       wr::ImageDescriptor descriptor1(GetSize() / 2, gfx::SurfaceFormat::R8G8);
-      aAPI->AddExternalImage(aImageKeys[0],
-                             descriptor0,
-                             aExtID,
-                             wr::WrExternalImageBufferType::TextureExternalHandle,
-                             0);
-      aAPI->AddExternalImage(aImageKeys[1],
-                             descriptor1,
-                             aExtID,
-                             wr::WrExternalImageBufferType::TextureExternalHandle,
-                             1);
+      aAPI->Resources().AddExternalImage(aImageKeys[0],
+                                         descriptor0,
+                                         aExtID,
+                                         wr::WrExternalImageBufferType::TextureExternalHandle,
+                                         0);
+      aAPI->Resources().AddExternalImage(aImageKeys[1],
+                                         descriptor1,
+                                         aExtID,
+                                         wr::WrExternalImageBufferType::TextureExternalHandle,
+                                         1);
       break;
     }
     default: {
       MOZ_ASSERT_UNREACHABLE("unexpected to be called");
     }
   }
 }
 
@@ -1333,17 +1333,17 @@ DXGIYCbCrTextureHostD3D11::AddWRImage(wr
   DataSourceSurface::MappedSurface map;
   if (!dataSourceSurface->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
     return;
   }
 
   IntSize size = dataSourceSurface->GetSize();
   wr::ImageDescriptor descriptor(size, map.mStride, dataSourceSurface->GetFormat());
   auto slice = Range<uint8_t>(map.mData, size.height * map.mStride);
-  aAPI->AddImage(aImageKeys[0], descriptor, slice);
+  aAPI->Resources().AddImage(aImageKeys[0], descriptor, slice);
 
   dataSourceSurface->Unmap();
 }
 
 void
 DXGIYCbCrTextureHostD3D11::PushExternalImage(wr::DisplayListBuilder& aBuilder,
                                              const wr::LayoutRect& aBounds,
                                              const wr::LayoutRect& aClip,
--- a/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp
+++ b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp
@@ -170,55 +170,55 @@ MacIOSurfaceTextureHostOGL::AddWRImage(w
   switch (GetFormat()) {
     case gfx::SurfaceFormat::R8G8B8X8:
     case gfx::SurfaceFormat::R8G8B8A8:
     case gfx::SurfaceFormat::B8G8R8A8:
     case gfx::SurfaceFormat::B8G8R8X8: {
       MOZ_ASSERT(aImageKeys.length() == 1);
       MOZ_ASSERT(mSurface->GetPlaneCount() == 0);
       wr::ImageDescriptor descriptor(GetSize(), GetFormat());
-      aAPI->AddExternalImage(aImageKeys[0],
-                             descriptor,
-                             aExtID,
-                             wr::WrExternalImageBufferType::TextureRectHandle,
-                             0);
+      aAPI->Resources().AddExternalImage(aImageKeys[0],
+                                         descriptor,
+                                         aExtID,
+                                         wr::WrExternalImageBufferType::TextureRectHandle,
+                                         0);
       break;
     }
     case gfx::SurfaceFormat::YUV422: {
       // This is the special buffer format. The buffer contents could be a
       // converted RGB interleaving data or a YCbCr interleaving data depending
       // on the different platform setting. (e.g. It will be RGB at OpenGL 2.1
       // and YCbCr at OpenGL 3.1)
       MOZ_ASSERT(aImageKeys.length() == 1);
       MOZ_ASSERT(mSurface->GetPlaneCount() == 0);
       wr::ImageDescriptor descriptor(GetSize(), gfx::SurfaceFormat::R8G8B8X8);
-      aAPI->AddExternalImage(aImageKeys[0],
-                             descriptor,
-                             aExtID,
-                             wr::WrExternalImageBufferType::TextureRectHandle,
-                             0);
+      aAPI->Resources().AddExternalImage(aImageKeys[0],
+                                         descriptor,
+                                         aExtID,
+                                         wr::WrExternalImageBufferType::TextureRectHandle,
+                                         0);
       break;
     }
     case gfx::SurfaceFormat::NV12: {
       MOZ_ASSERT(aImageKeys.length() == 2);
       MOZ_ASSERT(mSurface->GetPlaneCount() == 2);
       wr::ImageDescriptor descriptor0(gfx::IntSize(mSurface->GetDevicePixelWidth(0), mSurface->GetDevicePixelHeight(0)),
                                       gfx::SurfaceFormat::A8);
       wr::ImageDescriptor descriptor1(gfx::IntSize(mSurface->GetDevicePixelWidth(1), mSurface->GetDevicePixelHeight(1)),
                                       gfx::SurfaceFormat::R8G8);
-      aAPI->AddExternalImage(aImageKeys[0],
-                             descriptor0,
-                             aExtID,
-                             wr::WrExternalImageBufferType::TextureRectHandle,
-                             0);
-      aAPI->AddExternalImage(aImageKeys[1],
-                             descriptor1,
-                             aExtID,
-                             wr::WrExternalImageBufferType::TextureRectHandle,
-                             1);
+      aAPI->Resources().AddExternalImage(aImageKeys[0],
+                                         descriptor0,
+                                         aExtID,
+                                         wr::WrExternalImageBufferType::TextureRectHandle,
+                                         0);
+      aAPI->Resources().AddExternalImage(aImageKeys[1],
+                                         descriptor1,
+                                         aExtID,
+                                         wr::WrExternalImageBufferType::TextureRectHandle,
+                                         1);
       break;
     }
     default: {
       MOZ_ASSERT_UNREACHABLE("unexpected to be called");
     }
   }
 }
 
--- a/gfx/layers/wr/AsyncImagePipelineManager.cpp
+++ b/gfx/layers/wr/AsyncImagePipelineManager.cpp
@@ -53,18 +53,19 @@ AsyncImagePipelineManager::HasKeysToDele
   return !mKeysToDelete.IsEmpty();
 }
 
 void
 AsyncImagePipelineManager::DeleteOldAsyncImages()
 {
   MOZ_ASSERT(!mDestroyed);
   for (wr::ImageKey key : mKeysToDelete) {
-    mApi->DeleteImage(key);
+    mApi->Resources().DeleteImage(key);
   }
+  mApi->UpdateResources(mApi->Resources());
   mKeysToDelete.Clear();
 }
 
 void
 AsyncImagePipelineManager::AddPipeline(const wr::PipelineId& aPipelineId)
 {
   if (mDestroyed) {
     return;
@@ -120,19 +121,19 @@ AsyncImagePipelineManager::RemoveAsyncIm
   if (mDestroyed) {
     return;
   }
 
   uint64_t id = wr::AsUint64(aPipelineId);
   if (auto entry = mAsyncImagePipelines.Lookup(id)) {
     AsyncImagePipeline* holder = entry.Data();
     ++mAsyncImageEpoch; // Update webrender epoch
-    mApi->ClearRootDisplayList(wr::NewEpoch(mAsyncImageEpoch), aPipelineId);
+    mApi->ClearDisplayList(wr::NewEpoch(mAsyncImageEpoch), aPipelineId);
     for (wr::ImageKey key : holder->mKeys) {
-      mApi->DeleteImage(key);
+      mApi->Resources().DeleteImage(key);
     }
     entry.Remove();
     RemovePipeline(aPipelineId, wr::NewEpoch(mAsyncImageEpoch));
   }
 }
 
 void
 AsyncImagePipelineManager::UpdateAsyncImagePipeline(const wr::PipelineId& aPipelineId,
@@ -184,17 +185,17 @@ AsyncImagePipelineManager::GenerateImage
       return false;
     }
     gfx::IntSize size = dSurf->GetSize();
     wr::ImageDescriptor descriptor(size, map.mStride, dSurf->GetFormat());
     auto slice = Range<uint8_t>(map.mData, size.height * map.mStride);
 
     wr::ImageKey key = GenerateImageKey();
     aKeys.AppendElement(key);
-    mApi->AddImage(key, descriptor, slice);
+    mApi->Resources().AddImage(key, descriptor, slice);
     dSurf->Unmap();
   }
   return false;
 }
 
 bool
 AsyncImagePipelineManager::UpdateImageKeys(bool& aUseExternalImage,
                                            AsyncImagePipeline* aImageMgr,
@@ -304,19 +305,19 @@ AsyncImagePipelineManager::ApplyAsyncIma
                           keys[0]);
       }
       builder.PopStackingContext();
     }
 
     wr::BuiltDisplayList dl;
     wr::LayoutSize builderContentSize;
     builder.Finalize(builderContentSize, dl);
-    mApi->SetRootDisplayList(gfx::Color(0.f, 0.f, 0.f, 0.f), epoch, LayerSize(pipeline->mScBounds.Width(), pipeline->mScBounds.Height()),
-                             pipelineId, builderContentSize,
-                             dl.dl_desc, dl.dl.inner.data, dl.dl.inner.length);
+    mApi->SetDisplayList(gfx::Color(0.f, 0.f, 0.f, 0.f), epoch, LayerSize(pipeline->mScBounds.Width(), pipeline->mScBounds.Height()),
+                         pipelineId, builderContentSize,
+                         dl.dl_desc, dl.dl.inner.data, dl.dl.inner.length);
   }
   DeleteOldAsyncImages();
   mKeysToDelete.SwapElements(keysToDelete);
 }
 
 void
 AsyncImagePipelineManager::HoldExternalImage(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, WebRenderTextureHost* aTexture)
 {
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -237,18 +237,17 @@ WebRenderBridgeParent::RecvAddImage(cons
     return IPC_OK();
   }
 
   MOZ_ASSERT(mApi);
   MOZ_ASSERT(mActiveImageKeys.find(wr::AsUint64(aImageKey)) == mActiveImageKeys.end());
 
   wr::ImageDescriptor descriptor(aSize, aStride, aFormat);
   mActiveImageKeys.insert(wr::AsUint64(aImageKey));
-  mApi->AddImage(aImageKey, descriptor,
-                 aBuffer.AsSlice());
+  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,
@@ -264,18 +263,17 @@ WebRenderBridgeParent::RecvAddBlobImage(
     return IPC_OK();
   }
 
   MOZ_ASSERT(mApi);
   MOZ_ASSERT(mActiveImageKeys.find(wr::AsUint64(aImageKey)) == mActiveImageKeys.end());
 
   wr::ImageDescriptor descriptor(aSize, aStride, aFormat);
   mActiveImageKeys.insert(wr::AsUint64(aImageKey));
-  mApi->AddBlobImage(aImageKey, descriptor,
-                     aBuffer.AsSlice());
+  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)
@@ -289,17 +287,17 @@ WebRenderBridgeParent::RecvAddRawFont(co
     return IPC_OK();
   }
 
   MOZ_ASSERT(mApi);
   MOZ_ASSERT(mFontKeys.find(wr::AsUint64(aFontKey)) == mFontKeys.end());
 
   auto slice = aBuffer.AsSlice();
   mFontKeys.insert(wr::AsUint64(aFontKey));
-  mApi->AddRawFont(aFontKey, slice, aFontIndex);
+  mApi->Resources().AddRawFont(aFontKey, slice, aFontIndex);
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvDeleteFont(const wr::FontKey& aFontKey)
 {
   if (mDestroyed) {
@@ -308,17 +306,17 @@ WebRenderBridgeParent::RecvDeleteFont(co
   MOZ_ASSERT(mApi);
 
   // Check if key is obsoleted.
   if (aFontKey.mNamespace != mIdNamespace) {
     return IPC_OK();
   }
 
   if (mFontKeys.erase(wr::AsUint64(aFontKey)) > 0) {
-    mApi->DeleteFont(aFontKey);
+    mApi->Resources().DeleteFont(aFontKey);
   } else {
     MOZ_ASSERT_UNREACHABLE("invalid FontKey");
   }
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
@@ -336,18 +334,18 @@ WebRenderBridgeParent::RecvAddFontInstan
   if (aInstanceKey.mNamespace != mIdNamespace) {
     return IPC_OK();
   }
 
   MOZ_ASSERT(mApi);
   MOZ_ASSERT(mFontInstanceKeys.find(wr::AsUint64(aInstanceKey)) == mFontInstanceKeys.end());
 
   mFontInstanceKeys.insert(wr::AsUint64(aInstanceKey));
-  mApi->AddFontInstance(aInstanceKey, aFontKey, aGlyphSize,
-                        aOptions.ptrOr(nullptr), aPlatformOptions.ptrOr(nullptr));
+  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) {
@@ -356,17 +354,17 @@ WebRenderBridgeParent::RecvDeleteFontIns
   MOZ_ASSERT(mApi);
 
   // Check if key is obsoleted.
   if (aInstanceKey.mNamespace != mIdNamespace) {
     return IPC_OK();
   }
 
   if (mFontInstanceKeys.erase(wr::AsUint64(aInstanceKey)) > 0) {
-    mApi->DeleteFontInstance(aInstanceKey);
+    mApi->Resources().DeleteFontInstance(aInstanceKey);
   } else {
     MOZ_ASSERT_UNREACHABLE("invalid FontInstanceKey");
   }
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
@@ -381,17 +379,17 @@ WebRenderBridgeParent::RecvUpdateImage(c
   MOZ_ASSERT(mApi);
 
   // Check if key is obsoleted.
   if (aImageKey.mNamespace != mIdNamespace) {
     return IPC_OK();
   }
 
   wr::ImageDescriptor descriptor(aSize, aFormat);
-  mApi->UpdateImageBuffer(aImageKey, descriptor, aBuffer.AsSlice());
+  mApi->Resources().UpdateImageBuffer(aImageKey, descriptor, aBuffer.AsSlice());
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvDeleteImage(const wr::ImageKey& aImageKey)
 {
   if (mDestroyed) {
@@ -655,17 +653,17 @@ WebRenderBridgeParent::ProcessWebRenderP
         if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
           NS_ERROR("DataSourceSurface failed to map");
           break;
         }
 
         IntSize size = dSurf->GetSize();
         wr::ImageDescriptor descriptor(size, map.mStride, dSurf->GetFormat());
         auto slice = Range<uint8_t>(map.mData, size.height * map.mStride);
-        mApi->AddImage(keys[0], descriptor, slice);
+        mApi->Resources().AddImage(keys[0], descriptor, slice);
 
         dSurf->Unmap();
         break;
       }
       case WebRenderParentCommand::TOpUpdateAsyncImagePipeline: {
         const OpUpdateAsyncImagePipeline& op = cmd.get_OpUpdateAsyncImagePipeline();
         mAsyncImageManager->UpdateAsyncImagePipeline(op.pipelineId(),
                                                       op.scBounds(),
@@ -723,19 +721,19 @@ WebRenderBridgeParent::ProcessWebRenderC
     return;
   }
 
   if (mWidget) {
     LayoutDeviceIntSize size = mWidget->GetClientSize();
     mApi->SetWindowParameters(size);
   }
   gfx::Color color = mWidget ? gfx::Color(0.3f, 0.f, 0.f, 1.f) : gfx::Color(0.f, 0.f, 0.f, 0.f);
-  mApi->SetRootDisplayList(color, aEpoch, LayerSize(aSize.width, aSize.height),
-                           mPipelineId, aContentSize,
-                           dlDesc, dl.mData, dl.mLength);
+  mApi->SetDisplayList(color, aEpoch, LayerSize(aSize.width, aSize.height),
+                       mPipelineId, aContentSize,
+                       dlDesc, dl.mData, dl.mLength);
 
   ScheduleComposition();
   DeleteOldImages();
 
   if (ShouldParentObserveEpoch()) {
     mCompositorBridge->ObserveLayerUpdate(GetLayersId(), GetChildLayerObserverEpoch(), true);
   }
 }
@@ -900,17 +898,17 @@ mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvClearCachedResources()
 {
   if (mDestroyed) {
     return IPC_OK();
   }
   mCompositorBridge->ObserveLayerUpdate(GetLayersId(), GetChildLayerObserverEpoch(), false);
 
   // Clear resources
-  mApi->ClearRootDisplayList(wr::NewEpoch(GetNextWrEpoch()), mPipelineId);
+  mApi->ClearDisplayList(wr::NewEpoch(GetNextWrEpoch()), mPipelineId);
   // Schedule composition to clean up Pipeline
   mCompositorScheduler->ScheduleComposition();
   DeleteOldImages();
   // Remove animations.
   for (std::unordered_set<uint64_t>::iterator iter = mActiveAnimations.begin(); iter != mActiveAnimations.end(); iter++) {
     mAnimStorage->ClearById(*iter);
   }
   mActiveAnimations.clear();
@@ -1272,18 +1270,19 @@ WebRenderBridgeParent::GetLayersId() con
 {
   return wr::AsUint64(mPipelineId);
 }
 
 void
 WebRenderBridgeParent::DeleteOldImages()
 {
   for (wr::ImageKey key : mKeysToDelete) {
-    mApi->DeleteImage(key);
+    mApi->Resources().DeleteImage(key);
   }
+  mApi->UpdateResources(mApi->Resources());
   mKeysToDelete.clear();
 }
 
 void
 WebRenderBridgeParent::ScheduleComposition()
 {
   if (mCompositorScheduler) {
     mCompositorScheduler->ScheduleComposition();
@@ -1343,17 +1342,17 @@ WebRenderBridgeParent::Resume()
 void
 WebRenderBridgeParent::ClearResources()
 {
   if (!mApi) {
     return;
   }
 
   uint32_t wrEpoch = GetNextWrEpoch();
-  mApi->ClearRootDisplayList(wr::NewEpoch(wrEpoch), mPipelineId);
+  mApi->ClearDisplayList(wr::NewEpoch(wrEpoch), mPipelineId);
   // Schedule composition to clean up Pipeline
   mCompositorScheduler->ScheduleComposition();
   // WrFontKeys and WrImageKeys are deleted during WebRenderAPI destruction.
   mFontInstanceKeys.clear();
   mFontKeys.clear();
   mActiveImageKeys.clear();
   mKeysToDelete.clear();
   for (auto iter = mExternalImageIds.Iter(); !iter.Done(); iter.Next()) {
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -223,41 +223,42 @@ WebRenderAPI::GenerateFrame(const nsTArr
                                           nullptr : aOpacityArray.Elements(),
                                         aOpacityArray.Length(),
                                         aTransformArray.IsEmpty() ?
                                           nullptr : aTransformArray.Elements(),
                                         aTransformArray.Length());
 }
 
 void
-WebRenderAPI::SetRootDisplayList(gfx::Color aBgColor,
-                                 Epoch aEpoch,
-                                 mozilla::LayerSize aViewportSize,
-                                 wr::WrPipelineId pipeline_id,
-                                 const LayoutSize& content_size,
-                                 wr::BuiltDisplayListDescriptor dl_descriptor,
-                                 uint8_t *dl_data,
-                                 size_t dl_size)
+WebRenderAPI::SetDisplayList(gfx::Color aBgColor,
+                             Epoch aEpoch,
+                             mozilla::LayerSize aViewportSize,
+                             wr::WrPipelineId pipeline_id,
+                             const LayoutSize& content_size,
+                             wr::BuiltDisplayListDescriptor dl_descriptor,
+                             uint8_t *dl_data,
+                             size_t dl_size)
 {
-    wr_api_set_root_display_list(mDocHandle,
-                                 ToColorF(aBgColor),
-                                 aEpoch,
-                                 aViewportSize.width, aViewportSize.height,
-                                 pipeline_id,
-                                 content_size,
-                                 dl_descriptor,
-                                 dl_data,
-                                 dl_size);
+    wr_api_set_display_list(mDocHandle,
+                            ToColorF(aBgColor),
+                            aEpoch,
+                            aViewportSize.width, aViewportSize.height,
+                            pipeline_id,
+                            content_size,
+                            dl_descriptor,
+                            dl_data,
+                            dl_size,
+                            mResources.Raw());
 }
 
 void
-WebRenderAPI::ClearRootDisplayList(Epoch aEpoch,
-                                   wr::WrPipelineId pipeline_id)
+WebRenderAPI::ClearDisplayList(Epoch aEpoch,
+                               wr::WrPipelineId pipeline_id)
 {
-  wr_api_clear_root_display_list(mDocHandle, aEpoch, pipeline_id);
+  wr_api_clear_display_list(mDocHandle, aEpoch, pipeline_id, mResources.Raw());
 }
 
 void
 WebRenderAPI::SetWindowParameters(LayoutDeviceIntSize size)
 {
   wr_api_set_window_parameters(mDocHandle, size.width, size.height);
 }
 
@@ -419,130 +420,147 @@ WebRenderAPI::WaitFlushed()
 
 void
 WebRenderAPI::SetRootPipeline(PipelineId aPipeline)
 {
   wr_api_set_root_pipeline(mDocHandle, aPipeline);
 }
 
 void
-WebRenderAPI::AddImage(ImageKey key, const ImageDescriptor& aDescriptor,
-                       Range<uint8_t> aBytes)
+WebRenderAPI::UpdateResources(ResourceUpdateQueue& aUpdates)
+{
+  wr_api_update_resources(mDocHandle, aUpdates.Raw());
+}
+
+ResourceUpdateQueue::ResourceUpdateQueue()
+{
+  mUpdates = wr_resource_updates_new();
+}
+
+ResourceUpdateQueue::~ResourceUpdateQueue()
 {
-  wr_api_add_image(mDocHandle,
-                   key,
-                   &aDescriptor,
-                   RangeToByteSlice(aBytes));
+  wr_resource_updates_delete(mUpdates);
+}
+
+void
+ResourceUpdateQueue::AddImage(ImageKey key, const ImageDescriptor& aDescriptor,
+                              Range<uint8_t> aBytes)
+{
+  wr_resource_updates_add_image(mUpdates,
+                                key,
+                                &aDescriptor,
+                                RangeToByteSlice(aBytes));
 }
 
 void
-WebRenderAPI::AddBlobImage(ImageKey key, const ImageDescriptor& aDescriptor,
-                           Range<uint8_t> aBytes)
+ResourceUpdateQueue::AddBlobImage(ImageKey key, const ImageDescriptor& aDescriptor,
+                                  Range<uint8_t> aBytes)
 {
-  wr_api_add_blob_image(mDocHandle,
-                        key,
-                        &aDescriptor,
-                        RangeToByteSlice(aBytes));
+  wr_resource_updates_add_blob_image(mUpdates,
+                                     key,
+                                     &aDescriptor,
+                                     RangeToByteSlice(aBytes));
 }
 
 void
-WebRenderAPI::AddExternalImage(ImageKey key,
-                               const ImageDescriptor& aDescriptor,
-                               ExternalImageId aExtID,
-                               wr::WrExternalImageBufferType aBufferType,
-                               uint8_t aChannelIndex)
+ResourceUpdateQueue::AddExternalImage(ImageKey key,
+                                      const ImageDescriptor& aDescriptor,
+                                      ExternalImageId aExtID,
+                                      wr::WrExternalImageBufferType aBufferType,
+                                      uint8_t aChannelIndex)
 {
-  wr_api_add_external_image(mDocHandle,
-                            key,
-                            &aDescriptor,
-                            aExtID,
-                            aBufferType,
-                            aChannelIndex);
+  wr_resource_updates_add_external_image(mUpdates,
+                                         key,
+                                         &aDescriptor,
+                                         aExtID,
+                                         aBufferType,
+                                         aChannelIndex);
 }
 
 void
-WebRenderAPI::AddExternalImageBuffer(ImageKey aKey,
-                                     const ImageDescriptor& aDescriptor,
-                                     ExternalImageId aHandle)
+ResourceUpdateQueue::AddExternalImageBuffer(ImageKey aKey,
+                                            const ImageDescriptor& aDescriptor,
+                                            ExternalImageId aHandle)
 {
   auto channelIndex = 0;
   AddExternalImage(aKey, aDescriptor, aHandle,
                    wr::WrExternalImageBufferType::ExternalBuffer,
                    channelIndex);
 }
 
 void
-WebRenderAPI::UpdateImageBuffer(ImageKey aKey,
-                                const ImageDescriptor& aDescriptor,
-                                Range<uint8_t> aBytes)
+ResourceUpdateQueue::UpdateImageBuffer(ImageKey aKey,
+                                       const ImageDescriptor& aDescriptor,
+                                       Range<uint8_t> aBytes)
 {
-  wr_api_update_image(mDocHandle,
-                      aKey,
-                      &aDescriptor,
-                      RangeToByteSlice(aBytes));
+  wr_resource_updates_update_image(mUpdates,
+                                   aKey,
+                                   &aDescriptor,
+                                   RangeToByteSlice(aBytes));
 }
 
 void
-WebRenderAPI::UpdateBlobImage(ImageKey aKey,
-                              const ImageDescriptor& aDescriptor,
-                              Range<uint8_t> aBytes)
+ResourceUpdateQueue::UpdateBlobImage(ImageKey aKey,
+                                     const ImageDescriptor& aDescriptor,
+                                     Range<uint8_t> aBytes)
 {
-  wr_api_update_blob_image(mDocHandle,
-                           aKey,
-                           &aDescriptor,
-                           RangeToByteSlice(aBytes));
+  wr_resource_updates_update_blob_image(mUpdates,
+                                        aKey,
+                                        &aDescriptor,
+                                        RangeToByteSlice(aBytes));
 }
 
 void
-WebRenderAPI::UpdateExternalImage(ImageKey aKey,
-                                  const ImageDescriptor& aDescriptor,
-                                  ExternalImageId aExtID,
-                                  wr::WrExternalImageBufferType aBufferType,
-                                  uint8_t aChannelIndex)
+ResourceUpdateQueue::UpdateExternalImage(ImageKey aKey,
+                                         const ImageDescriptor& aDescriptor,
+                                         ExternalImageId aExtID,
+                                         wr::WrExternalImageBufferType aBufferType,
+                                         uint8_t aChannelIndex)
 {
-  wr_api_update_external_image(mDocHandle,
-                               aKey,
-                               &aDescriptor,
-                               aExtID,
-                               aBufferType,
-                               aChannelIndex);
+  wr_resource_updates_update_external_image(mUpdates,
+                                            aKey,
+                                            &aDescriptor,
+                                            aExtID,
+                                            aBufferType,
+                                            aChannelIndex);
 }
 
 void
-WebRenderAPI::DeleteImage(ImageKey aKey)
+ResourceUpdateQueue::DeleteImage(ImageKey aKey)
 {
-  wr_api_delete_image(mDocHandle, aKey);
+  wr_resource_updates_delete_image(mUpdates, aKey);
 }
 
 void
-WebRenderAPI::AddRawFont(wr::FontKey aKey, Range<uint8_t> aBytes, uint32_t aIndex)
+ResourceUpdateQueue::AddRawFont(wr::FontKey aKey, Range<uint8_t> aBytes, uint32_t aIndex)
 {
-  wr_api_add_raw_font(mDocHandle, aKey, &aBytes[0], aBytes.length(), aIndex);
+  wr_resource_updates_add_raw_font(mUpdates, aKey, &aBytes[0], aBytes.length(), aIndex);
 }
 
 void
-WebRenderAPI::DeleteFont(wr::FontKey aKey)
+ResourceUpdateQueue::DeleteFont(wr::FontKey aKey)
 {
-  wr_api_delete_font(mDocHandle, aKey);
+  wr_resource_updates_delete_font(mUpdates, aKey);
 }
 
 void
-WebRenderAPI::AddFontInstance(wr::FontInstanceKey aKey,
-                              wr::FontKey aFontKey,
-                              float aGlyphSize,
-                              const wr::FontInstanceOptions* aOptions,
-                              const wr::FontInstancePlatformOptions* aPlatformOptions)
+ResourceUpdateQueue::AddFontInstance(wr::FontInstanceKey aKey,
+                                     wr::FontKey aFontKey,
+                                     float aGlyphSize,
+                                     const wr::FontInstanceOptions* aOptions,
+                                     const wr::FontInstancePlatformOptions* aPlatformOptions)
 {
-  wr_api_add_font_instance(mDocHandle, aKey, aFontKey, aGlyphSize, aOptions, aPlatformOptions);
+  wr_resource_updates_add_font_instance(mUpdates, aKey, aFontKey, aGlyphSize,
+                                        aOptions, aPlatformOptions);
 }
 
 void
-WebRenderAPI::DeleteFontInstance(wr::FontInstanceKey aKey)
+ResourceUpdateQueue::DeleteFontInstance(wr::FontInstanceKey aKey)
 {
-  wr_api_delete_font_instance(mDocHandle, aKey);
+  wr_resource_updates_delete_font_instance(mUpdates, aKey);
 }
 
 class FrameStartTime : public RendererEvent
 {
 public:
   explicit FrameStartTime(const TimeStamp& aTime)
     : mTime(aTime)
   {
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -43,52 +43,23 @@ struct Line {
   float start;
   float end;
   float width;
   wr::ColorF color;
   wr::LineOrientation orientation;
   wr::LineStyle style;
 };
 
-class WebRenderAPI
-{
-  NS_INLINE_DECL_REFCOUNTING(WebRenderAPI);
-
+/// Updates to retained resources such as images and fonts, applied within the
+/// same transaction.
+class ResourceUpdateQueue {
 public:
-  /// This can be called on the compositor thread only.
-  static already_AddRefed<WebRenderAPI> Create(layers::CompositorBridgeParentBase* aBridge,
-                                               RefPtr<widget::CompositorWidget>&& aWidget,
-                                               LayoutDeviceIntSize aSize);
-
-  already_AddRefed<WebRenderAPI> Clone();
-
-  wr::WindowId GetId() const { return mId; }
-
-  void UpdateScrollPosition(const wr::WrPipelineId& aPipelineId,
-                            const layers::FrameMetrics::ViewID& aScrollId,
-                            const wr::LayoutPoint& aScrollPosition);
+  ResourceUpdateQueue();
 
-  void GenerateFrame();
-  void GenerateFrame(const nsTArray<wr::WrOpacityProperty>& aOpacityArray,
-                     const nsTArray<wr::WrTransformProperty>& aTransformArray);
-
-  void SetWindowParameters(LayoutDeviceIntSize size);
-  void SetRootDisplayList(gfx::Color aBgColor,
-                          Epoch aEpoch,
-                          mozilla::LayerSize aViewportSize,
-                          wr::WrPipelineId pipeline_id,
-                          const wr::LayoutSize& content_size,
-                          wr::BuiltDisplayListDescriptor dl_descriptor,
-                          uint8_t *dl_data,
-                          size_t dl_size);
-
-  void ClearRootDisplayList(Epoch aEpoch,
-                            wr::WrPipelineId pipeline_id);
-
-  void SetRootPipeline(wr::PipelineId aPipeline);
+  ~ResourceUpdateQueue();
 
   void AddImage(wr::ImageKey aKey,
                 const ImageDescriptor& aDescriptor,
                 Range<uint8_t> aBytes);
 
   void AddBlobImage(wr::ImageKey aKey,
                     const ImageDescriptor& aDescriptor,
                     Range<uint8_t> aBytes);
@@ -126,19 +97,68 @@ public:
   void AddFontInstance(wr::FontInstanceKey aKey,
                        wr::FontKey aFontKey,
                        float aGlyphSize,
                        const wr::FontInstanceOptions* aOptions,
                        const wr::FontInstancePlatformOptions* aPlatformOptions);
 
   void DeleteFontInstance(wr::FontInstanceKey aKey);
 
+  // Try to avoid using this when possible.
+  wr::ResourceUpdates* Raw() { return mUpdates; }
+
+protected:
+  wr::ResourceUpdates* mUpdates;
+};
+
+class WebRenderAPI
+{
+  NS_INLINE_DECL_REFCOUNTING(WebRenderAPI);
+
+public:
+  /// This can be called on the compositor thread only.
+  static already_AddRefed<WebRenderAPI> Create(layers::CompositorBridgeParentBase* aBridge,
+                                               RefPtr<widget::CompositorWidget>&& aWidget,
+                                               LayoutDeviceIntSize aSize);
+
+  already_AddRefed<WebRenderAPI> Clone();
+
+  wr::WindowId GetId() const { return mId; }
+
+  void UpdateScrollPosition(const wr::WrPipelineId& aPipelineId,
+                            const layers::FrameMetrics::ViewID& aScrollId,
+                            const wr::LayoutPoint& aScrollPosition);
+
+  void GenerateFrame();
+  void GenerateFrame(const nsTArray<wr::WrOpacityProperty>& aOpacityArray,
+                     const nsTArray<wr::WrTransformProperty>& aTransformArray);
+
+  void SetWindowParameters(LayoutDeviceIntSize size);
+
+  void SetDisplayList(gfx::Color aBgColor,
+                      Epoch aEpoch,
+                      mozilla::LayerSize aViewportSize,
+                      wr::WrPipelineId pipeline_id,
+                      const wr::LayoutSize& content_size,
+                      wr::BuiltDisplayListDescriptor dl_descriptor,
+                      uint8_t *dl_data,
+                      size_t dl_size);
+
+  void ClearDisplayList(Epoch aEpoch, wr::WrPipelineId pipeline_id);
+
+  void SetRootPipeline(wr::PipelineId aPipeline);
+
+  void UpdateResources(ResourceUpdateQueue& aUpdates);
+
+  ResourceUpdateQueue& Resources() { return mResources; }
+
   void SetFrameStartTime(const TimeStamp& aTime);
 
   void RunOnRenderThread(UniquePtr<RendererEvent> aEvent);
+
   void Readback(gfx::IntSize aSize, uint8_t *aBuffer, uint32_t aBufferSize);
 
   void Pause();
   bool Resume();
 
   wr::WrIdNamespace GetNamespace();
   uint32_t GetMaxTextureSize() const { return mMaxTextureSize; }
   bool GetUseANGLE() const { return mUseANGLE; }
@@ -152,16 +172,17 @@ protected:
     , mUseANGLE(aUseANGLE)
     , mSyncHandle(aSyncHandle)
   {}
 
   ~WebRenderAPI();
   // Should be used only for shutdown handling
   void WaitFlushed();
 
+  ResourceUpdateQueue mResources;
   wr::DocumentHandle* mDocHandle;
   wr::WindowId mId;
   uint32_t mMaxTextureSize;
   bool mUseANGLE;
   layers::SyncHandle mSyncHandle;
   RefPtr<wr::WebRenderAPI> mRootApi;
 
   friend class DisplayListBuilder;
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -644,126 +644,135 @@ pub unsafe extern "C" fn wr_api_delete(d
     let handle = Box::from_raw(dh);
     if handle.document_id.0 == handle.api.get_namespace_id() {
         handle.api.delete_document(handle.document_id);
         handle.api.shut_down();
     }
 }
 
 #[no_mangle]
-pub extern "C" fn wr_api_add_image(dh: &mut DocumentHandle,
-                                   image_key: WrImageKey,
-                                   descriptor: &WrImageDescriptor,
-                                   bytes: ByteSlice) {
-    assert!(unsafe { is_in_compositor_thread() });
+pub extern "C" fn wr_resource_updates_add_image(
+    resources: &mut ResourceUpdates,
+    image_key: WrImageKey,
+    descriptor: &WrImageDescriptor,
+    bytes: ByteSlice
+) {
     let copied_bytes = bytes.as_slice().to_owned();
-    let mut resources = ResourceUpdates::new();
-    resources.add_image(image_key,
-                        descriptor.into(),
-                        ImageData::new(copied_bytes),
-                        None);
-    dh.api.update_resources(resources);
+    resources.add_image(
+        image_key,
+        descriptor.into(),
+        ImageData::new(copied_bytes),
+        None
+    );
 }
 
 #[no_mangle]
-pub extern "C" fn wr_api_add_blob_image(dh: &mut DocumentHandle,
-                                        image_key: WrImageKey,
-                                        descriptor: &WrImageDescriptor,
-                                        bytes: ByteSlice) {
-    assert!(unsafe { is_in_compositor_thread() });
+pub extern "C" fn wr_resource_updates_add_blob_image(
+    resources: &mut ResourceUpdates,
+    image_key: WrImageKey,
+    descriptor: &WrImageDescriptor,
+    bytes: ByteSlice
+) {
     let copied_bytes = bytes.as_slice().to_owned();
-    let mut resources = ResourceUpdates::new();
-    resources.add_image(image_key,
-                        descriptor.into(),
-                        ImageData::new_blob_image(copied_bytes),
-                        None);
-    dh.api.update_resources(resources);
+    resources.add_image(
+        image_key,
+        descriptor.into(),
+        ImageData::new_blob_image(copied_bytes),
+        None
+    );
 }
 
 #[no_mangle]
-pub extern "C" fn wr_api_add_external_image(dh: &mut DocumentHandle,
-                                            image_key: WrImageKey,
-                                            descriptor: &WrImageDescriptor,
-                                            external_image_id: WrExternalImageId,
-                                            buffer_type: WrExternalImageBufferType,
-                                            channel_index: u8) {
-    assert!(unsafe { is_in_compositor_thread() });
-    let mut resources = ResourceUpdates::new();
-    resources.add_image(image_key,
-                        descriptor.into(),
-                        ImageData::External(ExternalImageData {
-                                             id: external_image_id.into(),
-                                             channel_index: channel_index,
-                                             image_type: buffer_type,
-                                         }),
-                        None);
-    dh.api.update_resources(resources);
+pub extern "C" fn wr_resource_updates_add_external_image(
+    resources: &mut ResourceUpdates,
+    image_key: WrImageKey,
+    descriptor: &WrImageDescriptor,
+    external_image_id: WrExternalImageId,
+    buffer_type: WrExternalImageBufferType,
+    channel_index: u8
+) {
+    resources.add_image(
+        image_key,
+        descriptor.into(),
+        ImageData::External(
+            ExternalImageData {
+                id: external_image_id.into(),
+                channel_index: channel_index,
+                image_type: buffer_type,
+            }
+        ),
+        None
+    );
 }
 
 #[no_mangle]
-pub extern "C" fn wr_api_update_image(dh: &mut DocumentHandle,
-                                      key: WrImageKey,
-                                      descriptor: &WrImageDescriptor,
-                                      bytes: ByteSlice) {
-    assert!(unsafe { is_in_compositor_thread() });
+pub extern "C" fn wr_resource_updates_update_image(
+    resources: &mut ResourceUpdates,
+    key: WrImageKey,
+    descriptor: &WrImageDescriptor,
+    bytes: ByteSlice
+) {
     let copied_bytes = bytes.as_slice().to_owned();
-
-    let mut resources = ResourceUpdates::new();
     resources.update_image(key, descriptor.into(), ImageData::new(copied_bytes), None);
-    dh.api.update_resources(resources);
 }
 
 #[no_mangle]
-pub extern "C" fn wr_api_update_external_image(
-    dh: &mut DocumentHandle,
+pub extern "C" fn wr_resource_updates_update_external_image(
+    resources: &mut ResourceUpdates,
     key: WrImageKey,
     descriptor: &WrImageDescriptor,
     external_image_id: WrExternalImageId,
     image_type: WrExternalImageBufferType,
     channel_index: u8
 ) {
-    assert!(unsafe { is_in_compositor_thread() });
-
-    let data = ImageData::External(
-        ExternalImageData {
-            id: external_image_id.into(),
-            channel_index,
-            image_type,
-        }
+    resources.update_image(
+        key,
+        descriptor.into(),
+        ImageData::External(
+            ExternalImageData {
+                id: external_image_id.into(),
+                channel_index,
+                image_type,
+            }
+        ),
+        None
     );
-
-    let mut resources = ResourceUpdates::new();
-    resources.update_image(key, descriptor.into(), data, None);
-    dh.api.update_resources(resources);
 }
 
 #[no_mangle]
-pub extern "C" fn wr_api_update_blob_image(dh: &mut DocumentHandle,
-                                           image_key: WrImageKey,
-                                           descriptor: &WrImageDescriptor,
-                                           bytes: ByteSlice) {
-    assert!(unsafe { is_in_compositor_thread() });
+pub extern "C" fn wr_resource_updates_update_blob_image(
+    resources: &mut ResourceUpdates,
+    image_key: WrImageKey,
+    descriptor: &WrImageDescriptor,
+    bytes: ByteSlice
+) {
     let copied_bytes = bytes.as_slice().to_owned();
-    let mut resources = ResourceUpdates::new();
     resources.update_image(
         image_key,
         descriptor.into(),
         ImageData::new_blob_image(copied_bytes),
         None
     );
-    dh.api.update_resources(resources);
 }
 
 #[no_mangle]
-pub extern "C" fn wr_api_delete_image(dh: &mut DocumentHandle,
-                                      key: WrImageKey) {
-    assert!(unsafe { is_in_compositor_thread() });
-    let mut resources = ResourceUpdates::new();
+pub extern "C" fn wr_resource_updates_delete_image(
+    resources: &mut ResourceUpdates,
+    key: WrImageKey
+) {
     resources.delete_image(key);
-    dh.api.update_resources(resources);
+}
+
+#[no_mangle]
+pub extern "C" fn wr_api_update_resources(
+    dh: &mut DocumentHandle,
+    resources: &mut ResourceUpdates
+) {
+    let resource_updates = mem::replace(resources, ResourceUpdates::new());
+    dh.api.update_resources(resource_updates);
 }
 
 #[no_mangle]
 pub extern "C" fn wr_api_set_root_pipeline(dh: &mut DocumentHandle,
                                            pipeline_id: WrPipelineId) {
     dh.api.set_root_pipeline(dh.document_id, pipeline_id);
 }
 
@@ -773,65 +782,75 @@ pub extern "C" fn wr_api_set_window_para
                                                height: i32) {
     let size = DeviceUintSize::new(width as u32, height as u32);
     dh.api.set_window_parameters(dh.document_id,
                                  size,
                                  DeviceUintRect::new(DeviceUintPoint::new(0, 0), size));
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn wr_api_set_root_display_list(dh: &mut DocumentHandle,
-                                                      color: ColorF,
-                                                      epoch: WrEpoch,
-                                                      viewport_width: f32,
-                                                      viewport_height: f32,
-                                                      pipeline_id: WrPipelineId,
-                                                      content_size: LayoutSize,
-                                                      dl_descriptor: BuiltDisplayListDescriptor,
-                                                      dl_data: *mut u8,
-                                                      dl_size: usize) {
-    let color = if color.a == 0.0 {
-        None
-    } else {
-        Some(color)
-    };
+pub unsafe extern "C" fn wr_api_set_display_list(
+    dh: &mut DocumentHandle,
+    color: ColorF,
+    epoch: WrEpoch,
+    viewport_width: f32,
+    viewport_height: f32,
+    pipeline_id: WrPipelineId,
+    content_size: LayoutSize,
+    dl_descriptor: BuiltDisplayListDescriptor,
+    dl_data: *mut u8,
+    dl_size: usize,
+    resources: &mut ResourceUpdates,
+) {
+    let resource_updates = mem::replace(resources, ResourceUpdates::new());
+
+    let color = if color.a == 0.0 { None } else { Some(color) };
+
     // See the documentation of set_display_list in api.rs. I don't think
     // it makes a difference in gecko at the moment(until APZ is figured out)
     // but I suppose it is a good default.
     let preserve_frame_state = true;
 
     let dl_slice = make_slice(dl_data, dl_size);
     let mut dl_vec = Vec::new();
     // XXX: see if we can get rid of the copy here
     dl_vec.extend_from_slice(dl_slice);
     let dl = BuiltDisplayList::from_data(dl_vec, dl_descriptor);
 
-    dh.api.set_display_list(dh.document_id,
-                            epoch,
-                            color,
-                            LayoutSize::new(viewport_width, viewport_height),
-                            (pipeline_id, content_size, dl),
-                            preserve_frame_state,
-                            ResourceUpdates::new());
+    dh.api.set_display_list(
+        dh.document_id,
+        epoch,
+        color,
+        LayoutSize::new(viewport_width, viewport_height),
+        (pipeline_id, content_size, dl),
+        preserve_frame_state,
+        resource_updates
+    );
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn wr_api_clear_root_display_list(dh: &mut DocumentHandle,
-                                                        epoch: WrEpoch,
-                                                        pipeline_id: WrPipelineId) {
+pub unsafe extern "C" fn wr_api_clear_display_list(
+    dh: &mut DocumentHandle,
+    epoch: WrEpoch,
+    pipeline_id: WrPipelineId,
+    resources: &mut ResourceUpdates
+) {
     let preserve_frame_state = true;
     let frame_builder = WebRenderFrameBuilder::new(pipeline_id, LayoutSize::zero());
+    let resource_updates = mem::replace(resources, ResourceUpdates::new());
 
-    dh.api.set_display_list(dh.document_id,
-                            epoch,
-                            None,
-                            LayoutSize::new(0.0, 0.0),
-                            frame_builder.dl_builder.finalize(),
-                            preserve_frame_state,
-                            ResourceUpdates::new());
+    dh.api.set_display_list(
+        dh.document_id,
+        epoch,
+        None,
+        LayoutSize::new(0.0, 0.0),
+        frame_builder.dl_builder.finalize(),
+        preserve_frame_state,
+        resource_updates
+    );
 }
 
 #[no_mangle]
 pub extern "C" fn wr_api_generate_frame(dh: &mut DocumentHandle) {
     dh.api.generate_frame(dh.document_id, None);
 }
 
 #[no_mangle]
@@ -878,65 +897,76 @@ pub extern "C" fn wr_api_generate_frame_
 pub extern "C" fn wr_api_send_external_event(dh: &mut DocumentHandle,
                                              evt: usize) {
     assert!(unsafe { !is_in_render_thread() });
 
     dh.api.send_external_event(ExternalEvent::from_raw(evt));
 }
 
 #[no_mangle]
-pub extern "C" fn wr_api_add_raw_font(dh: &mut DocumentHandle,
-                                      key: WrFontKey,
-                                      font_buffer: *mut u8,
-                                      buffer_size: usize,
-                                      index: u32) {
-    assert!(unsafe { is_in_compositor_thread() });
-
+pub extern "C" fn wr_resource_updates_add_raw_font(
+    resources: &mut ResourceUpdates,
+    key: WrFontKey,
+    font_buffer: *mut u8,
+    buffer_size: usize,
+    index: u32
+) {
     let font_slice = make_slice(font_buffer, buffer_size);
     let mut font_vector = Vec::new();
     font_vector.extend_from_slice(font_slice);
 
-    let mut resources = ResourceUpdates::new();
     resources.add_raw_font(key, font_vector, index);
-    dh.api.update_resources(resources);
 }
 
 #[no_mangle]
-pub extern "C" fn wr_api_delete_font(dh: &mut DocumentHandle,
-                                     key: WrFontKey) {
-    assert!(unsafe { is_in_compositor_thread() });
-    let mut resources = ResourceUpdates::new();
+pub extern "C" fn wr_resource_updates_delete_font(
+    resources: &mut ResourceUpdates,
+    key: WrFontKey
+) {
     resources.delete_font(key);
-    dh.api.update_resources(resources);
 }
 
 #[no_mangle]
-pub extern "C" fn wr_api_add_font_instance(dh: &mut DocumentHandle,
-                                           key: WrFontInstanceKey,
-                                           font_key: WrFontKey,
-                                           glyph_size: f32,
-                                           options: *const FontInstanceOptions,
-                                           platform_options: *const FontInstancePlatformOptions) {
-    assert!(unsafe { is_in_compositor_thread() });
-    let mut resources = ResourceUpdates::new();
-    resources.add_font_instance(key,
-                                font_key,
-                                Au::from_f32_px(glyph_size),
-                                unsafe { options.as_ref().cloned() },
-                                unsafe { platform_options.as_ref().cloned() });
-    dh.api.update_resources(resources);
+pub extern "C" fn wr_resource_updates_add_font_instance(
+    resources: &mut ResourceUpdates,
+    key: WrFontInstanceKey,
+    font_key: WrFontKey,
+    glyph_size: f32,
+    options: *const FontInstanceOptions,
+    platform_options: *const FontInstancePlatformOptions
+) {
+    resources.add_font_instance(
+        key,
+        font_key,
+        Au::from_f32_px(glyph_size),
+        unsafe { options.as_ref().cloned() },
+        unsafe { platform_options.as_ref().cloned() }
+    );
 }
 
 #[no_mangle]
-pub extern "C" fn wr_api_delete_font_instance(dh: &mut DocumentHandle,
-                                              key: WrFontInstanceKey) {
-    assert!(unsafe { is_in_compositor_thread() });
-    let mut resources = ResourceUpdates::new();
+pub extern "C" fn wr_resource_updates_delete_font_instance(
+    resources: &mut ResourceUpdates,
+    key: WrFontInstanceKey
+) {
     resources.delete_font_instance(key);
-    dh.api.update_resources(resources);
+}
+
+#[no_mangle]
+pub extern "C" fn wr_resource_updates_new() -> *mut ResourceUpdates {
+    let updates = Box::new(ResourceUpdates::new());
+    Box::into_raw(updates)
+}
+
+/// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
+#[no_mangle]
+pub extern "C" fn wr_resource_updates_delete(updates: *mut ResourceUpdates) {
+    unsafe {
+        Box::from_raw(updates);
+    }
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn wr_api_get_namespace(dh: &mut DocumentHandle) -> WrIdNamespace {
     dh.api.get_namespace_id()
 }
 
 // RenderThread WIP notes:
--- a/gfx/webrender_bindings/webrender_ffi_generated.h
+++ b/gfx/webrender_bindings/webrender_ffi_generated.h
@@ -170,135 +170,31 @@ enum class YuvColorSpace : uint32_t {
 struct Arc_VecU8;
 
 struct DocumentHandle;
 
 // The renderer is responsible for submitting to the GPU the work prepared by the
 // RenderBackend.
 struct Renderer;
 
+// The resource updates for a given transaction (they must be applied in the same frame).
+struct ResourceUpdates;
+
 struct Vec_u8;
 
 struct WrRenderedEpochs;
 
 struct WrState;
 
 struct WrThreadPool;
 
 typedef Vec_u8 VecU8;
 
 typedef Arc_VecU8 ArcVecU8;
 
-struct IdNamespace {
-  uint32_t mHandle;
-
-  bool operator==(const IdNamespace& aOther) const {
-    return mHandle == aOther.mHandle;
-  }
-  bool operator!=(const IdNamespace& aOther) const {
-    return mHandle != aOther.mHandle;
-  }
-  bool operator<(const IdNamespace& aOther) const {
-    return mHandle < aOther.mHandle;
-  }
-  bool operator<=(const IdNamespace& aOther) const {
-    return mHandle <= aOther.mHandle;
-  }
-};
-
-struct ImageKey {
-  IdNamespace mNamespace;
-  uint32_t mHandle;
-
-  bool operator==(const ImageKey& aOther) const {
-    return mNamespace == aOther.mNamespace &&
-           mHandle == aOther.mHandle;
-  }
-};
-
-typedef ImageKey WrImageKey;
-
-struct WrImageDescriptor {
-  ImageFormat format;
-  uint32_t width;
-  uint32_t height;
-  uint32_t stride;
-  bool is_opaque;
-
-  bool operator==(const WrImageDescriptor& aOther) const {
-    return format == aOther.format &&
-           width == aOther.width &&
-           height == aOther.height &&
-           stride == aOther.stride &&
-           is_opaque == aOther.is_opaque;
-  }
-};
-
-struct ByteSlice {
-  const uint8_t *buffer;
-  size_t len;
-
-  bool operator==(const ByteSlice& aOther) const {
-    return buffer == aOther.buffer &&
-           len == aOther.len;
-  }
-};
-
-struct WrExternalImageId {
-  uint64_t mHandle;
-
-  bool operator==(const WrExternalImageId& aOther) const {
-    return mHandle == aOther.mHandle;
-  }
-};
-
-typedef ExternalImageType WrExternalImageBufferType;
-
-struct FontInstanceKey {
-  IdNamespace mNamespace;
-  uint32_t mHandle;
-
-  bool operator==(const FontInstanceKey& aOther) const {
-    return mNamespace == aOther.mNamespace &&
-           mHandle == aOther.mHandle;
-  }
-};
-
-typedef FontInstanceKey WrFontInstanceKey;
-
-struct FontKey {
-  IdNamespace mNamespace;
-  uint32_t mHandle;
-
-  bool operator==(const FontKey& aOther) const {
-    return mNamespace == aOther.mNamespace &&
-           mHandle == aOther.mHandle;
-  }
-};
-
-typedef FontKey WrFontKey;
-
-struct FontInstanceOptions {
-  FontRenderMode render_mode;
-
-  bool operator==(const FontInstanceOptions& aOther) const {
-    return render_mode == aOther.render_mode;
-  }
-};
-
-struct FontInstancePlatformOptions {
-  bool use_embedded_bitmap;
-  bool force_gdi_rendering;
-
-  bool operator==(const FontInstancePlatformOptions& aOther) const {
-    return use_embedded_bitmap == aOther.use_embedded_bitmap &&
-           force_gdi_rendering == aOther.force_gdi_rendering;
-  }
-};
-
 struct Epoch {
   uint32_t mHandle;
 
   bool operator==(const Epoch& aOther) const {
     return mHandle == aOther.mHandle;
   }
   bool operator<(const Epoch& aOther) const {
     return mHandle < aOther.mHandle;
@@ -428,16 +324,33 @@ struct TypedTransform3D_f32__LayoutPixel
 
 typedef TypedTransform3D_f32__LayoutPixel__LayoutPixel LayoutTransform;
 
 struct WrTransformProperty {
   uint64_t id;
   LayoutTransform transform;
 };
 
+struct IdNamespace {
+  uint32_t mHandle;
+
+  bool operator==(const IdNamespace& aOther) const {
+    return mHandle == aOther.mHandle;
+  }
+  bool operator!=(const IdNamespace& aOther) const {
+    return mHandle != aOther.mHandle;
+  }
+  bool operator<(const IdNamespace& aOther) const {
+    return mHandle < aOther.mHandle;
+  }
+  bool operator<=(const IdNamespace& aOther) const {
+    return mHandle <= aOther.mHandle;
+  }
+};
+
 typedef IdNamespace WrIdNamespace;
 
 // Represents RGBA screen colors with floating point numbers.
 // 
 // All components must be between 0.0 and 1.0.
 // An alpha value of 1.0 is opaque while 0.0 is fully transparent.
 struct ColorF {
   float r;
@@ -497,16 +410,28 @@ struct WrComplexClipRegion {
   BorderRadius radii;
 
   bool operator==(const WrComplexClipRegion& aOther) const {
     return rect == aOther.rect &&
            radii == aOther.radii;
   }
 };
 
+struct ImageKey {
+  IdNamespace mNamespace;
+  uint32_t mHandle;
+
+  bool operator==(const ImageKey& aOther) const {
+    return mNamespace == aOther.mNamespace &&
+           mHandle == aOther.mHandle;
+  }
+};
+
+typedef ImageKey WrImageKey;
+
 struct WrImageMask {
   WrImageKey image;
   LayoutRect rect;
   bool repeat;
 
   bool operator==(const WrImageMask& aOther) const {
     return image == aOther.image &&
            rect == aOther.rect &&
@@ -613,16 +538,28 @@ struct WrFilterOp {
   float argument;
 
   bool operator==(const WrFilterOp& aOther) const {
     return filter_type == aOther.filter_type &&
            argument == aOther.argument;
   }
 };
 
+struct FontInstanceKey {
+  IdNamespace mNamespace;
+  uint32_t mHandle;
+
+  bool operator==(const FontInstanceKey& aOther) const {
+    return mNamespace == aOther.mNamespace &&
+           mHandle == aOther.mHandle;
+  }
+};
+
+typedef FontInstanceKey WrFontInstanceKey;
+
 typedef uint32_t GlyphIndex;
 
 struct GlyphInstance {
   GlyphIndex index;
   LayoutPoint point;
 
   bool operator==(const GlyphInstance& aOther) const {
     return index == aOther.index &&
@@ -647,16 +584,26 @@ struct TextShadow {
     return offset == aOther.offset &&
            color == aOther.color &&
            blur_radius == aOther.blur_radius;
   }
 };
 
 typedef YuvColorSpace WrYuvColorSpace;
 
+struct ByteSlice {
+  const uint8_t *buffer;
+  size_t len;
+
+  bool operator==(const ByteSlice& aOther) const {
+    return buffer == aOther.buffer &&
+           len == aOther.len;
+  }
+};
+
 struct TypedPoint2D_u16__Tiles {
   uint16_t x;
   uint16_t y;
 
   bool operator==(const TypedPoint2D_u16__Tiles& aOther) const {
     return x == aOther.x &&
            y == aOther.y;
   }
@@ -713,32 +660,88 @@ struct WrExternalImage {
            v0 == aOther.v0 &&
            u1 == aOther.u1 &&
            v1 == aOther.v1 &&
            buff == aOther.buff &&
            size == aOther.size;
   }
 };
 
+struct WrExternalImageId {
+  uint64_t mHandle;
+
+  bool operator==(const WrExternalImageId& aOther) const {
+    return mHandle == aOther.mHandle;
+  }
+};
+
 typedef WrExternalImage (*LockExternalImageCallback)(void*, WrExternalImageId, uint8_t);
 
 typedef void (*UnlockExternalImageCallback)(void*, WrExternalImageId, uint8_t);
 
 struct WrExternalImageHandler {
   void *external_image_obj;
   LockExternalImageCallback lock_func;
   UnlockExternalImageCallback unlock_func;
 
   bool operator==(const WrExternalImageHandler& aOther) const {
     return external_image_obj == aOther.external_image_obj &&
            lock_func == aOther.lock_func &&
            unlock_func == aOther.unlock_func;
   }
 };
 
+struct WrImageDescriptor {
+  ImageFormat format;
+  uint32_t width;
+  uint32_t height;
+  uint32_t stride;
+  bool is_opaque;
+
+  bool operator==(const WrImageDescriptor& aOther) const {
+    return format == aOther.format &&
+           width == aOther.width &&
+           height == aOther.height &&
+           stride == aOther.stride &&
+           is_opaque == aOther.is_opaque;
+  }
+};
+
+typedef ExternalImageType WrExternalImageBufferType;
+
+struct FontKey {
+  IdNamespace mNamespace;
+  uint32_t mHandle;
+
+  bool operator==(const FontKey& aOther) const {
+    return mNamespace == aOther.mNamespace &&
+           mHandle == aOther.mHandle;
+  }
+};
+
+typedef FontKey WrFontKey;
+
+struct FontInstanceOptions {
+  FontRenderMode render_mode;
+
+  bool operator==(const FontInstanceOptions& aOther) const {
+    return render_mode == aOther.render_mode;
+  }
+};
+
+struct FontInstancePlatformOptions {
+  bool use_embedded_bitmap;
+  bool force_gdi_rendering;
+
+  bool operator==(const FontInstancePlatformOptions& aOther) const {
+    return use_embedded_bitmap == aOther.use_embedded_bitmap &&
+           force_gdi_rendering == aOther.force_gdi_rendering;
+  }
+};
+
 /* DO NOT MODIFY THIS MANUALLY! This file was generated using cbindgen.
  * To generate this file:
  *   1. Get the latest cbindgen using `cargo install --force cbindgen`
  *      a. Alternatively, you can clone `https://github.com/rlhunt/cbindgen` and use a tagged release
  *   2. Run `rustup run nightly cbindgen toolkit/library/rust/ --crate webrender_bindings -o gfx/webrender_bindings/webrender_ffi_generated.h`
  */
 
 extern void gfx_critical_note(const char *aMsg);
@@ -753,86 +756,32 @@ extern bool is_in_main_thread();
 
 extern bool is_in_render_thread();
 
 WR_INLINE
 const VecU8 *wr_add_ref_arc(const ArcVecU8 *aArc)
 WR_FUNC;
 
 WR_INLINE
-void wr_api_add_blob_image(DocumentHandle *aDh,
-                           WrImageKey aImageKey,
-                           const WrImageDescriptor *aDescriptor,
-                           ByteSlice aBytes)
-WR_FUNC;
-
-WR_INLINE
-void wr_api_add_external_image(DocumentHandle *aDh,
-                               WrImageKey aImageKey,
-                               const WrImageDescriptor *aDescriptor,
-                               WrExternalImageId aExternalImageId,
-                               WrExternalImageBufferType aBufferType,
-                               uint8_t aChannelIndex)
-WR_FUNC;
-
-WR_INLINE
-void wr_api_add_font_instance(DocumentHandle *aDh,
-                              WrFontInstanceKey aKey,
-                              WrFontKey aFontKey,
-                              float aGlyphSize,
-                              const FontInstanceOptions *aOptions,
-                              const FontInstancePlatformOptions *aPlatformOptions)
-WR_FUNC;
-
-WR_INLINE
-void wr_api_add_image(DocumentHandle *aDh,
-                      WrImageKey aImageKey,
-                      const WrImageDescriptor *aDescriptor,
-                      ByteSlice aBytes)
-WR_FUNC;
-
-WR_INLINE
-void wr_api_add_raw_font(DocumentHandle *aDh,
-                         WrFontKey aKey,
-                         uint8_t *aFontBuffer,
-                         size_t aBufferSize,
-                         uint32_t aIndex)
-WR_FUNC;
-
-WR_INLINE
-void wr_api_clear_root_display_list(DocumentHandle *aDh,
-                                    WrEpoch aEpoch,
-                                    WrPipelineId aPipelineId)
+void wr_api_clear_display_list(DocumentHandle *aDh,
+                               WrEpoch aEpoch,
+                               WrPipelineId aPipelineId,
+                               ResourceUpdates *aResources)
 WR_FUNC;
 
 WR_INLINE
 void wr_api_clone(DocumentHandle *aDh,
                   DocumentHandle **aOutHandle)
 WR_FUNC;
 
 WR_INLINE
 void wr_api_delete(DocumentHandle *aDh)
 WR_DESTRUCTOR_SAFE_FUNC;
 
 WR_INLINE
-void wr_api_delete_font(DocumentHandle *aDh,
-                        WrFontKey aKey)
-WR_FUNC;
-
-WR_INLINE
-void wr_api_delete_font_instance(DocumentHandle *aDh,
-                                 WrFontInstanceKey aKey)
-WR_FUNC;
-
-WR_INLINE
-void wr_api_delete_image(DocumentHandle *aDh,
-                         WrImageKey aKey)
-WR_FUNC;
-
-WR_INLINE
 void wr_api_finalize_builder(WrState *aState,
                              LayoutSize *aContentSize,
                              BuiltDisplayListDescriptor *aDlDescriptor,
                              WrVecU8 *aDlData)
 WR_FUNC;
 
 WR_INLINE
 void wr_api_generate_frame(DocumentHandle *aDh)
@@ -851,60 +800,43 @@ WrIdNamespace wr_api_get_namespace(Docum
 WR_FUNC;
 
 WR_INLINE
 void wr_api_send_external_event(DocumentHandle *aDh,
                                 size_t aEvt)
 WR_DESTRUCTOR_SAFE_FUNC;
 
 WR_INLINE
-void wr_api_set_root_display_list(DocumentHandle *aDh,
-                                  ColorF aColor,
-                                  WrEpoch aEpoch,
-                                  float aViewportWidth,
-                                  float aViewportHeight,
-                                  WrPipelineId aPipelineId,
-                                  LayoutSize aContentSize,
-                                  BuiltDisplayListDescriptor aDlDescriptor,
-                                  uint8_t *aDlData,
-                                  size_t aDlSize)
+void wr_api_set_display_list(DocumentHandle *aDh,
+                             ColorF aColor,
+                             WrEpoch aEpoch,
+                             float aViewportWidth,
+                             float aViewportHeight,
+                             WrPipelineId aPipelineId,
+                             LayoutSize aContentSize,
+                             BuiltDisplayListDescriptor aDlDescriptor,
+                             uint8_t *aDlData,
+                             size_t aDlSize,
+                             ResourceUpdates *aResources)
 WR_FUNC;
 
 WR_INLINE
 void wr_api_set_root_pipeline(DocumentHandle *aDh,
                               WrPipelineId aPipelineId)
 WR_FUNC;
 
 WR_INLINE
 void wr_api_set_window_parameters(DocumentHandle *aDh,
                                   int32_t aWidth,
                                   int32_t aHeight)
 WR_FUNC;
 
 WR_INLINE
-void wr_api_update_blob_image(DocumentHandle *aDh,
-                              WrImageKey aImageKey,
-                              const WrImageDescriptor *aDescriptor,
-                              ByteSlice aBytes)
-WR_FUNC;
-
-WR_INLINE
-void wr_api_update_external_image(DocumentHandle *aDh,
-                                  WrImageKey aKey,
-                                  const WrImageDescriptor *aDescriptor,
-                                  WrExternalImageId aExternalImageId,
-                                  WrExternalImageBufferType aImageType,
-                                  uint8_t aChannelIndex)
-WR_FUNC;
-
-WR_INLINE
-void wr_api_update_image(DocumentHandle *aDh,
-                         WrImageKey aKey,
-                         const WrImageDescriptor *aDescriptor,
-                         ByteSlice aBytes)
+void wr_api_update_resources(DocumentHandle *aDh,
+                             ResourceUpdates *aResources)
 WR_FUNC;
 
 WR_INLINE
 void wr_dec_ref_arc(const VecU8 *aArc)
 WR_FUNC;
 
 WR_INLINE
 void wr_dp_begin(WrState *aState,
@@ -1229,16 +1161,102 @@ void wr_renderer_set_external_image_hand
                                             WrExternalImageHandler *aExternalImageHandler)
 WR_FUNC;
 
 WR_INLINE
 void wr_renderer_update(Renderer *aRenderer)
 WR_FUNC;
 
 WR_INLINE
+void wr_resource_updates_add_blob_image(ResourceUpdates *aResources,
+                                        WrImageKey aImageKey,
+                                        const WrImageDescriptor *aDescriptor,
+                                        ByteSlice aBytes)
+WR_FUNC;
+
+WR_INLINE
+void wr_resource_updates_add_external_image(ResourceUpdates *aResources,
+                                            WrImageKey aImageKey,
+                                            const WrImageDescriptor *aDescriptor,
+                                            WrExternalImageId aExternalImageId,
+                                            WrExternalImageBufferType aBufferType,
+                                            uint8_t aChannelIndex)
+WR_FUNC;
+
+WR_INLINE
+void wr_resource_updates_add_font_instance(ResourceUpdates *aResources,
+                                           WrFontInstanceKey aKey,
+                                           WrFontKey aFontKey,
+                                           float aGlyphSize,
+                                           const FontInstanceOptions *aOptions,
+                                           const FontInstancePlatformOptions *aPlatformOptions)
+WR_FUNC;
+
+WR_INLINE
+void wr_resource_updates_add_image(ResourceUpdates *aResources,
+                                   WrImageKey aImageKey,
+                                   const WrImageDescriptor *aDescriptor,
+                                   ByteSlice aBytes)
+WR_FUNC;
+
+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_delete(ResourceUpdates *aUpdates)
+WR_DESTRUCTOR_SAFE_FUNC;
+
+WR_INLINE
+void wr_resource_updates_delete_font(ResourceUpdates *aResources,
+                                     WrFontKey aKey)
+WR_FUNC;
+
+WR_INLINE
+void wr_resource_updates_delete_font_instance(ResourceUpdates *aResources,
+                                              WrFontInstanceKey aKey)
+WR_FUNC;
+
+WR_INLINE
+void wr_resource_updates_delete_image(ResourceUpdates *aResources,
+                                      WrImageKey aKey)
+WR_FUNC;
+
+WR_INLINE
+ResourceUpdates *wr_resource_updates_new()
+WR_FUNC;
+
+WR_INLINE
+void wr_resource_updates_update_blob_image(ResourceUpdates *aResources,
+                                           WrImageKey aImageKey,
+                                           const WrImageDescriptor *aDescriptor,
+                                           ByteSlice aBytes)
+WR_FUNC;
+
+WR_INLINE
+void wr_resource_updates_update_external_image(ResourceUpdates *aResources,
+                                               WrImageKey aKey,
+                                               const WrImageDescriptor *aDescriptor,
+                                               WrExternalImageId aExternalImageId,
+                                               WrExternalImageBufferType aImageType,
+                                               uint8_t aChannelIndex)
+WR_FUNC;
+
+WR_INLINE
+void wr_resource_updates_update_image(ResourceUpdates *aResources,
+                                      WrImageKey aKey,
+                                      const WrImageDescriptor *aDescriptor,
+                                      ByteSlice aBytes)
+WR_FUNC;
+
+WR_INLINE
 void wr_scroll_layer_with_id(DocumentHandle *aDh,
                              WrPipelineId aPipelineId,
                              uint64_t aScrollId,
                              LayoutPoint aNewScrollOrigin)
 WR_FUNC;
 
 WR_INLINE
 void wr_state_delete(WrState *aState)