Bug 1403539 - Skip to PushImage in WebRenderCommandsBuilder if AddXXXImage fails to return. r=nical
authorvincentliu <vliu@mozilla.com>
Thu, 12 Oct 2017 10:25:34 +0800
changeset 428271 b3dddc032e3d4f11e80ca03d6fc15e611ef95c26
parent 428270 76fb9cb1078c4abf59ac2fc50a95bbb90e6979fa
child 428272 7fde6d8f818288f648f077d83ee1f200b580e1ff
push id97
push userfmarier@mozilla.com
push dateSat, 14 Oct 2017 01:12:59 +0000
reviewersnical
bugs1403539
milestone58.0a1
Bug 1403539 - Skip to PushImage in WebRenderCommandsBuilder if AddXXXImage fails to return. r=nical
gfx/layers/wr/IpcResourceUpdateQueue.cpp
gfx/layers/wr/IpcResourceUpdateQueue.h
gfx/layers/wr/WebRenderCommandBuilder.cpp
--- a/gfx/layers/wr/IpcResourceUpdateQueue.cpp
+++ b/gfx/layers/wr/IpcResourceUpdateQueue.cpp
@@ -36,20 +36,28 @@ ShmSegmentsWriter::Write(Range<uint8_t> 
     memcpy(dstPtr, aBytes.begin().get(), length);
     return range;
   }
 
   int remainingBytesToCopy = length;
 
   size_t srcCursor = 0;
   size_t dstCursor = mCursor;
+  size_t currAllocLen = mSmallAllocs.Length();
 
   while (remainingBytesToCopy > 0) {
     if (dstCursor >= mSmallAllocs.Length() * mChunkSize) {
-      AllocChunk();
+      if (!AllocChunk()) {
+        for (size_t i = mSmallAllocs.Length() ; currAllocLen <= i ; i--) {
+          ipc::Shmem shm = mSmallAllocs.ElementAt(i);
+          mShmAllocator->DeallocShmem(shm);
+          mSmallAllocs.RemoveElementAt(i);
+        }
+        return layers::OffsetRange(0, start, 0);
+      }
       continue;
     }
 
     const size_t dstMaxOffset = mChunkSize * mSmallAllocs.Length();
     const size_t dstBaseOffset = mChunkSize * (mSmallAllocs.Length() - 1);
 
     MOZ_ASSERT(dstCursor >= dstBaseOffset);
     MOZ_ASSERT(dstCursor <= dstMaxOffset);
@@ -70,36 +78,39 @@ ShmSegmentsWriter::Write(Range<uint8_t> 
     MOZ_ASSERT(remainingBytesToCopy >= 0);
   }
 
   mCursor += length;
 
   return layers::OffsetRange(0, start, length);
 }
 
-void
+bool
 ShmSegmentsWriter::AllocChunk()
 {
   ipc::Shmem shm;
   auto shmType = ipc::SharedMemory::SharedMemoryType::TYPE_BASIC;
   if (!mShmAllocator->AllocShmem(mChunkSize, shmType, &shm)) {
-    gfxCriticalError() << "ShmSegmentsWriter failed to allocate chunk #" << mSmallAllocs.Length();
-    MOZ_CRASH();
+    gfxCriticalNote << "ShmSegmentsWriter failed to allocate chunk #" << mSmallAllocs.Length();
+    MOZ_ASSERT(false, "ShmSegmentsWriter fails to allocate chunk");
+    return false;
   }
   mSmallAllocs.AppendElement(shm);
+  return true;
 }
 
 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();
+    gfxCriticalNote << "ShmSegmentsWriter failed to allocate large chunk of size " << aSize;
+    MOZ_ASSERT(false, "ShmSegmentsWriter fails to allocate large chunk");
+    return layers::OffsetRange(0, 0, 0);
   }
   mLargeAllocs.AppendElement(shm);
 
   return layers::OffsetRange(mLargeAllocs.Length(), 0, aSize);
 }
 
 void
 ShmSegmentsWriter::Flush(nsTArray<ipc::Shmem>& aSmallAllocs, nsTArray<ipc::Shmem>& aLargeAllocs)
@@ -217,67 +228,87 @@ ShmSegmentsReader::Read(const layers::Of
   return aInto.Length() - initialLength == aRange.length();
 }
 
 IpcResourceUpdateQueue::IpcResourceUpdateQueue(ipc::IShmemAllocator* aAllocator,
                                                size_t aChunkSize)
 : mWriter(Move(aAllocator), aChunkSize)
 {}
 
-void
+bool
 IpcResourceUpdateQueue::AddImage(ImageKey key, const ImageDescriptor& aDescriptor,
                                  Range<uint8_t> aBytes)
 {
   auto bytes = mWriter.Write(aBytes);
+  if (!bytes.length()) {
+    return false;
+  }
   mUpdates.AppendElement(layers::OpAddImage(aDescriptor, bytes, 0, key));
+  return true;
 }
 
-void
+bool
 IpcResourceUpdateQueue::AddBlobImage(ImageKey key, const ImageDescriptor& aDescriptor,
                                      Range<uint8_t> aBytes)
 {
   auto bytes = mWriter.Write(aBytes);
+  if (!bytes.length()) {
+    return false;
+  }
   mUpdates.AppendElement(layers::OpAddBlobImage(aDescriptor, bytes, 0, key));
+  return true;
 }
 
 void
 IpcResourceUpdateQueue::AddExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey)
 {
   mUpdates.AppendElement(layers::OpAddExternalImage(aExtId, aKey));
 }
 
-void
+bool
 IpcResourceUpdateQueue::UpdateImageBuffer(ImageKey aKey,
                                           const ImageDescriptor& aDescriptor,
                                           Range<uint8_t> aBytes)
 {
   auto bytes = mWriter.Write(aBytes);
+  if (!bytes.length()) {
+    return false;
+  }
   mUpdates.AppendElement(layers::OpUpdateImage(aDescriptor, bytes, aKey));
+  return true;
 }
 
-void
+bool
 IpcResourceUpdateQueue::UpdateBlobImage(ImageKey aKey,
                                         const ImageDescriptor& aDescriptor,
                                         Range<uint8_t> aBytes)
 {
   auto bytes = mWriter.Write(aBytes);
+  if (!bytes.length()) {
+    return false;
+  }
   mUpdates.AppendElement(layers::OpUpdateBlobImage(aDescriptor, bytes, aKey));
+  return true;
 }
 
 void
 IpcResourceUpdateQueue::DeleteImage(ImageKey aKey)
 {
   mUpdates.AppendElement(layers::OpDeleteImage(aKey));
 }
 
-void
+bool
 IpcResourceUpdateQueue::AddRawFont(wr::FontKey aKey, Range<uint8_t> aBytes, uint32_t aIndex)
 {
   auto bytes = mWriter.Write(aBytes);
+  if (!bytes.length()) {
+    return false;
+  }
   mUpdates.AppendElement(layers::OpAddRawFont(bytes, aIndex, aKey));
+  return true;
 }
 
 void
 IpcResourceUpdateQueue::DeleteFont(wr::FontKey aKey)
 {
   mUpdates.AppendElement(layers::OpDeleteFont(aKey));
 }
 
--- a/gfx/layers/wr/IpcResourceUpdateQueue.h
+++ b/gfx/layers/wr/IpcResourceUpdateQueue.h
@@ -29,17 +29,17 @@ public:
     return Write(Range<uint8_t>((uint8_t*)aValues.begin().get(), aValues.length() * sizeof(T)));
   }
 
   void Flush(nsTArray<ipc::Shmem>& aSmallAllocs, nsTArray<ipc::Shmem>& aLargeAllocs);
 
   void Clear();
 
 protected:
-  void AllocChunk();
+  bool AllocChunk();
   layers::OffsetRange AllocLargeChunk(size_t aSize);
 
   nsTArray<ipc::Shmem> mSmallAllocs;
   nsTArray<ipc::Shmem> mLargeAllocs;
   ipc::IShmemAllocator* mShmAllocator;
   size_t mCursor;
   size_t mChunkSize;
 };
@@ -62,43 +62,43 @@ protected:
 class IpcResourceUpdateQueue {
 public:
   // Because we are using shmems, the size should be a multiple of the page size.
   // Each shmem has two guard pages, and the minimum shmem size (at least one Windows)
   // is 64k which is already quite large for a lot of the resources we use here.
   // So we pick 64k - 2 * 4k = 57344 bytes as the defautl alloc
   explicit IpcResourceUpdateQueue(ipc::IShmemAllocator* aAllocator, size_t aChunkSize = 57344);
 
-  void AddImage(wr::ImageKey aKey,
+  bool AddImage(wr::ImageKey aKey,
                 const ImageDescriptor& aDescriptor,
                 Range<uint8_t> aBytes);
 
-  void AddBlobImage(wr::ImageKey aKey,
+  bool AddBlobImage(wr::ImageKey aKey,
                     const ImageDescriptor& aDescriptor,
                     Range<uint8_t> aBytes);
 
   void AddExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey);
 
-  void UpdateImageBuffer(wr::ImageKey aKey,
+  bool UpdateImageBuffer(wr::ImageKey aKey,
                          const ImageDescriptor& aDescriptor,
                          Range<uint8_t> aBytes);
 
-  void UpdateBlobImage(wr::ImageKey aKey,
+  bool UpdateBlobImage(wr::ImageKey aKey,
                        const ImageDescriptor& aDescriptor,
                        Range<uint8_t> aBytes);
 
   void UpdateExternalImage(ImageKey aKey,
                            const ImageDescriptor& aDescriptor,
                            ExternalImageId aExtID,
                            wr::WrExternalImageBufferType aBufferType,
                            uint8_t aChannelIndex = 0);
 
   void DeleteImage(wr::ImageKey aKey);
 
-  void AddRawFont(wr::FontKey aKey, Range<uint8_t> aBytes, uint32_t aIndex);
+  bool AddRawFont(wr::FontKey aKey, Range<uint8_t> aBytes, uint32_t aIndex);
 
   void DeleteFont(wr::FontKey aKey);
 
   void AddFontInstance(wr::FontInstanceKey aKey,
                        wr::FontKey aFontKey,
                        float aGlyphSize,
                        const wr::FontInstanceOptions* aOptions,
                        const wr::FontInstancePlatformOptions* aPlatformOptions,
--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -511,17 +511,19 @@ WebRenderCommandBuilder::GenerateFallbac
       RefPtr<gfx::DrawTarget> dt = gfx::Factory::CreateRecordingDrawTarget(recorder, dummyDt, paintSize.ToUnknownSize());
       PaintItemByDrawTarget(aItem, dt, paintRect, offset, aDisplayListBuilder,
                             fallbackData->mBasicLayerManager, mManager, scale);
       recorder->Finish();
 
       Range<uint8_t> bytes((uint8_t*)recorder->mOutputStream.mData, recorder->mOutputStream.mLength);
       wr::ImageKey key = mManager->WrBridge()->GetNextImageKey();
       wr::ImageDescriptor descriptor(paintSize.ToUnknownSize(), 0, dt->GetFormat(), isOpaque);
-      aResources.AddBlobImage(key, descriptor, bytes);
+      if (!aResources.AddBlobImage(key, descriptor, bytes)) {
+        return nullptr;
+      }
       fallbackData->SetKey(key);
     } else {
       fallbackData->CreateImageClientIfNeeded();
       RefPtr<ImageClient> imageClient = fallbackData->GetImageClient();
       RefPtr<ImageContainer> imageContainer = LayerManager::CreateImageContainer();
 
       {
         UpdateImageHelper helper(imageContainer, imageClient, paintSize.ToUnknownSize(), format);