From e58cfe332e4371d1ecf5da6c0e0ef06f848b9160 Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Wed, 10 Sep 2014 17:54:16 -0400 Subject: [PATCH] Bug 1063733 - Optimize DataSourceSurface allocation, r=bas,seth --- dom/base/ImageEncoder.cpp | 3 +-- gfx/2d/2D.h | 8 ++++---- gfx/2d/DataSurfaceHelpers.h | 2 ++ gfx/2d/DrawTargetCG.cpp | 3 +-- gfx/2d/Factory.cpp | 10 ++++++---- gfx/2d/FilterNodeSoftware.cpp | 14 ++++---------- gfx/2d/SourceSurfaceRawData.cpp | 10 ++++++---- gfx/2d/SourceSurfaceRawData.h | 6 ++++-- gfx/2d/Tools.h | 12 ++++++++---- image/src/RasterImage.cpp | 4 +++- image/src/imgTools.cpp | 3 ++- 11 files changed, 41 insertions(+), 34 deletions(-) diff --git a/dom/base/ImageEncoder.cpp b/dom/base/ImageEncoder.cpp index a27c7199cb7..17fdd3727e1 100644 --- a/dom/base/ImageEncoder.cpp +++ b/dom/base/ImageEncoder.cpp @@ -416,12 +416,11 @@ ImageEncoder::ExtractDataInternal(const nsAString& aType, RefPtr emptyCanvas = Factory::CreateDataSourceSurfaceWithStride(IntSize(aSize.width, aSize.height), SurfaceFormat::B8G8R8A8, - 4 * aSize.width); + 4 * aSize.width, true); if (NS_WARN_IF(!emptyCanvas)) { return NS_ERROR_INVALID_ARG; } - ClearDataSourceSurface(emptyCanvas); DataSourceSurface::MappedSurface map; if (!emptyCanvas->Map(DataSourceSurface::MapType::WRITE, &map)) { return NS_ERROR_INVALID_ARG; diff --git a/gfx/2d/2D.h b/gfx/2d/2D.h index 474cf567aa7..99c51485ee8 100644 --- a/gfx/2d/2D.h +++ b/gfx/2d/2D.h @@ -1117,20 +1117,20 @@ public: * 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. The caller is responsible for handing the case where nullptr - * is returned. + * is returned. The surface is not zeroed unless requested. */ static TemporaryRef - 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 caller is responsible for handling the case - * where nullptr is returned. + * where nullptr is returned. The surface is not zeroed unless requested. */ static TemporaryRef - 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 diff --git a/gfx/2d/DataSurfaceHelpers.h b/gfx/2d/DataSurfaceHelpers.h index 7cb58f1b0de..f48e5f66a94 100644 --- a/gfx/2d/DataSurfaceHelpers.h +++ b/gfx/2d/DataSurfaceHelpers.h @@ -48,6 +48,8 @@ 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); diff --git a/gfx/2d/DrawTargetCG.cpp b/gfx/2d/DrawTargetCG.cpp index 49ad08f19b2..5b49666dd5a 100644 --- a/gfx/2d/DrawTargetCG.cpp +++ b/gfx/2d/DrawTargetCG.cpp @@ -1358,9 +1358,8 @@ DrawTargetCG::Init(BackendType aType, } 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(mData); - memset(aData, 0, bufLen); } mSize = aSize; diff --git a/gfx/2d/Factory.cpp b/gfx/2d/Factory.cpp index 8b39b7d9f9c..ca809e93319 100644 --- a/gfx/2d/Factory.cpp +++ b/gfx/2d/Factory.cpp @@ -700,7 +700,8 @@ Factory::CreateWrappingDataSourceSurface(uint8_t *aData, int32_t aStride, TemporaryRef Factory::CreateDataSourceSurface(const IntSize &aSize, - SurfaceFormat aFormat) + SurfaceFormat aFormat, + bool aZero) { if (!CheckSurfaceSize(aSize)) { gfxWarning() << "CreateDataSourceSurface failed with bad size"; @@ -708,7 +709,7 @@ Factory::CreateDataSourceSurface(const IntSize &aSize, } RefPtr newSurf = new SourceSurfaceAlignedRawData(); - if (newSurf->Init(aSize, aFormat)) { + if (newSurf->Init(aSize, aFormat, aZero)) { return newSurf.forget(); } @@ -719,7 +720,8 @@ Factory::CreateDataSourceSurface(const IntSize &aSize, TemporaryRef Factory::CreateDataSourceSurfaceWithStride(const IntSize &aSize, SurfaceFormat aFormat, - int32_t aStride) + int32_t aStride, + bool aZero) { if (aStride < aSize.width * BytesPerPixel(aFormat)) { gfxWarning() << "CreateDataSourceSurfaceWithStride failed with bad stride"; @@ -727,7 +729,7 @@ Factory::CreateDataSourceSurfaceWithStride(const IntSize &aSize, } RefPtr newSurf = new SourceSurfaceAlignedRawData(); - if (newSurf->InitWithStride(aSize, aFormat, aStride)) { + if (newSurf->InitWithStride(aSize, aFormat, aStride, aZero)) { return newSurf.forget(); } diff --git a/gfx/2d/FilterNodeSoftware.cpp b/gfx/2d/FilterNodeSoftware.cpp index 0f5e7827a53..8972ed59b54 100644 --- a/gfx/2d/FilterNodeSoftware.cpp +++ b/gfx/2d/FilterNodeSoftware.cpp @@ -492,16 +492,13 @@ GetDataSurfaceInRect(SourceSurface *aSurface, IntRect intersectInDestSpace = intersect - aDestRect.TopLeft(); SurfaceFormat format = aSurface ? aSurface->GetFormat() : SurfaceFormat(SurfaceFormat::B8G8R8A8); + bool clear = aEdgeMode == EDGE_MODE_NONE && !aSurfaceRect.Contains(aDestRect); RefPtr target = - Factory::CreateDataSourceSurface(aDestRect.Size(), format); + Factory::CreateDataSourceSurface(aDestRect.Size(), format, clear); if (MOZ2D_WARN_IF(!target)) { return nullptr; } - if (aEdgeMode == EDGE_MODE_NONE && !aSurfaceRect.Contains(aDestRect)) { - ClearDataSourceSurface(target); - } - if (!aSurface) { return target.forget(); } @@ -2371,11 +2368,10 @@ FilterNodeConvolveMatrixSoftware::DoRender(const IntRect& aRect, DebugOnlyAutoColorSamplingAccessControl accessControl(input); RefPtr target = - Factory::CreateDataSourceSurface(aRect.Size(), SurfaceFormat::B8G8R8A8); + Factory::CreateDataSourceSurface(aRect.Size(), SurfaceFormat::B8G8R8A8, true); if (MOZ2D_WARN_IF(!target)) { return nullptr; } - ClearDataSourceSurface(target); IntPoint offset = aRect.TopLeft() - srcRect.TopLeft(); @@ -2776,15 +2772,13 @@ FilterNodeCompositeSoftware::Render(const IntRect& aRect) RefPtr start = GetInputDataSourceSurface(IN_COMPOSITE_IN_START, aRect, NEED_COLOR_CHANNELS); RefPtr dest = - Factory::CreateDataSourceSurface(aRect.Size(), SurfaceFormat::B8G8R8A8); + Factory::CreateDataSourceSurface(aRect.Size(), SurfaceFormat::B8G8R8A8, !start); if (MOZ2D_WARN_IF(!dest)) { return nullptr; } if (start) { CopyRect(start, dest, aRect - aRect.TopLeft(), IntPoint()); - } else { - ClearDataSourceSurface(dest); } for (size_t inputIndex = 1; inputIndex < NumberOfSetInputs(); inputIndex++) { diff --git a/gfx/2d/SourceSurfaceRawData.cpp b/gfx/2d/SourceSurfaceRawData.cpp index 92be3baa33b..901a5f56766 100644 --- a/gfx/2d/SourceSurfaceRawData.cpp +++ b/gfx/2d/SourceSurfaceRawData.cpp @@ -44,7 +44,8 @@ SourceSurfaceRawData::GuaranteePersistance() bool SourceSurfaceAlignedRawData::Init(const IntSize &aSize, - SurfaceFormat aFormat) + SurfaceFormat aFormat, + bool aZero) { mFormat = aFormat; mStride = GetAlignedStride<16>(aSize.width * BytesPerPixel(aFormat)); @@ -53,7 +54,7 @@ SourceSurfaceAlignedRawData::Init(const IntSize &aSize, 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(); @@ -66,7 +67,8 @@ SourceSurfaceAlignedRawData::Init(const IntSize &aSize, bool SourceSurfaceAlignedRawData::InitWithStride(const IntSize &aSize, SurfaceFormat aFormat, - int32_t aStride) + int32_t aStride, + bool aZero) { mFormat = aFormat; mStride = aStride; @@ -75,7 +77,7 @@ SourceSurfaceAlignedRawData::InitWithStride(const IntSize &aSize, 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(); diff --git a/gfx/2d/SourceSurfaceRawData.h b/gfx/2d/SourceSurfaceRawData.h index 13fd2f0c55b..13a84e5d017 100644 --- a/gfx/2d/SourceSurfaceRawData.h +++ b/gfx/2d/SourceSurfaceRawData.h @@ -56,10 +56,12 @@ public: 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 mArray; diff --git a/gfx/2d/Tools.h b/gfx/2d/Tools.h index 33ad6076fbd..2df3f31b84f 100644 --- a/gfx/2d/Tools.h +++ b/gfx/2d/Tools.h @@ -103,11 +103,11 @@ struct AlignedArray { } - explicit MOZ_ALWAYS_INLINE AlignedArray(size_t aCount) + explicit MOZ_ALWAYS_INLINE AlignedArray(size_t aCount, bool aZero = false) : mStorage(nullptr) , mCount(0) { - Realloc(aCount); + Realloc(aCount, aZero); } MOZ_ALWAYS_INLINE ~AlignedArray() @@ -138,7 +138,7 @@ struct AlignedArray 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 = @@ -151,7 +151,11 @@ struct AlignedArray } // 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(calloc(1, storageByteCount.value())); + } else { + mStorage = new (std::nothrow) uint8_t[storageByteCount.value()]; + } if (!mStorage) { mStorage = nullptr; mPtr = nullptr; diff --git a/image/src/RasterImage.cpp b/image/src/RasterImage.cpp index e5a1d38688d..9ab2c7aff2b 100644 --- a/image/src/RasterImage.cpp +++ b/image/src/RasterImage.cpp @@ -863,7 +863,9 @@ RasterImage::CopyFrame(uint32_t aWhichFrame, IntSize size(mSize.width, mSize.height); RefPtr surf = - Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8); + Factory::CreateDataSourceSurface(size, + SurfaceFormat::B8G8R8A8, + /* aZero = */ true); if (NS_WARN_IF(!surf)) { return nullptr; } diff --git a/image/src/imgTools.cpp b/image/src/imgTools.cpp index 6e792295bd1..7ded938536a 100644 --- a/image/src/imgTools.cpp +++ b/image/src/imgTools.cpp @@ -274,7 +274,8 @@ NS_IMETHODIMP imgTools::EncodeCroppedImage(imgIContainer *aContainer, RefPtr dataSurface = Factory::CreateDataSourceSurface(IntSize(aWidth, aHeight), - SurfaceFormat::B8G8R8A8); + SurfaceFormat::B8G8R8A8, + /* aZero = */ true); if (NS_WARN_IF(!dataSurface)) { return NS_ERROR_FAILURE; }