Bug 1400532 - Separate small and large shmem allocations in IpcResourceUpdateQueue. r=jrmuizel
authorNicolas Silva <nsilva@mozilla.com>
Wed, 20 Sep 2017 13:39:19 +0200
changeset 381960 d5e1533786ee8a8f754ef737ccd7980d30818e93
parent 381959 5c407eb7c7ef6cf42c1611dee2152cdee6a25e56
child 381961 8658f8f875d1d3015de7cdc495edea872436403f
push id32543
push userkwierso@gmail.com
push dateThu, 21 Sep 2017 00:18:37 +0000
treeherdermozilla-central@61340c7debf6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1400532
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 1400532 - Separate small and large shmem allocations in IpcResourceUpdateQueue. r=jrmuizel
gfx/layers/ipc/PWebRenderBridge.ipdl
gfx/layers/ipc/WebRenderMessages.ipdlh
gfx/layers/wr/IpcResourceUpdateQueue.cpp
gfx/layers/wr/IpcResourceUpdateQueue.h
gfx/layers/wr/WebRenderBridgeChild.cpp
gfx/layers/wr/WebRenderBridgeParent.cpp
gfx/layers/wr/WebRenderBridgeParent.h
--- a/gfx/layers/ipc/PWebRenderBridge.ipdl
+++ b/gfx/layers/ipc/PWebRenderBridge.ipdl
@@ -46,24 +46,24 @@ parent:
   // next Update call.
   async InitReadLocks(ReadLockInit[] locks);
 
   sync Create(IntSize aSize);
   async DeleteCompositorAnimations(uint64_t[] aIds);
   async SetDisplayList(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
                        LayoutSize aContentSize, ByteBuffer aDL, BuiltDisplayListDescriptor aDLDesc,
                        WebRenderScrollData aScrollData,
-                       OpUpdateResource[] aResourceUpdates, Shmem[] aResourceData,
+                       OpUpdateResource[] aResourceUpdates, Shmem[] aSmallShmems, Shmem[] aLargeShmems,
                        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,
-                          OpUpdateResource[] aResourceUpdates, Shmem[] aResourceData,
+                          OpUpdateResource[] aResourceUpdates, Shmem[] aSmallShmems, Shmem[] aLargeShmems,
                           IdNamespace aIdNamespace, TimeStamp txnStartTime, TimeStamp fwdTime);
-  async UpdateResources(OpUpdateResource[] aResourceUpdates, Shmem[] aResourceData);
+  async UpdateResources(OpUpdateResource[] aResourceUpdates, Shmem[] aSmallShmems, Shmem[] aLargeShmems);
   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/ipc/WebRenderMessages.ipdlh
+++ b/gfx/layers/ipc/WebRenderMessages.ipdlh
@@ -63,16 +63,17 @@ struct OpUpdateAsyncImagePipeline {
 
 union WebRenderParentCommand {
   OpUpdateAsyncImagePipeline;
   CompositableOperation;
   OpAddCompositorAnimations;
 };
 
 struct OffsetRange {
+  uint32_t source;
   uint32_t start;
   uint32_t length;
 };
 
 struct OpAddImage {
   ImageDescriptor descriptor;
   OffsetRange bytes;
   uint16_t tiling;
--- a/gfx/layers/wr/IpcResourceUpdateQueue.cpp
+++ b/gfx/layers/wr/IpcResourceUpdateQueue.cpp
@@ -25,127 +25,189 @@ ShmSegmentsWriter::~ShmSegmentsWriter()
 }
 
 layers::OffsetRange
 ShmSegmentsWriter::Write(Range<uint8_t> aBytes)
 {
   const size_t start = mCursor;
   const size_t length = aBytes.length();
 
+  if (length >= mChunkSize * 4) {
+    auto range = AllocLargeChunk(length);
+    uint8_t* dstPtr = mLargeAllocs.LastElement().get<uint8_t>();
+    memcpy(dstPtr, aBytes.begin().get(), length);
+    return range;
+  }
+
   int remainingBytesToCopy = length;
 
   size_t srcCursor = 0;
   size_t dstCursor = mCursor;
 
   while (remainingBytesToCopy > 0) {
-    if (dstCursor >= mData.Length() * mChunkSize) {
+    if (dstCursor >= mSmallAllocs.Length() * mChunkSize) {
       AllocChunk();
       continue;
     }
 
-    const size_t dstMaxOffset = mChunkSize * mData.Length();
-    const size_t dstBaseOffset = mChunkSize * (mData.Length() - 1);
+    const size_t dstMaxOffset = mChunkSize * mSmallAllocs.Length();
+    const size_t dstBaseOffset = mChunkSize * (mSmallAllocs.Length() - 1);
 
     MOZ_ASSERT(dstCursor >= dstBaseOffset);
     MOZ_ASSERT(dstCursor <= dstMaxOffset);
 
     size_t availableRange = dstMaxOffset - dstCursor;
     size_t copyRange = std::min<int>(availableRange, remainingBytesToCopy);
 
     uint8_t* srcPtr = &aBytes[srcCursor];
-    uint8_t* dstPtr = mData.LastElement().get<uint8_t>() + (dstCursor - dstBaseOffset);
+    uint8_t* dstPtr = mSmallAllocs.LastElement().get<uint8_t>() + (dstCursor - dstBaseOffset);
 
     memcpy(dstPtr, srcPtr, copyRange);
 
     srcCursor += copyRange;
     dstCursor += copyRange;
     remainingBytesToCopy -= copyRange;
 
     // sanity check
     MOZ_ASSERT(remainingBytesToCopy >= 0);
   }
 
   mCursor += length;
 
-  return layers::OffsetRange(start, length);
+  return layers::OffsetRange(0, start, length);
 }
 
 void
 ShmSegmentsWriter::AllocChunk()
 {
   ipc::Shmem shm;
   auto shmType = ipc::SharedMemory::SharedMemoryType::TYPE_BASIC;
   if (!mShmAllocator->AllocShmem(mChunkSize, shmType, &shm)) {
-    MOZ_CRASH("Shared memory allocation failed");
+    gfxCriticalError() << "ShmSegmentsWriter failed to allocate chunk #" << mSmallAllocs.Length();
+    MOZ_CRASH();
   }
-  mData.AppendElement(shm);
+  mSmallAllocs.AppendElement(shm);
+}
+
+layers::OffsetRange
+ShmSegmentsWriter::AllocLargeChunk(size_t aSize)
+{
+  ipc::Shmem shm;
+  auto shmType = ipc::SharedMemory::SharedMemoryType::TYPE_BASIC;
+  if (!mShmAllocator->AllocShmem(aSize, shmType, &shm)) {
+    gfxCriticalError() << "ShmSegmentsWriter failed to allocate large chunk of size " << aSize;
+    MOZ_CRASH();
+  }
+  mLargeAllocs.AppendElement(shm);
+
+  return layers::OffsetRange(mLargeAllocs.Length(), 0, aSize);
 }
 
 void
-ShmSegmentsWriter::Flush(nsTArray<ipc::Shmem>& aInto)
+ShmSegmentsWriter::Flush(nsTArray<ipc::Shmem>& aSmallAllocs, nsTArray<ipc::Shmem>& aLargeAllocs)
 {
-  aInto.Clear();
-  mData.SwapElements(aInto);
+  aSmallAllocs.Clear();
+  aLargeAllocs.Clear();
+  mSmallAllocs.SwapElements(aSmallAllocs);
+  mLargeAllocs.SwapElements(aLargeAllocs);
 }
 
 void
 ShmSegmentsWriter::Clear()
 {
   if (mShmAllocator) {
-    for (auto& shm : mData) {
+    for (auto& shm : mSmallAllocs) {
+      mShmAllocator->DeallocShmem(shm);
+    }
+    for (auto& shm : mLargeAllocs) {
       mShmAllocator->DeallocShmem(shm);
     }
   }
-  mData.Clear();
+  mSmallAllocs.Clear();
+  mLargeAllocs.Clear();
   mCursor = 0;
 }
 
-ShmSegmentsReader::ShmSegmentsReader(const nsTArray<ipc::Shmem>& aShmems)
-: mData(aShmems)
+ShmSegmentsReader::ShmSegmentsReader(const nsTArray<ipc::Shmem>& aSmallShmems,
+                                     const nsTArray<ipc::Shmem>& aLargeShmems)
+: mSmallAllocs(aSmallShmems)
+, mLargeAllocs(aLargeShmems)
 , mChunkSize(0)
 {
-  if (mData.IsEmpty()) {
+  if (mSmallAllocs.IsEmpty()) {
     return;
   }
 
-  mChunkSize = mData[0].Size<uint8_t>();
+  mChunkSize = mSmallAllocs[0].Size<uint8_t>();
 
   // Check that all shmems are readable and have the same size. If anything
   // isn't right, set mChunkSize to zero which signifies that the reader is
   // in an invalid state and Read calls will return false;
-  for (const auto& shm : mData) {
+  for (const auto& shm : mSmallAllocs) {
     if (!shm.IsReadable()
         || shm.Size<uint8_t>() != mChunkSize
         || shm.get<uint8_t>() == nullptr) {
       mChunkSize = 0;
       return;
     }
   }
+
+  for (const auto& shm : mLargeAllocs) {
+    if (!shm.IsReadable()
+        || shm.get<uint8_t>() == nullptr) {
+      mChunkSize = 0;
+      return;
+    }
+  }
 }
 
 bool
-ShmSegmentsReader::Read(layers::OffsetRange aRange, wr::Vec_u8& aInto)
+ShmSegmentsReader::ReadLarge(const layers::OffsetRange& aRange, wr::Vec_u8& aInto)
 {
+  // source = zero is for small allocs.
+  MOZ_RELEASE_ASSERT(aRange.source() != 0);
+  if (aRange.source() > mLargeAllocs.Length()) {
+    return false;
+  }
+  size_t id = aRange.source() - 1;
+  const ipc::Shmem& shm = mLargeAllocs[id];
+  if (shm.Size<uint8_t>() < aRange.length()) {
+    return false;
+  }
+
+  uint8_t* srcPtr = shm.get<uint8_t>();
+  aInto.PushBytes(Range<uint8_t>(srcPtr, aRange.length()));
+
+  return true;
+}
+
+bool
+ShmSegmentsReader::Read(const layers::OffsetRange& aRange, wr::Vec_u8& aInto)
+{
+  if (aRange.source() != 0) {
+    return ReadLarge(aRange, aInto);
+  }
+
   if (mChunkSize == 0) {
     return false;
   }
 
-  if (aRange.start() + aRange.length() > mChunkSize * mData.Length()) {
+  if (aRange.start() + aRange.length() > mChunkSize * mSmallAllocs.Length()) {
     return false;
   }
 
   size_t initialLength = aInto.Length();
 
   size_t srcCursor = aRange.start();
   int remainingBytesToCopy = aRange.length();
   while (remainingBytesToCopy > 0) {
     const size_t shm_idx = srcCursor / mChunkSize;
     const size_t ptrOffset = srcCursor % mChunkSize;
     const size_t copyRange = std::min<int>(remainingBytesToCopy, mChunkSize - ptrOffset);
-    uint8_t* srcPtr = mData[shm_idx].get<uint8_t>() + ptrOffset;
+    uint8_t* srcPtr = mSmallAllocs[shm_idx].get<uint8_t>() + ptrOffset;
 
     aInto.PushBytes(Range<uint8_t>(srcPtr, copyRange));
 
     srcCursor += copyRange;
     remainingBytesToCopy -= copyRange;
   }
 
   return aInto.Length() - initialLength == aRange.length();
@@ -233,21 +295,22 @@ IpcResourceUpdateQueue::AddFontInstance(
 void
 IpcResourceUpdateQueue::DeleteFontInstance(wr::FontInstanceKey aKey)
 {
   mUpdates.AppendElement(layers::OpDeleteFontInstance(aKey));
 }
 
 void
 IpcResourceUpdateQueue::Flush(nsTArray<layers::OpUpdateResource>& aUpdates,
-                              nsTArray<ipc::Shmem>& aResourceData)
+                              nsTArray<ipc::Shmem>& aSmallAllocs,
+                              nsTArray<ipc::Shmem>& aLargeAllocs)
 {
   aUpdates.Clear();
   mUpdates.SwapElements(aUpdates);
-  mWriter.Flush(aResourceData);
+  mWriter.Flush(aSmallAllocs, aLargeAllocs);
 }
 
 void
 IpcResourceUpdateQueue::Clear()
 {
   mWriter.Clear();
   mUpdates.Clear();
 }
--- a/gfx/layers/wr/IpcResourceUpdateQueue.h
+++ b/gfx/layers/wr/IpcResourceUpdateQueue.h
@@ -9,56 +9,62 @@
 #include "mozilla/webrender/WebRenderTypes.h"
 
 namespace mozilla {
 namespace ipc {
 class IShmemAllocator;
 }
 namespace wr {
 
+/// ShmSegmentsWriter pushes bytes in a sequence of fixed size shmems for small
+/// allocations and creates dedicated shmems for large allocations.
 class ShmSegmentsWriter {
 public:
   ShmSegmentsWriter(ipc::IShmemAllocator* aAllocator, size_t aChunkSize);
   ~ShmSegmentsWriter();
 
   layers::OffsetRange Write(Range<uint8_t> aBytes);
 
-  void Flush(nsTArray<ipc::Shmem>& aData);
+  void Flush(nsTArray<ipc::Shmem>& aSmallAllocs, nsTArray<ipc::Shmem>& aLargeAllocs);
 
   void Clear();
 
 protected:
   void AllocChunk();
+  layers::OffsetRange AllocLargeChunk(size_t aSize);
 
-  nsTArray<ipc::Shmem> mData;
+  nsTArray<ipc::Shmem> mSmallAllocs;
+  nsTArray<ipc::Shmem> mLargeAllocs;
   ipc::IShmemAllocator* mShmAllocator;
   size_t mCursor;
   size_t mChunkSize;
 };
 
 class ShmSegmentsReader {
 public:
-  explicit ShmSegmentsReader(const nsTArray<ipc::Shmem>& aShmems);
+  ShmSegmentsReader(const nsTArray<ipc::Shmem>& aSmallShmems,
+                    const nsTArray<ipc::Shmem>& aLargeShmems);
 
-  bool Read(layers::OffsetRange aRange, wr::Vec_u8& aInto);
+  bool Read(const layers::OffsetRange& aRange, wr::Vec_u8& aInto);
 
 protected:
-  void AllocChunk();
+  bool ReadLarge(const layers::OffsetRange& aRange, wr::Vec_u8& aInto);
 
-  const nsTArray<ipc::Shmem>& mData;
+  const nsTArray<ipc::Shmem>& mSmallAllocs;
+  const nsTArray<ipc::Shmem>& mLargeAllocs;
   size_t mChunkSize;
 };
 
 class IpcResourceUpdateQueue {
 public:
-  // TODO: 8192 is completely arbitrary, needs some adjustments.
+  // TODO: 32768 is completely arbitrary, needs some adjustments.
   // Because we are using shmems, the size should be a multiple of the page size, and keep in mind
   // that each shmem has guard pages, one of which contains meta-data so at least an extra page
   // is mapped under the hood (so having a lot of smaller shmems = overhead).
-  explicit IpcResourceUpdateQueue(ipc::IShmemAllocator* aAllocator, size_t aChunkSize = 8192);
+  explicit IpcResourceUpdateQueue(ipc::IShmemAllocator* aAllocator, size_t aChunkSize = 32768);
 
   void AddImage(wr::ImageKey aKey,
                 const ImageDescriptor& aDescriptor,
                 Range<uint8_t> aBytes);
 
   void AddBlobImage(wr::ImageKey aKey,
                     const ImageDescriptor& aDescriptor,
                     Range<uint8_t> aBytes);
@@ -91,17 +97,18 @@ public:
                        const wr::FontInstanceOptions* aOptions,
                        const wr::FontInstancePlatformOptions* aPlatformOptions);
 
   void DeleteFontInstance(wr::FontInstanceKey aKey);
 
   void Clear();
 
   void Flush(nsTArray<layers::OpUpdateResource>& aUpdates,
-             nsTArray<ipc::Shmem>& aResources);
+             nsTArray<ipc::Shmem>& aSmallAllocs,
+             nsTArray<ipc::Shmem>& aLargeAllocs);
 
 protected:
   ShmSegmentsWriter mWriter;
   nsTArray<layers::OpUpdateResource> mUpdates;
 };
 
 } // namespace
 } // namespace
--- a/gfx/layers/wr/WebRenderBridgeChild.cpp
+++ b/gfx/layers/wr/WebRenderBridgeChild.cpp
@@ -102,20 +102,21 @@ void
 WebRenderBridgeChild::UpdateResources(wr::IpcResourceUpdateQueue& aResources)
 {
   if (!IPCOpen()) {
     aResources.Clear();
     return;
   }
 
   nsTArray<OpUpdateResource> resourceUpdates;
-  nsTArray<ipc::Shmem> resourceData;
-  aResources.Flush(resourceUpdates, resourceData);
+  nsTArray<ipc::Shmem> smallShmems;
+  nsTArray<ipc::Shmem> largeShmems;
+  aResources.Flush(resourceUpdates, smallShmems, largeShmems);
 
-  this->SendUpdateResources(resourceUpdates, resourceData);
+  this->SendUpdateResources(resourceUpdates, Move(smallShmems), Move(largeShmems));
 }
 
 void
 WebRenderBridgeChild::EndTransaction(wr::DisplayListBuilder &aBuilder,
                                      wr::IpcResourceUpdateQueue& aResources,
                                      const gfx::IntSize& aSize,
                                      bool aIsSync,
                                      uint64_t aTransactionId,
@@ -131,30 +132,31 @@ WebRenderBridgeChild::EndTransaction(wr:
   ByteBuffer dlData(Move(dl.dl));
 
   TimeStamp fwdTime;
 #if defined(ENABLE_FRAME_LATENCY_LOG)
   fwdTime = TimeStamp::Now();
 #endif
 
   nsTArray<OpUpdateResource> resourceUpdates;
-  nsTArray<ipc::Shmem> resourceData;
-  aResources.Flush(resourceUpdates, resourceData);
+  nsTArray<ipc::Shmem> smallShmems;
+  nsTArray<ipc::Shmem> largeShmems;
+  aResources.Flush(resourceUpdates, smallShmems, largeShmems);
 
   if (aIsSync) {
     this->SendSetDisplayListSync(aSize, mParentCommands, mDestroyedActors,
                                  GetFwdTransactionId(), aTransactionId,
                                  contentSize, dlData, dl.dl_desc, aScrollData,
-                                 Move(resourceUpdates), Move(resourceData),
+                                 Move(resourceUpdates), Move(smallShmems), Move(largeShmems),
                                  mIdNamespace, aTxnStartTime, fwdTime);
   } else {
     this->SendSetDisplayList(aSize, mParentCommands, mDestroyedActors,
                              GetFwdTransactionId(), aTransactionId,
                              contentSize, dlData, dl.dl_desc, aScrollData,
-                             Move(resourceUpdates), Move(resourceData),
+                             Move(resourceUpdates), Move(smallShmems), Move(largeShmems),
                              mIdNamespace, aTxnStartTime, fwdTime);
   }
 
   mParentCommands.Clear();
   mDestroyedActors.Clear();
   mIsInTransaction = false;
 }
 
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -230,20 +230,21 @@ WebRenderBridgeParent::DeallocShmems(nsT
       DeallocShmem(shm);
     }
   }
   aShmems.Clear();
 }
 
 bool
 WebRenderBridgeParent::UpdateResources(const nsTArray<OpUpdateResource>& aResourceUpdates,
-                                       const nsTArray<ipc::Shmem>& aResourceData,
+                                       const nsTArray<ipc::Shmem>& aSmallShmems,
+                                       const nsTArray<ipc::Shmem>& aLargeShmems,
                                        wr::ResourceUpdateQueue& aUpdates)
 {
-  wr::ShmSegmentsReader reader(aResourceData);
+  wr::ShmSegmentsReader reader(aSmallShmems, aLargeShmems);
 
   for (const auto& cmd : aResourceUpdates) {
     switch (cmd.type()) {
       case OpUpdateResource::TOpAddImage: {
         const auto& op = cmd.get_OpAddImage();
         wr::Vec_u8 bytes;
         if (!reader.Read(op.bytes(), bytes)) {
           return false;
@@ -371,32 +372,36 @@ WebRenderBridgeParent::AddExternalImage(
   aResources.AddImage(keys[0], descriptor, data);
   dSurf->Unmap();
 
   return true;
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvUpdateResources(nsTArray<OpUpdateResource>&& aResourceUpdates,
-                                           nsTArray<ipc::Shmem>&& aResourceData)
+                                           nsTArray<ipc::Shmem>&& aSmallShmems,
+                                           nsTArray<ipc::Shmem>&& aLargeShmems)
 {
   if (mDestroyed) {
-    DeallocShmems(aResourceData);
+    DeallocShmems(aSmallShmems);
+    DeallocShmems(aLargeShmems);
     return IPC_OK();
   }
 
   wr::ResourceUpdateQueue updates;
 
-  if (!UpdateResources(aResourceUpdates, aResourceData, updates)) {
-    DeallocShmems(aResourceData);
+  if (!UpdateResources(aResourceUpdates, aSmallShmems, aLargeShmems, updates)) {
+    DeallocShmems(aSmallShmems);
+    DeallocShmems(aLargeShmems);
     IPC_FAIL(this, "Invalid WebRender resource data shmem or address.");
   }
 
   mApi->UpdateResources(updates);
-  DeallocShmems(aResourceData);
+  DeallocShmems(aSmallShmems);
+  DeallocShmems(aLargeShmems);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvDeleteCompositorAnimations(InfallibleTArray<uint64_t>&& aIds)
 {
   if (mDestroyed) {
     return IPC_OK();
@@ -492,26 +497,28 @@ WebRenderBridgeParent::RecvSetDisplayLis
                                           InfallibleTArray<OpDestroy>&& aToDestroy,
                                           const uint64_t& aFwdTransactionId,
                                           const uint64_t& aTransactionId,
                                           const wr::LayoutSize& aContentSize,
                                           const wr::ByteBuffer& dl,
                                           const wr::BuiltDisplayListDescriptor& dlDesc,
                                           const WebRenderScrollData& aScrollData,
                                           nsTArray<OpUpdateResource>&& aResourceUpdates,
-                                          nsTArray<ipc::Shmem>&& aResourceData,
+                                          nsTArray<ipc::Shmem>&& aSmallShmems,
+                                          nsTArray<ipc::Shmem>&& aLargeShmems,
                                           const wr::IdNamespace& aIdNamespace,
                                           const TimeStamp& aTxnStartTime,
                                           const TimeStamp& aFwdTime)
 {
   if (mDestroyed) {
     for (const auto& op : aToDestroy) {
       DestroyActor(op);
     }
-    DeallocShmems(aResourceData);
+    DeallocShmems(aSmallShmems);
+    DeallocShmems(aLargeShmems);
     return IPC_OK();
   }
 
   AutoProfilerTracing tracing("Paint", "SetDisplayList");
   UpdateFwdTransactionId(aFwdTransactionId);
   AutoClearReadLocks clearLocks(mReadLocks);
 
   // This ensures that destroy operations are always processed. It is not safe
@@ -521,17 +528,19 @@ WebRenderBridgeParent::RecvSetDisplayLis
   uint32_t wrEpoch = GetNextWrEpoch();
 
 
   wr::ResourceUpdateQueue resources;
 
   mAsyncImageManager->SetCompositionTime(TimeStamp::Now());
   ProcessWebRenderParentCommands(aCommands, resources);
 
-  UpdateResources(aResourceUpdates, aResourceData, resources);
+  if (!UpdateResources(aResourceUpdates, aSmallShmems, aLargeShmems, resources)) {
+    return IPC_FAIL(this, "Failed to deserialize resource updates");
+  }
 
   // If id namespaces do not match, it means the command is obsolete, probably
   // because the tab just moved to a new window.
   // In that case do not send the commands to webrender.
   if (mIdNamespace == aIdNamespace) {
     if (mWidget) {
       LayoutDeviceIntSize size = mWidget->GetClientSize();
       mApi->SetWindowParameters(size);
@@ -556,40 +565,42 @@ WebRenderBridgeParent::RecvSetDisplayLis
 
   if (mIdNamespace != aIdNamespace) {
     // Pretend we composited since someone is wating for this event,
     // though DisplayList was not pushed to webrender.
     TimeStamp now = TimeStamp::Now();
     mCompositorBridge->DidComposite(wr::AsUint64(mPipelineId), now, now);
   }
 
-  DeallocShmems(aResourceData);
+  DeallocShmems(aSmallShmems);
+  DeallocShmems(aLargeShmems);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvSetDisplayListSync(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,
                                               const WebRenderScrollData& aScrollData,
                                               nsTArray<OpUpdateResource>&& aResourceUpdates,
-                                              nsTArray<ipc::Shmem>&& aResourceData,
+                                              nsTArray<ipc::Shmem>&& aSmallShmems,
+                                              nsTArray<ipc::Shmem>&& aLargeShmems,
                                               const wr::IdNamespace& aIdNamespace,
                                               const TimeStamp& aTxnStartTime,
                                               const TimeStamp& aFwdTime)
 {
   return RecvSetDisplayList(aSize, Move(aCommands), Move(aToDestroy),
                             aFwdTransactionId, aTransactionId,
                             aContentSize, dl, dlDesc, aScrollData,
-                            Move(aResourceUpdates), Move(aResourceData),
+                            Move(aResourceUpdates), Move(aSmallShmems), Move(aLargeShmems),
                             aIdNamespace, aTxnStartTime, aFwdTime);
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvParentCommands(nsTArray<WebRenderParentCommand>&& aCommands)
 {
   if (mDestroyed) {
     return IPC_OK();
--- a/gfx/layers/wr/WebRenderBridgeParent.h
+++ b/gfx/layers/wr/WebRenderBridgeParent.h
@@ -69,42 +69,45 @@ public:
 
   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 RecvDeleteCompositorAnimations(InfallibleTArray<uint64_t>&& aIds) override;
   mozilla::ipc::IPCResult RecvUpdateResources(nsTArray<OpUpdateResource>&& aUpdates,
-                                              nsTArray<ipc::Shmem>&& aResourceData) override;
+                                              nsTArray<ipc::Shmem>&& aSmallShmems,
+                                              nsTArray<ipc::Shmem>&& aLargeShmems) 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,
                                              const WebRenderScrollData& aScrollData,
                                              nsTArray<OpUpdateResource>&& aResourceUpdates,
-                                             nsTArray<ipc::Shmem>&& aResourceData,
+                                             nsTArray<ipc::Shmem>&& aSmallShmems,
+                                             nsTArray<ipc::Shmem>&& aLargeShmems,
                                              const wr::IdNamespace& aIdNamespace,
                                              const TimeStamp& aTxnStartTime,
                                              const TimeStamp& aFwdTime) override;
   mozilla::ipc::IPCResult RecvSetDisplayListSync(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,
                                                  const WebRenderScrollData& aScrollData,
                                                  nsTArray<OpUpdateResource>&& aResourceUpdates,
-                                                 nsTArray<ipc::Shmem>&& aResourceData,
+                                                 nsTArray<ipc::Shmem>&& aSmallShmems,
+                                                 nsTArray<ipc::Shmem>&& aLargeShmems,
                                                  const wr::IdNamespace& aIdNamespace,
                                                  const TimeStamp& aTxnStartTime,
                                                  const TimeStamp& aFwdTime) override;
   mozilla::ipc::IPCResult RecvParentCommands(nsTArray<WebRenderParentCommand>&& commands) override;
   mozilla::ipc::IPCResult RecvGetSnapshot(PTextureParent* aTexture) override;
 
   mozilla::ipc::IPCResult RecvAddPipelineIdForCompositable(const wr::PipelineId& aPipelineIds,
                                                            const CompositableHandle& aHandle,
@@ -185,17 +188,18 @@ public:
 
 private:
   void DeallocShmems(nsTArray<ipc::Shmem>& aShmems);
 
   explicit WebRenderBridgeParent(const wr::PipelineId& aPipelineId);
   virtual ~WebRenderBridgeParent();
 
   bool UpdateResources(const nsTArray<OpUpdateResource>& aResourceUpdates,
-                       const nsTArray<ipc::Shmem>& aResourceData,
+                       const nsTArray<ipc::Shmem>& aSmallShmems,
+                       const nsTArray<ipc::Shmem>& aLargeShmems,
                        wr::ResourceUpdateQueue& aUpdates);
   bool AddExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey,
                         wr::ResourceUpdateQueue& aResources);
 
   uint64_t GetLayersId() const;
   void ProcessWebRenderParentCommands(const InfallibleTArray<WebRenderParentCommand>& aCommands,
                                       wr::ResourceUpdateQueue& aResources);