Bug 1063733 - Optimize DataSourceSurface allocation. r=bas, r=seth, a=sledru
authorMichael Wu <mwu@mozilla.com>
Wed, 10 Sep 2014 17:54:16 -0400
changeset 216725 5982da7a1215
parent 216724 abbbaa040046
child 216726 2938d6cea847
push id3891
push userryanvm@gmail.com
push date2014-09-15 14:22 +0000
treeherdermozilla-beta@5982da7a1215 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbas, seth, sledru
bugs1063733
milestone33.0
Bug 1063733 - Optimize DataSourceSurface allocation. r=bas, r=seth, a=sledru
gfx/2d/2D.h
gfx/2d/DataSurfaceHelpers.h
gfx/2d/DrawTargetCG.cpp
gfx/2d/Factory.cpp
gfx/2d/FilterNodeSoftware.cpp
gfx/2d/SourceSurfaceRawData.cpp
gfx/2d/SourceSurfaceRawData.h
gfx/2d/Tools.h
image/src/RasterImage.cpp
image/src/imgTools.cpp
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -1055,29 +1055,29 @@ public:
    * cairo_scaled_font_t* parameters must correspond to the same font.
    */
   static TemporaryRef<ScaledFont>
     CreateScaledFontWithCairo(const NativeFont &aNativeFont, Float aSize, cairo_scaled_font_t* aScaledFont);
 
   /**
    * This creates a simple data source surface for a certain size. It allocates
    * new memory for the surface. This memory is freed when the surface is
-   * destroyed.
+   * destroyed. The surface is not zeroed unless requested.
    */
   static TemporaryRef<DataSourceSurface>
-    CreateDataSourceSurface(const IntSize &aSize, SurfaceFormat aFormat);
+    CreateDataSourceSurface(const IntSize &aSize, SurfaceFormat aFormat, bool aZero = false);
 
   /**
    * This creates a simple data source surface for a certain size with a
    * specific stride, which must be large enough to fit all pixels.
    * It allocates new memory for the surface. This memory is freed when
-   * the surface is destroyed.
+   * the surface is destroyed. The surface is not zeroed unless requested.
    */
   static TemporaryRef<DataSourceSurface>
-    CreateDataSourceSurfaceWithStride(const IntSize &aSize, SurfaceFormat aFormat, int32_t aStride);
+    CreateDataSourceSurfaceWithStride(const IntSize &aSize, SurfaceFormat aFormat, int32_t aStride, bool aZero = false);
 
   /**
    * This creates a simple data source surface for some existing data. It will
    * wrap this data and the data for this source surface. The caller is
    * responsible for deallocating the memory only after destruction of the
    * surface.
    */
   static TemporaryRef<DataSourceSurface>
--- a/gfx/2d/DataSurfaceHelpers.h
+++ b/gfx/2d/DataSurfaceHelpers.h
@@ -43,16 +43,18 @@ SurfaceToPackedBGRA(DataSourceSurface *a
  * color components).
  */
 uint8_t*
 SurfaceToPackedBGR(DataSourceSurface *aSurface);
 
 /**
  * Clears all the bytes in a DataSourceSurface's data array to zero (so to
  * transparent black for SurfaceFormat::B8G8R8A8, for example).
+ * Note that DataSourceSurfaces can be initialized to zero, which is
+ * more efficient than zeroing the surface after initialization.
  */
 void
 ClearDataSourceSurface(DataSourceSurface *aSurface);
 
 /**
  * Multiplies aStride and aHeight and makes sure the result is limited to
  * something sane. To keep things consistent, this should always be used
  * wherever we allocate a buffer based on surface stride and height.
--- a/gfx/2d/DrawTargetCG.cpp
+++ b/gfx/2d/DrawTargetCG.cpp
@@ -1328,19 +1328,18 @@ DrawTargetCG::Init(BackendType aType,
     size_t bufLen = BufferSizeFromStrideAndHeight(aStride, aSize.height);
     if (bufLen == 0) {
       mColorSpace = nullptr;
       mCg = nullptr;
       return false;
     }
     static_assert(sizeof(decltype(mData[0])) == 1,
                   "mData.Realloc() takes an object count, so its objects must be 1-byte sized if we use bufLen");
-    mData.Realloc(/* actually an object count */ bufLen);
+    mData.Realloc(/* actually an object count */ bufLen, true);
     aData = static_cast<unsigned char*>(mData);
-    memset(aData, 0, bufLen);
   }
 
   mSize = aSize;
 
   if (aType == BackendType::COREGRAPHICS_ACCELERATED) {
     RefPtr<MacIOSurface> ioSurface = MacIOSurface::CreateIOSurface(aSize.width, aSize.height);
     mCg = ioSurface->CreateIOSurfaceContext();
     // If we don't have the symbol for 'CreateIOSurfaceContext' mCg will be null
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -686,41 +686,43 @@ Factory::CreateWrappingDataSourceSurface
     return newSurf.forget();
   }
 
   return nullptr;
 }
 
 TemporaryRef<DataSourceSurface>
 Factory::CreateDataSourceSurface(const IntSize &aSize,
-                                 SurfaceFormat aFormat)
+                                 SurfaceFormat aFormat,
+                                 bool aZero)
 {
   if (!CheckSurfaceSize(aSize)) {
     return nullptr;
   }
 
   RefPtr<SourceSurfaceAlignedRawData> newSurf = new SourceSurfaceAlignedRawData();
-  if (newSurf->Init(aSize, aFormat)) {
+  if (newSurf->Init(aSize, aFormat, aZero)) {
     return newSurf.forget();
   }
 
   return nullptr;
 }
 
 TemporaryRef<DataSourceSurface>
 Factory::CreateDataSourceSurfaceWithStride(const IntSize &aSize,
                                            SurfaceFormat aFormat,
-                                           int32_t aStride)
+                                           int32_t aStride,
+                                           bool aZero)
 {
   if (aStride < aSize.width * BytesPerPixel(aFormat)) {
     return nullptr;
   }
 
   RefPtr<SourceSurfaceAlignedRawData> newSurf = new SourceSurfaceAlignedRawData();
-  if (newSurf->InitWithStride(aSize, aFormat, aStride)) {
+  if (newSurf->InitWithStride(aSize, aFormat, aStride, aZero)) {
     return newSurf.forget();
   }
 
   return nullptr;
 }
 
 TemporaryRef<DrawEventRecorder>
 Factory::CreateEventRecorderForFile(const char *aFilename)
--- a/gfx/2d/FilterNodeSoftware.cpp
+++ b/gfx/2d/FilterNodeSoftware.cpp
@@ -486,27 +486,24 @@ GetDataSurfaceInRect(SourceSurface *aSur
     return aSurface ? aSurface->GetDataSurface() : nullptr;
   }
 
   IntRect intersect = sourceRect.Intersect(aDestRect);
   IntRect intersectInSourceSpace = intersect - sourceRect.TopLeft();
   IntRect intersectInDestSpace = intersect - aDestRect.TopLeft();
   SurfaceFormat format = aSurface ? aSurface->GetFormat() : SurfaceFormat(SurfaceFormat::B8G8R8A8);
 
+  bool clear = aEdgeMode == EDGE_MODE_NONE && !aSurfaceRect.Contains(aDestRect);
   RefPtr<DataSourceSurface> target =
-    Factory::CreateDataSourceSurface(aDestRect.Size(), format);
+    Factory::CreateDataSourceSurface(aDestRect.Size(), format, clear);
 
   if (!target) {
     return nullptr;
   }
 
-  if (aEdgeMode == EDGE_MODE_NONE && !aSurfaceRect.Contains(aDestRect)) {
-    ClearDataSourceSurface(target);
-  }
-
   if (!aSurface) {
     return target.forget();
   }
 
   RefPtr<DataSourceSurface> dataSource = aSurface->GetDataSurface();
   MOZ_ASSERT(dataSource);
 
   if (aEdgeMode == EDGE_MODE_WRAP) {
@@ -2366,21 +2363,20 @@ FilterNodeConvolveMatrixSoftware::DoRend
 
   if (!input) {
     return nullptr;
   }
 
   DebugOnlyAutoColorSamplingAccessControl accessControl(input);
 
   RefPtr<DataSourceSurface> target =
-    Factory::CreateDataSourceSurface(aRect.Size(), SurfaceFormat::B8G8R8A8);
+    Factory::CreateDataSourceSurface(aRect.Size(), SurfaceFormat::B8G8R8A8, true);
   if (!target) {
     return nullptr;
   }
-  ClearDataSourceSurface(target);
 
   IntPoint offset = aRect.TopLeft() - srcRect.TopLeft();
 
   uint8_t* sourceData = DataAtOffset(input, offset);
   int32_t sourceStride = input->Stride();
   uint8_t* targetData = target->GetData();
   int32_t targetStride = target->Stride();
 
@@ -2771,25 +2767,23 @@ FilterNodeCompositeSoftware::SetAttribut
 }
 
 TemporaryRef<DataSourceSurface>
 FilterNodeCompositeSoftware::Render(const IntRect& aRect)
 {
   RefPtr<DataSourceSurface> start =
     GetInputDataSourceSurface(IN_COMPOSITE_IN_START, aRect, NEED_COLOR_CHANNELS);
   RefPtr<DataSourceSurface> dest =
-    Factory::CreateDataSourceSurface(aRect.Size(), SurfaceFormat::B8G8R8A8);
+    Factory::CreateDataSourceSurface(aRect.Size(), SurfaceFormat::B8G8R8A8, !start);
   if (!dest) {
     return nullptr;
   }
 
   if (start) {
     CopyRect(start, dest, aRect - aRect.TopLeft(), IntPoint());
-  } else {
-    ClearDataSourceSurface(dest);
   }
 
   for (size_t inputIndex = 1; inputIndex < NumberOfSetInputs(); inputIndex++) {
     RefPtr<DataSourceSurface> input =
       GetInputDataSourceSurface(IN_COMPOSITE_IN_START + inputIndex, aRect, NEED_COLOR_CHANNELS);
     if (input) {
       FilterProcessing::ApplyComposition(input, dest, mOperator);
     } else {
--- a/gfx/2d/SourceSurfaceRawData.cpp
+++ b/gfx/2d/SourceSurfaceRawData.cpp
@@ -25,48 +25,50 @@ SourceSurfaceRawData::InitWrappingData(u
   mFormat = aFormat;
   mOwnData = aOwnData;
 
   return true;
 }
 
 bool
 SourceSurfaceAlignedRawData::Init(const IntSize &aSize,
-                                  SurfaceFormat aFormat)
+                                  SurfaceFormat aFormat,
+                                  bool aZero)
 {
   mFormat = aFormat;
   mStride = GetAlignedStride<16>(aSize.width * BytesPerPixel(aFormat));
 
   size_t bufLen = BufferSizeFromStrideAndHeight(mStride, aSize.height);
   if (bufLen > 0) {
     static_assert(sizeof(decltype(mArray[0])) == 1,
                   "mArray.Realloc() takes an object count, so its objects must be 1-byte sized if we use bufLen");
-    mArray.Realloc(/* actually an object count */ bufLen);
+    mArray.Realloc(/* actually an object count */ bufLen, aZero);
     mSize = aSize;
   } else {
     mArray.Dealloc();
     mSize.SizeTo(0, 0);
   }
 
   return mArray != nullptr;
 }
 
 bool
 SourceSurfaceAlignedRawData::InitWithStride(const IntSize &aSize,
                                             SurfaceFormat aFormat,
-                                            int32_t aStride)
+                                            int32_t aStride,
+                                            bool aZero)
 {
   mFormat = aFormat;
   mStride = aStride;
 
   size_t bufLen = BufferSizeFromStrideAndHeight(mStride, aSize.height);
   if (bufLen > 0) {
     static_assert(sizeof(decltype(mArray[0])) == 1,
                   "mArray.Realloc() takes an object count, so its objects must be 1-byte sized if we use bufLen");
-    mArray.Realloc(/* actually an object count */ bufLen);
+    mArray.Realloc(/* actually an object count */ bufLen, aZero);
     mSize = aSize;
   } else {
     mArray.Dealloc();
     mSize.SizeTo(0, 0);
   }
 
   return mArray != nullptr;
 }
--- a/gfx/2d/SourceSurfaceRawData.h
+++ b/gfx/2d/SourceSurfaceRawData.h
@@ -49,20 +49,22 @@ public:
   virtual uint8_t *GetData() { return mArray; }
   virtual int32_t Stride() { return mStride; }
 
   virtual SurfaceType GetType() const { return SurfaceType::DATA; }
   virtual IntSize GetSize() const { return mSize; }
   virtual SurfaceFormat GetFormat() const { return mFormat; }
 
   bool Init(const IntSize &aSize,
-            SurfaceFormat aFormat);
+            SurfaceFormat aFormat,
+            bool aZero);
   bool InitWithStride(const IntSize &aSize,
                       SurfaceFormat aFormat,
-                      int32_t aStride);
+                      int32_t aStride,
+                      bool aZero);
 
 private:
   AlignedArray<uint8_t> mArray;
   int32_t mStride;
   SurfaceFormat mFormat;
   IntSize mSize;
 };
 
--- a/gfx/2d/Tools.h
+++ b/gfx/2d/Tools.h
@@ -98,21 +98,21 @@ struct AlignedArray
   typedef T value_type;
 
   AlignedArray()
     : mPtr(nullptr)
     , mStorage(nullptr)
   {
   }
 
-  MOZ_ALWAYS_INLINE AlignedArray(size_t aCount)
+  MOZ_ALWAYS_INLINE AlignedArray(size_t aCount, bool aZero = false)
     : mStorage(nullptr)
     , mCount(0)
   {
-    Realloc(aCount);
+    Realloc(aCount, aZero);
   }
 
   MOZ_ALWAYS_INLINE ~AlignedArray()
   {
     Dealloc();
   }
 
   void Dealloc()
@@ -133,30 +133,34 @@ struct AlignedArray
     }
 #endif
 
     delete [] mStorage;
     mStorage = nullptr;
     mPtr = nullptr;
   }
 
-  MOZ_ALWAYS_INLINE void Realloc(size_t aCount)
+  MOZ_ALWAYS_INLINE void Realloc(size_t aCount, bool aZero = false)
   {
     delete [] mStorage;
     CheckedInt32 storageByteCount =
       CheckedInt32(sizeof(T)) * aCount + (alignment - 1);
     if (!storageByteCount.isValid()) {
       mStorage = nullptr;
       mPtr = nullptr;
       mCount = 0;
       return;
     }
     // We don't create an array of T here, since we don't want ctors to be
     // invoked at the wrong places if we realign below.
-    mStorage = new (std::nothrow) uint8_t[storageByteCount.value()];
+    if (aZero) {
+      mStorage = static_cast<uint8_t *>(calloc(1, storageByteCount.value()));
+    } else {
+      mStorage = new (std::nothrow) uint8_t[storageByteCount.value()];
+    }
     if (!mStorage) {
       mStorage = nullptr;
       mPtr = nullptr;
       mCount = 0;
       return;
     }
     if (uintptr_t(mStorage) % alignment) {
       // Our storage does not start at a <alignment>-byte boundary. Make sure mPtr does!
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -859,17 +859,19 @@ RasterImage::CopyFrame(uint32_t aWhichFr
     return nullptr;
   }
 
   // Create a 32-bit image surface of our size, but draw using the frame's
   // rect, implicitly padding the frame out to the image's size.
 
   IntSize size(mSize.width, mSize.height);
   RefPtr<DataSourceSurface> surf =
-    Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8);
+    Factory::CreateDataSourceSurface(size,
+                                     SurfaceFormat::B8G8R8A8,
+                                     /* aZero = */ true);
 
   DataSourceSurface::MappedSurface mapping;
   DebugOnly<bool> success =
     surf->Map(DataSourceSurface::MapType::WRITE, &mapping);
   NS_ASSERTION(success, "Failed to map surface");
   RefPtr<DrawTarget> target =
     Factory::CreateDrawTargetForData(BackendType::CAIRO,
                                      mapping.mData,
--- a/image/src/imgTools.cpp
+++ b/image/src/imgTools.cpp
@@ -265,17 +265,18 @@ NS_IMETHODIMP imgTools::EncodeCroppedIma
   }
 
   // Check that the given crop rectangle is within image bounds.
   NS_ENSURE_ARG(frameWidth >= aOffsetX + aWidth &&
                 frameHeight >= aOffsetY + aHeight);
 
   RefPtr<DataSourceSurface> dataSurface =
     Factory::CreateDataSourceSurface(IntSize(aWidth, aHeight),
-                                     SurfaceFormat::B8G8R8A8);
+                                     SurfaceFormat::B8G8R8A8,
+                                     /* aZero = */ true);
   DataSourceSurface::MappedSurface map;
   if (!dataSurface->Map(DataSourceSurface::MapType::WRITE, &map)) {
     return NS_ERROR_FAILURE;
   }
 
   RefPtr<DrawTarget> dt =
     Factory::CreateDrawTargetForData(BackendType::CAIRO,
                                      map.mData,