diff options
author | 2014-03-07 03:24:41 +0000 | |
---|---|---|
committer | 2014-03-07 03:24:41 +0000 | |
commit | a5572e5bb2a2bbeeb59de0741c2527869d365a0c (patch) | |
tree | dcc5ca5a5f15d9cb45e7b4a4681900fb9c41a90d /src/core | |
parent | 1d328e46179b12149aec48ccdcf39bd853bb3ec5 (diff) |
Add a class to allocate small objects w/o extra calls to new.
Add SkSmallAllocator, a template for allocating small (as defined by the
instantiation) objects without extra calls to new. Add a helper macro to
make using it simple.
Remove SkTemplatesPriv.h, whose behavior is replaced by SkSmallAllocator.
The old SK_PLACEMENT_NEW had the following drawbacks:
- Easily confused with SkNEW_PLACEMENT.
- Requires passing around lots of void*s along with the storageSize.
- Requires using a separate class for deleting it.
- We had multiple ways Auto objects for deleting in different places.
- It always did a straight heap allocation on Windows, meaning Windows
did not get any advantages from the confusing code.
The new SkSmallAllocator simplifies things:
- It is clear about what it does.
- It takes care of the deletion in one place that is automatically
handled.
Further, the new class can be used to create more than one object. This
is in preparation for BUG=skia:1976, for which we would like to create
a new object without extra heap allocations. The plan is to create both
the blitter and the new object on the stack using the SkSmallAllocator.
Add a new test for SkSmallAllocator.
SkShader.h:
Move the private version of CreateBitmapShader to SkBitmapProcShader
(which already has the implementation) and remove the friend class
(which was only used to call this private function). This allows
SkSmallAllocator to reside in the private src/ directory.
SkBitmapProcShader:
Move CreateBitmapShader and the macro for the storage size here. With
the macro in a (private) header, the (private) headers with function
declarations (which now depend on the storage size used) can see the
macro.
Use SkSmallAllocator in CreateBitmapShader.
Change the macro to kBlitterStorageByteCount, since SkSmallAllocator
takes a byte count as its template parameter.
SkBlitter:
Use the SkSmallAllocator.
Remove Sk3DShader::fKillProc and SkAutoCallProc. Both of their
behaviors have been moved into SkSmallAllocator (SkAutoCallProc was
unnecessary anyway, because the only time we ever used it we also
called detach(), so its auto behavior never happened).
Create the Sk3DShader on the stack, if there's room.
Remove the helper version of Choose, which was unused.
SmallAllocatorTest:
Test for the new class.
The rest:
Use SkSmallAllocator.
BUG=skia:1976
R=reed@google.com, mtklein@google.com
Author: scroggo@google.com
Review URL: https://codereview.chromium.org/179343005
git-svn-id: http://skia.googlecode.com/svn/trunk@13696 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/SkBitmapProcShader.cpp | 27 | ||||
-rw-r--r-- | src/core/SkBitmapProcShader.h | 11 | ||||
-rw-r--r-- | src/core/SkBlitter.cpp | 104 | ||||
-rw-r--r-- | src/core/SkBlitter.h | 15 | ||||
-rw-r--r-- | src/core/SkBlitter_RGB16.cpp | 25 | ||||
-rw-r--r-- | src/core/SkBlitter_Sprite.cpp | 17 | ||||
-rw-r--r-- | src/core/SkCoreBlitters.h | 8 | ||||
-rw-r--r-- | src/core/SkDraw.cpp | 65 | ||||
-rw-r--r-- | src/core/SkShader.cpp | 10 | ||||
-rw-r--r-- | src/core/SkSmallAllocator.h | 148 | ||||
-rw-r--r-- | src/core/SkSpriteBlitter.h | 9 | ||||
-rw-r--r-- | src/core/SkSpriteBlitter_ARGB32.cpp | 22 | ||||
-rw-r--r-- | src/core/SkSpriteBlitter_RGB16.cpp | 38 | ||||
-rw-r--r-- | src/core/SkTemplatesPriv.h | 76 |
14 files changed, 290 insertions, 285 deletions
diff --git a/src/core/SkBitmapProcShader.cpp b/src/core/SkBitmapProcShader.cpp index 74b9e86669..55a772ec10 100644 --- a/src/core/SkBitmapProcShader.cpp +++ b/src/core/SkBitmapProcShader.cpp @@ -294,8 +294,6 @@ static bool canUseColorShader(const SkBitmap& bm, SkColor* color) { return false; } -#include "SkTemplatesPriv.h" - static bool bitmapIsTooBig(const SkBitmap& bm) { // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it // communicates between its matrix-proc and its sampler-proc. Until we can @@ -306,20 +304,29 @@ static bool bitmapIsTooBig(const SkBitmap& bm) { return bm.width() > maxSize || bm.height() > maxSize; } -SkShader* SkShader::CreateBitmapShader(const SkBitmap& src, - TileMode tmx, TileMode tmy, - void* storage, size_t storageSize) { +SkShader* CreateBitmapShader(const SkBitmap& src, SkShader::TileMode tmx, + SkShader::TileMode tmy, SkTBlitterAllocator* allocator) { SkShader* shader; SkColor color; if (src.isNull() || bitmapIsTooBig(src)) { - SK_PLACEMENT_NEW(shader, SkEmptyShader, storage, storageSize); + if (NULL == allocator) { + shader = SkNEW(SkEmptyShader); + } else { + shader = allocator->createT<SkEmptyShader>(); + } } else if (canUseColorShader(src, &color)) { - SK_PLACEMENT_NEW_ARGS(shader, SkColorShader, storage, storageSize, - (color)); + if (NULL == allocator) { + shader = SkNEW_ARGS(SkColorShader, (color)); + } else { + shader = allocator->createT<SkColorShader>(color); + } } else { - SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage, - storageSize, (src, tmx, tmy)); + if (NULL == allocator) { + shader = SkNEW_ARGS(SkBitmapProcShader, (src, tmx, tmy)); + } else { + shader = allocator->createT<SkBitmapProcShader>(src, tmx, tmy); + } } return shader; } diff --git a/src/core/SkBitmapProcShader.h b/src/core/SkBitmapProcShader.h index b7e60f1ca1..7a4ddb45ab 100644 --- a/src/core/SkBitmapProcShader.h +++ b/src/core/SkBitmapProcShader.h @@ -12,6 +12,7 @@ #include "SkShader.h" #include "SkBitmapProcState.h" +#include "SkSmallAllocator.h" class SkBitmapProcShader : public SkShader { public: @@ -48,4 +49,14 @@ private: typedef SkShader INHERITED; }; +// Commonly used allocator. It currently is only used to allocate up to 2 objects. The total +// bytes requested is calculated using one of our large shaders plus the size of an Sk3DBlitter +// in SkDraw.cpp +typedef SkSmallAllocator<2, sizeof(SkBitmapProcShader) + sizeof(void*) * 2> SkTBlitterAllocator; + +// If alloc is non-NULL, it will be used to allocate the returned SkShader, and MUST outlive +// the SkShader. +SkShader* CreateBitmapShader(const SkBitmap& src, SkShader::TileMode, SkShader::TileMode, + SkTBlitterAllocator* alloc); + #endif diff --git a/src/core/SkBlitter.cpp b/src/core/SkBlitter.cpp index 98325c0245..f925eaa7b2 100644 --- a/src/core/SkBlitter.cpp +++ b/src/core/SkBlitter.cpp @@ -11,16 +11,16 @@ #include "SkAntiRun.h" #include "SkColor.h" #include "SkColorFilter.h" +#include "SkCoreBlitters.h" #include "SkFilterShader.h" #include "SkReadBuffer.h" #include "SkWriteBuffer.h" #include "SkMask.h" #include "SkMaskFilter.h" -#include "SkTemplatesPriv.h" +#include "SkString.h" #include "SkTLazy.h" #include "SkUtils.h" #include "SkXfermode.h" -#include "SkString.h" SkBlitter::~SkBlitter() {} @@ -705,15 +705,10 @@ private: class Sk3DBlitter : public SkBlitter { public: - Sk3DBlitter(SkBlitter* proxy, Sk3DShader* shader, void (*killProc)(void*)) - : fProxy(proxy), f3DShader(shader), fKillProc(killProc) { - shader->ref(); - } - - virtual ~Sk3DBlitter() { - f3DShader->unref(); - fKillProc(fProxy); - } + Sk3DBlitter(SkBlitter* proxy, Sk3DShader* shader) + : fProxy(proxy) + , f3DShader(SkRef(shader)) + {} virtual void blitH(int x, int y, int width) { fProxy->blitH(x, y, width); @@ -747,50 +742,15 @@ public: } private: - SkBlitter* fProxy; - Sk3DShader* f3DShader; - void (*fKillProc)(void*); + // fProxy is unowned. It will be deleted by SkSmallAllocator. + SkBlitter* fProxy; + SkAutoTUnref<Sk3DShader> f3DShader; }; /////////////////////////////////////////////////////////////////////////////// #include "SkCoreBlitters.h" -class SkAutoCallProc { -public: - typedef void (*Proc)(void*); - - SkAutoCallProc(void* obj, Proc proc) - : fObj(obj), fProc(proc) {} - - ~SkAutoCallProc() { - if (fObj && fProc) { - fProc(fObj); - } - } - - void* get() const { return fObj; } - - void* detach() { - void* obj = fObj; - fObj = NULL; - return obj; - } - -private: - void* fObj; - Proc fProc; -}; -#define SkAutoCallProc(...) SK_REQUIRE_LOCAL_VAR(SkAutoCallProc) - -static void destroy_blitter(void* blitter) { - ((SkBlitter*)blitter)->~SkBlitter(); -} - -static void delete_blitter(void* blitter) { - SkDELETE((SkBlitter*)blitter); -} - static bool just_solid_color(const SkPaint& paint) { if (paint.getAlpha() == 0xFF && paint.getColorFilter() == NULL) { SkShader* shader = paint.getShader(); @@ -852,9 +812,9 @@ static XferInterp interpret_xfermode(const SkPaint& paint, SkXfermode* xfer, SkBlitter* SkBlitter::Choose(const SkBitmap& device, const SkMatrix& matrix, const SkPaint& origPaint, - void* storage, size_t storageSize, + SkTBlitterAllocator* allocator, bool drawCoverage) { - SkASSERT(storageSize == 0 || storage != NULL); + SkASSERT(allocator != NULL); SkBlitter* blitter = NULL; @@ -862,7 +822,7 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device, // (e.g. they have a bounder that always aborts the draw) if (kUnknown_SkColorType == device.colorType() || (drawCoverage && (kAlpha_8_SkColorType != device.colorType()))) { - SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize); + blitter = allocator->createT<SkNullBlitter>(); return blitter; } @@ -887,9 +847,10 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device, mode = NULL; paint.writable()->setXfermode(NULL); break; - case kSkipDrawing_XferInterp: - SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize); + case kSkipDrawing_XferInterp:{ + blitter = allocator->createT<SkNullBlitter>(); return blitter; + } default: break; } @@ -940,7 +901,7 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device, * not fail) in its destructor. */ if (shader && !shader->setContext(device, *paint, matrix)) { - SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize); + blitter = allocator->createT<SkNullBlitter>(); return blitter; } @@ -950,49 +911,40 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device, if (drawCoverage) { SkASSERT(NULL == shader); SkASSERT(NULL == paint->getXfermode()); - SK_PLACEMENT_NEW_ARGS(blitter, SkA8_Coverage_Blitter, - storage, storageSize, (device, *paint)); + blitter = allocator->createT<SkA8_Coverage_Blitter>(device, *paint); } else if (shader) { - SK_PLACEMENT_NEW_ARGS(blitter, SkA8_Shader_Blitter, - storage, storageSize, (device, *paint)); + blitter = allocator->createT<SkA8_Shader_Blitter>(device, *paint); } else { - SK_PLACEMENT_NEW_ARGS(blitter, SkA8_Blitter, - storage, storageSize, (device, *paint)); + blitter = allocator->createT<SkA8_Blitter>(device, *paint); } break; case kRGB_565_SkColorType: - blitter = SkBlitter_ChooseD565(device, *paint, storage, storageSize); + blitter = SkBlitter_ChooseD565(device, *paint, allocator); break; case kPMColor_SkColorType: if (shader) { - SK_PLACEMENT_NEW_ARGS(blitter, SkARGB32_Shader_Blitter, - storage, storageSize, (device, *paint)); + blitter = allocator->createT<SkARGB32_Shader_Blitter>(device, *paint); } else if (paint->getColor() == SK_ColorBLACK) { - SK_PLACEMENT_NEW_ARGS(blitter, SkARGB32_Black_Blitter, - storage, storageSize, (device, *paint)); + blitter = allocator->createT<SkARGB32_Black_Blitter>(device, *paint); } else if (paint->getAlpha() == 0xFF) { - SK_PLACEMENT_NEW_ARGS(blitter, SkARGB32_Opaque_Blitter, - storage, storageSize, (device, *paint)); + blitter = allocator->createT<SkARGB32_Opaque_Blitter>(device, *paint); } else { - SK_PLACEMENT_NEW_ARGS(blitter, SkARGB32_Blitter, - storage, storageSize, (device, *paint)); + blitter = allocator->createT<SkARGB32_Blitter>(device, *paint); } break; default: SkDEBUGFAIL("unsupported device config"); - SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize); + blitter = allocator->createT<SkNullBlitter>(); break; } if (shader3D) { - void (*proc)(void*) = ((void*)storage == (void*)blitter) ? destroy_blitter : delete_blitter; - SkAutoCallProc tmp(blitter, proc); - - blitter = SkNEW_ARGS(Sk3DBlitter, (blitter, shader3D, proc)); - (void)tmp.detach(); + SkBlitter* innerBlitter = blitter; + // innerBlitter was allocated by allocator, which will delete it. + blitter = allocator->createT<Sk3DBlitter>(innerBlitter, shader3D); } return blitter; } diff --git a/src/core/SkBlitter.h b/src/core/SkBlitter.h index b659fe4735..d19a34badc 100644 --- a/src/core/SkBlitter.h +++ b/src/core/SkBlitter.h @@ -11,11 +11,14 @@ #define SkBlitter_DEFINED #include "SkBitmap.h" +#include "SkBitmapProcShader.h" +#include "SkMask.h" #include "SkMatrix.h" #include "SkPaint.h" #include "SkRefCnt.h" #include "SkRegion.h" -#include "SkMask.h" +#include "SkShader.h" +#include "SkSmallAllocator.h" /** SkBlitter and its subclasses are responsible for actually writing pixels into memory. Besides efficiency, they handle clipping and antialiasing. @@ -69,21 +72,15 @@ public: */ static SkBlitter* Choose(const SkBitmap& device, const SkMatrix& matrix, - const SkPaint& paint) { - return Choose(device, matrix, paint, NULL, 0); - } - - static SkBlitter* Choose(const SkBitmap& device, - const SkMatrix& matrix, const SkPaint& paint, - void* storage, size_t storageSize, + SkTBlitterAllocator*, bool drawCoverage = false); static SkBlitter* ChooseSprite(const SkBitmap& device, const SkPaint&, const SkBitmap& src, int left, int top, - void* storage, size_t storageSize); + SkTBlitterAllocator*); ///@} private: diff --git a/src/core/SkBlitter_RGB16.cpp b/src/core/SkBlitter_RGB16.cpp index 256cbc6936..b01800b51f 100644 --- a/src/core/SkBlitter_RGB16.cpp +++ b/src/core/SkBlitter_RGB16.cpp @@ -12,7 +12,6 @@ #include "SkColorPriv.h" #include "SkDither.h" #include "SkShader.h" -#include "SkTemplatesPriv.h" #include "SkUtils.h" #include "SkXfermode.h" @@ -1013,7 +1012,9 @@ void SkRGB16_Shader_Xfermode_Blitter::blitAntiH(int x, int y, /////////////////////////////////////////////////////////////////////////////// SkBlitter* SkBlitter_ChooseD565(const SkBitmap& device, const SkPaint& paint, - void* storage, size_t storageSize) { + SkTBlitterAllocator* allocator) { + SkASSERT(allocator != NULL); + SkBlitter* blitter; SkShader* shader = paint.getShader(); SkXfermode* mode = paint.getXfermode(); @@ -1023,31 +1024,25 @@ SkBlitter* SkBlitter_ChooseD565(const SkBitmap& device, const SkPaint& paint, if (shader) { if (mode) { - SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Shader_Xfermode_Blitter, - storage, storageSize, (device, paint)); + blitter = allocator->createT<SkRGB16_Shader_Xfermode_Blitter>(device, paint); } else if (shader->canCallShadeSpan16()) { - SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Shader16_Blitter, - storage, storageSize, (device, paint)); + blitter = allocator->createT<SkRGB16_Shader16_Blitter>(device, paint); } else { - SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Shader_Blitter, - storage, storageSize, (device, paint)); + blitter = allocator->createT<SkRGB16_Shader_Blitter>(device, paint); } } else { // no shader, no xfermode, (and we always ignore colorfilter) SkColor color = paint.getColor(); if (0 == SkColorGetA(color)) { - SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize); + blitter = allocator->createT<SkNullBlitter>(); #ifdef USE_BLACK_BLITTER } else if (SK_ColorBLACK == color) { - SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Black_Blitter, storage, - storageSize, (device, paint)); + blitter = allocator->createT<SkRGB16_Black_Blitter>(device, paint); #endif } else if (0xFF == SkColorGetA(color)) { - SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Opaque_Blitter, storage, - storageSize, (device, paint)); + blitter = allocator->createT<SkRGB16_Opaque_Blitter>(device, paint); } else { - SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Blitter, storage, - storageSize, (device, paint)); + blitter = allocator->createT<SkRGB16_Blitter>(device, paint); } } diff --git a/src/core/SkBlitter_Sprite.cpp b/src/core/SkBlitter_Sprite.cpp index 86251ff59f..e15e2fcde4 100644 --- a/src/core/SkBlitter_Sprite.cpp +++ b/src/core/SkBlitter_Sprite.cpp @@ -1,4 +1,3 @@ - /* * Copyright 2006 The Android Open Source Project * @@ -6,7 +5,7 @@ * found in the LICENSE file. */ - +#include "SkSmallAllocator.h" #include "SkSpriteBlitter.h" SkSpriteBlitter::SkSpriteBlitter(const SkBitmap& source) @@ -49,11 +48,8 @@ void SkSpriteBlitter::blitMask(const SkMask&, const SkIRect& clip) { // returning null means the caller will call SkBlitter::Choose() and // have wrapped the source bitmap inside a shader -SkBlitter* SkBlitter::ChooseSprite( const SkBitmap& device, - const SkPaint& paint, - const SkBitmap& source, - int left, int top, - void* storage, size_t storageSize) { +SkBlitter* SkBlitter::ChooseSprite(const SkBitmap& device, const SkPaint& paint, + const SkBitmap& source, int left, int top, SkTBlitterAllocator* allocator) { /* We currently ignore antialiasing and filtertype, meaning we will take our special blitters regardless of these settings. Ignoring filtertype seems fine since by definition there is no scale in the matrix. Ignoring antialiasing is @@ -63,17 +59,16 @@ SkBlitter* SkBlitter::ChooseSprite( const SkBitmap& device, paint and return null if it is set, forcing the client to take the slow shader case (which does respect soft edges). */ + SkASSERT(allocator != NULL); SkSpriteBlitter* blitter; switch (device.colorType()) { case kRGB_565_SkColorType: - blitter = SkSpriteBlitter::ChooseD16(source, paint, storage, - storageSize); + blitter = SkSpriteBlitter::ChooseD16(source, paint, allocator); break; case kPMColor_SkColorType: - blitter = SkSpriteBlitter::ChooseD32(source, paint, storage, - storageSize); + blitter = SkSpriteBlitter::ChooseD32(source, paint, allocator); break; default: blitter = NULL; diff --git a/src/core/SkCoreBlitters.h b/src/core/SkCoreBlitters.h index 1605a5273d..285184050b 100644 --- a/src/core/SkCoreBlitters.h +++ b/src/core/SkCoreBlitters.h @@ -8,8 +8,11 @@ #ifndef SkCoreBlitters_DEFINED #define SkCoreBlitters_DEFINED +#include "SkBitmapProcShader.h" #include "SkBlitter.h" #include "SkBlitRow.h" +#include "SkShader.h" +#include "SkSmallAllocator.h" class SkRasterBlitter : public SkBlitter { public: @@ -175,8 +178,7 @@ private: SkBlitter::Choose(...) */ -extern SkBlitter* SkBlitter_ChooseD565(const SkBitmap& device, - const SkPaint& paint, - void* storage, size_t storageSize); +SkBlitter* SkBlitter_ChooseD565(const SkBitmap& device, const SkPaint& paint, + SkTBlitterAllocator* allocator); #endif diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp index 175abb6844..05b06453db 100644 --- a/src/core/SkDraw.cpp +++ b/src/core/SkDraw.cpp @@ -21,9 +21,9 @@ #include "SkRRect.h" #include "SkScan.h" #include "SkShader.h" +#include "SkSmallAllocator.h" #include "SkString.h" #include "SkStroke.h" -#include "SkTemplatesPriv.h" #include "SkTLazy.h" #include "SkUtils.h" @@ -32,9 +32,9 @@ #include "SkDrawProcs.h" #include "SkMatrixUtils.h" + //#define TRACE_BITMAP_DRAWS -#define kBlitterStorageLongCount (sizeof(SkBitmapProcShader) >> 2) /** Helper for allocating small blitters on the stack. */ @@ -45,16 +45,8 @@ public: } SkAutoBlitterChoose(const SkBitmap& device, const SkMatrix& matrix, const SkPaint& paint, bool drawCoverage = false) { - fBlitter = SkBlitter::Choose(device, matrix, paint, - fStorage, sizeof(fStorage), drawCoverage); - } - - ~SkAutoBlitterChoose() { - if ((void*)fBlitter == (void*)fStorage) { - fBlitter->~SkBlitter(); - } else { - SkDELETE(fBlitter); - } + fBlitter = SkBlitter::Choose(device, matrix, paint, &fAllocator, + drawCoverage); } SkBlitter* operator->() { return fBlitter; } @@ -63,13 +55,13 @@ public: void choose(const SkBitmap& device, const SkMatrix& matrix, const SkPaint& paint) { SkASSERT(!fBlitter); - fBlitter = SkBlitter::Choose(device, matrix, paint, - fStorage, sizeof(fStorage)); + fBlitter = SkBlitter::Choose(device, matrix, paint, &fAllocator); } private: - SkBlitter* fBlitter; - uint32_t fStorage[kBlitterStorageLongCount]; + // Owned by fAllocator, which will handle the delete. + SkBlitter* fBlitter; + SkTBlitterAllocator fAllocator; }; #define SkAutoBlitterChoose(...) SK_REQUIRE_LOCAL_VAR(SkAutoBlitterChoose) @@ -82,34 +74,29 @@ class SkAutoBitmapShaderInstall : SkNoncopyable { public: SkAutoBitmapShaderInstall(const SkBitmap& src, const SkPaint& paint) : fPaint(paint) /* makes a copy of the paint */ { - fPaint.setShader(SkShader::CreateBitmapShader(src, - SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, - fStorage, sizeof(fStorage))); + fPaint.setShader(CreateBitmapShader(src, SkShader::kClamp_TileMode, + SkShader::kClamp_TileMode, + &fAllocator)); // we deliberately left the shader with an owner-count of 2 SkASSERT(2 == fPaint.getShader()->getRefCnt()); } ~SkAutoBitmapShaderInstall() { - SkShader* shader = fPaint.getShader(); - // since we manually destroy shader, we insist that owners == 2 - SkASSERT(2 == shader->getRefCnt()); + // since fAllocator will destroy shader, we insist that owners == 2 + SkASSERT(2 == fPaint.getShader()->getRefCnt()); fPaint.setShader(NULL); // unref the shader by 1 - // now destroy to take care of the 2nd owner-count - if ((void*)shader == (void*)fStorage) { - shader->~SkShader(); - } else { - SkDELETE(shader); - } } // return the new paint that has the shader applied const SkPaint& paintWithShader() const { return fPaint; } private: - SkPaint fPaint; // copy of caller's paint (which we then modify) - uint32_t fStorage[kBlitterStorageLongCount]; + // copy of caller's paint (which we then modify) + SkPaint fPaint; + // Stores the shader. + SkTBlitterAllocator fAllocator; }; #define SkAutoBitmapShaderInstall(...) SK_REQUIRE_LOCAL_VAR(SkAutoBitmapShaderInstall) @@ -1323,12 +1310,11 @@ void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix, int ix = SkScalarRoundToInt(matrix.getTranslateX()); int iy = SkScalarRoundToInt(matrix.getTranslateY()); if (clipHandlesSprite(*fRC, ix, iy, bitmap)) { - uint32_t storage[kBlitterStorageLongCount]; - SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap, - ix, iy, storage, sizeof(storage)); + SkTBlitterAllocator allocator; + // blitter will be owned by the allocator. + SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap, + ix, iy, &allocator); if (blitter) { - SkAutoTPlacementDelete<SkBlitter> ad(blitter, storage); - SkIRect ir; ir.set(ix, iy, ix + bitmap.width(), iy + bitmap.height()); @@ -1378,13 +1364,12 @@ void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, paint.setStyle(SkPaint::kFill_Style); if (NULL == paint.getColorFilter() && clipHandlesSprite(*fRC, x, y, bitmap)) { - uint32_t storage[kBlitterStorageLongCount]; - SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap, - x, y, storage, sizeof(storage)); + SkTBlitterAllocator allocator; + // blitter will be owned by the allocator. + SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap, + x, y, &allocator); if (blitter) { - SkAutoTPlacementDelete<SkBlitter> ad(blitter, storage); - if (fBounder && !fBounder->doIRect(bounds)) { return; } diff --git a/src/core/SkShader.cpp b/src/core/SkShader.cpp index 47889f0d09..b06e0c26ff 100644 --- a/src/core/SkShader.cpp +++ b/src/core/SkShader.cpp @@ -5,13 +5,13 @@ * found in the LICENSE file. */ - +#include "SkBitmapProcShader.h" +#include "SkReadBuffer.h" +#include "SkMallocPixelRef.h" +#include "SkPaint.h" #include "SkScalar.h" #include "SkShader.h" -#include "SkReadBuffer.h" #include "SkWriteBuffer.h" -#include "SkPaint.h" -#include "SkMallocPixelRef.h" SkShader::SkShader() { fLocalMatrix.reset(); @@ -176,7 +176,7 @@ GrEffectRef* SkShader::asNewEffect(GrContext*, const SkPaint&) const { SkShader* SkShader::CreateBitmapShader(const SkBitmap& src, TileMode tmx, TileMode tmy) { - return SkShader::CreateBitmapShader(src, tmx, tmy, NULL, 0); + return ::CreateBitmapShader(src, tmx, tmy, NULL); } #ifdef SK_DEVELOPER diff --git a/src/core/SkSmallAllocator.h b/src/core/SkSmallAllocator.h new file mode 100644 index 0000000000..d5ebf3b7d4 --- /dev/null +++ b/src/core/SkSmallAllocator.h @@ -0,0 +1,148 @@ +/* + * Copyright 2014 Google, Inc + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSmallAllocator_DEFINED +#define SkSmallAllocator_DEFINED + +#include "SkTDArray.h" +#include "SkTypes.h" + +// Used by SkSmallAllocator to call the destructor for objects it has +// allocated. +template<typename T> void destroyT(void* ptr) { + static_cast<T*>(ptr)->~T(); +} + +/* + * Template class for allocating small objects without additional heap memory + * allocations. kMaxObjects is a hard limit on the number of objects that can + * be allocated using this class. After that, attempts to create more objects + * with this class will assert and return NULL. + * kTotalBytes is the total number of bytes provided for storage for all + * objects created by this allocator. If an object to be created is larger + * than the storage (minus storage already used), it will be allocated on the + * heap. This class's destructor will handle calling the destructor for each + * object it allocated and freeing its memory. + */ +template<uint32_t kMaxObjects, size_t kTotalBytes> +class SkSmallAllocator : public SkNoncopyable { +public: + SkSmallAllocator() + : fStorageUsed(0) + , fNumObjects(0) + {} + + ~SkSmallAllocator() { + // Destruct in reverse order, in case an earlier object points to a + // later object. + while (fNumObjects > 0) { + fNumObjects--; + Rec* rec = &fRecs[fNumObjects]; + rec->fKillProc(rec->fObj); + // Safe to do if fObj is in fStorage, since fHeapStorage will + // point to NULL. + sk_free(rec->fHeapStorage); + } + } + + /* + * Create a new object of type T. Its lifetime will be handled by this + * SkSmallAllocator. + * Each version behaves the same but takes a different number of + * arguments. + * Note: If kMaxObjects have been created by this SkSmallAllocator, NULL + * will be returned. + */ + template<typename T> + T* createT() { + void* buf = this->reserveT<T>(); + if (NULL == buf) { + return NULL; + } + SkNEW_PLACEMENT(buf, T); + return static_cast<T*>(buf); + } + + template<typename T, typename A1> T* createT(const A1& a1) { + void* buf = this->reserveT<T>(); + if (NULL == buf) { + return NULL; + } + SkNEW_PLACEMENT_ARGS(buf, T, (a1)); + return static_cast<T*>(buf); + } + + template<typename T, typename A1, typename A2> + T* createT(const A1& a1, const A2& a2) { + void* buf = this->reserveT<T>(); + if (NULL == buf) { + return NULL; + } + SkNEW_PLACEMENT_ARGS(buf, T, (a1, a2)); + return static_cast<T*>(buf); + } + + template<typename T, typename A1, typename A2, typename A3> + T* createT(const A1& a1, const A2& a2, const A3& a3) { + void* buf = this->reserveT<T>(); + if (NULL == buf) { + return NULL; + } + SkNEW_PLACEMENT_ARGS(buf, T, (a1, a2, a3)); + return static_cast<T*>(buf); + } + +private: + /* + * Helper function to provide space for one T. The space will be in + * fStorage if there is room, or on the heap otherwise. Either way, this + * class will call ~T() in its destructor and free the heap allocation if + * necessary. + */ + template<typename T> void* reserveT() { + SkASSERT(fNumObjects < kMaxObjects); + if (kMaxObjects == fNumObjects) { + return NULL; + } + const size_t storageRemaining = SkAlign4(kTotalBytes) - fStorageUsed; + const size_t storageRequired = SkAlign4(sizeof(T)); + Rec* rec = &fRecs[fNumObjects]; + if (storageRequired > storageRemaining) { + // Allocate on the heap. Ideally we want to avoid this situation, + // but we're not sure we can catch all callers, so handle it but + // assert false in debug mode. + SkASSERT(false); + rec->fHeapStorage = sk_malloc_throw(storageRequired); + rec->fObj = static_cast<void*>(rec->fHeapStorage); + } else { + // There is space in fStorage. + rec->fHeapStorage = NULL; + SkASSERT(SkIsAlign4(fStorageUsed)); + rec->fObj = static_cast<void*>(fStorage + (fStorageUsed / 4)); + fStorageUsed += storageRequired; + } + rec->fKillProc = destroyT<T>; + fNumObjects++; + return rec->fObj; + } + +private: + struct Rec { + void* fObj; + void* fHeapStorage; + void (*fKillProc)(void*); + }; + + // Number of bytes used so far. + size_t fStorageUsed; + // Pad the storage size to be 4-byte aligned. + uint32_t fStorage[SkAlign4(kTotalBytes) >> 2]; + uint32_t fNumObjects; + Rec fRecs[kMaxObjects]; +}; + +#endif // SkSmallAllocator_DEFINED diff --git a/src/core/SkSpriteBlitter.h b/src/core/SkSpriteBlitter.h index ae79afe1d8..f69a55a2a0 100644 --- a/src/core/SkSpriteBlitter.h +++ b/src/core/SkSpriteBlitter.h @@ -10,8 +10,11 @@ #ifndef SkSpriteBlitter_DEFINED #define SkSpriteBlitter_DEFINED -#include "SkBlitter.h" #include "SkBitmap.h" +#include "SkBitmapProcShader.h" +#include "SkBlitter.h" +#include "SkShader.h" +#include "SkSmallAllocator.h" class SkPaint; @@ -32,9 +35,9 @@ public: #endif static SkSpriteBlitter* ChooseD16(const SkBitmap& source, const SkPaint&, - void* storage, size_t storageSize); + SkTBlitterAllocator*); static SkSpriteBlitter* ChooseD32(const SkBitmap& source, const SkPaint&, - void* storage, size_t storageSize); + SkTBlitterAllocator*); protected: const SkBitmap* fDevice; diff --git a/src/core/SkSpriteBlitter_ARGB32.cpp b/src/core/SkSpriteBlitter_ARGB32.cpp index 3e8612dda3..b05e5033e4 100644 --- a/src/core/SkSpriteBlitter_ARGB32.cpp +++ b/src/core/SkSpriteBlitter_ARGB32.cpp @@ -263,11 +263,10 @@ public: /////////////////////////////////////////////////////////////////////////////// -#include "SkTemplatesPriv.h" +SkSpriteBlitter* SkSpriteBlitter::ChooseD32(const SkBitmap& source, const SkPaint& paint, + SkTBlitterAllocator* allocator) { + SkASSERT(allocator != NULL); -SkSpriteBlitter* SkSpriteBlitter::ChooseD32(const SkBitmap& source, - const SkPaint& paint, - void* storage, size_t storageSize) { if (paint.getMaskFilter() != NULL) { return NULL; } @@ -283,27 +282,22 @@ SkSpriteBlitter* SkSpriteBlitter::ChooseD32(const SkBitmap& source, return NULL; // we only have opaque sprites } if (xfermode || filter) { - SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D32_S4444_XferFilter, - storage, storageSize, (source, paint)); + blitter = allocator->createT<Sprite_D32_S4444_XferFilter>(source, paint); } else if (source.isOpaque()) { - SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D32_S4444_Opaque, - storage, storageSize, (source)); + blitter = allocator->createT<Sprite_D32_S4444_Opaque>(source); } else { - SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D32_S4444, - storage, storageSize, (source)); + blitter = allocator->createT<Sprite_D32_S4444>(source); } break; case kPMColor_SkColorType: if (xfermode || filter) { if (255 == alpha) { // this can handle xfermode or filter, but not alpha - SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D32_S32A_XferFilter, - storage, storageSize, (source, paint)); + blitter = allocator->createT<Sprite_D32_S32A_XferFilter>(source, paint); } } else { // this can handle alpha, but not xfermode or filter - SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D32_S32, - storage, storageSize, (source, alpha)); + blitter = allocator->createT<Sprite_D32_S32>(source, alpha); } break; default: diff --git a/src/core/SkSpriteBlitter_RGB16.cpp b/src/core/SkSpriteBlitter_RGB16.cpp index 7428c8a74a..74c1961dbd 100644 --- a/src/core/SkSpriteBlitter_RGB16.cpp +++ b/src/core/SkSpriteBlitter_RGB16.cpp @@ -306,11 +306,11 @@ private: /////////////////////////////////////////////////////////////////////////////// -#include "SkTemplatesPriv.h" +SkSpriteBlitter* SkSpriteBlitter::ChooseD16(const SkBitmap& source, const SkPaint& paint, + SkTBlitterAllocator* allocator) { + + SkASSERT(allocator != NULL); -SkSpriteBlitter* SkSpriteBlitter::ChooseD16(const SkBitmap& source, - const SkPaint& paint, - void* storage, size_t storageSize) { if (paint.getMaskFilter() != NULL) { // may add cases for this return NULL; } @@ -325,26 +325,22 @@ SkSpriteBlitter* SkSpriteBlitter::ChooseD16(const SkBitmap& source, unsigned alpha = paint.getAlpha(); switch (source.colorType()) { - case kPMColor_SkColorType: - SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S32_BlitRowProc, - storage, storageSize, (source)); + case kPMColor_SkColorType: { + blitter = allocator->createT<Sprite_D16_S32_BlitRowProc>(source); break; + } case kARGB_4444_SkColorType: if (255 == alpha) { - SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S4444_Opaque, - storage, storageSize, (source)); + blitter = allocator->createT<Sprite_D16_S4444_Opaque>(source); } else { - SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S4444_Blend, - storage, storageSize, (source, alpha >> 4)); + blitter = allocator->createT<Sprite_D16_S4444_Blend>(source, alpha >> 4); } break; case kRGB_565_SkColorType: if (255 == alpha) { - SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S16_Opaque, - storage, storageSize, (source)); + blitter = allocator->createT<Sprite_D16_S16_Opaque>(source); } else { - SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S16_Blend, - storage, storageSize, (source, alpha)); + blitter = allocator->createT<Sprite_D16_S16_Blend>(source, alpha); } break; case kIndex_8_SkColorType: @@ -354,19 +350,15 @@ SkSpriteBlitter* SkSpriteBlitter::ChooseD16(const SkBitmap& source, } if (source.isOpaque()) { if (255 == alpha) { - SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_SIndex8_Opaque, - storage, storageSize, (source)); + blitter = allocator->createT<Sprite_D16_SIndex8_Opaque>(source); } else { - SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_SIndex8_Blend, - storage, storageSize, (source, alpha)); + blitter = allocator->createT<Sprite_D16_SIndex8_Blend>(source, alpha); } } else { if (255 == alpha) { - SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_SIndex8A_Opaque, - storage, storageSize, (source)); + blitter = allocator->createT<Sprite_D16_SIndex8A_Opaque>(source); } else { - SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_SIndex8A_Blend, - storage, storageSize, (source, alpha)); + blitter = allocator->createT<Sprite_D16_SIndex8A_Blend>(source, alpha); } } break; diff --git a/src/core/SkTemplatesPriv.h b/src/core/SkTemplatesPriv.h deleted file mode 100644 index 79ae609335..0000000000 --- a/src/core/SkTemplatesPriv.h +++ /dev/null @@ -1,76 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkTemplatesPriv_DEFINED -#define SkTemplatesPriv_DEFINED - -#include "SkTemplates.h" - -//////////////////////////////////////////////////////////////////////////////// - -#ifdef SK_BUILD_FOR_WIN32 - #define SK_PLACEMENT_NEW(result, classname, storage, storageSize) \ - result = SkNEW(classname) - - #define SK_PLACEMENT_NEW_ARGS(result, classname, storage, storageSize, args) \ - result = SkNEW_ARGS(classname, args) -#else - #include <new> - #define SK_PLACEMENT_NEW(result, classname, storage, storagesize) \ - do { \ - if (storagesize) \ - { \ - SkASSERT(storageSize >= sizeof(classname)); \ - result = new(storage) classname; \ - } \ - else \ - result = SkNEW(classname); \ - } while (0) - - #define SK_PLACEMENT_NEW_ARGS(result, classname, storage, storagesize, args) \ - do { \ - if (storagesize) \ - { \ - SkASSERT(storageSize >= sizeof(classname)); \ - result = new(storage) classname args; \ - } \ - else \ - result = SkNEW_ARGS(classname, args); \ - } while (0) -#endif - -//////////////////////////////////////////////////////////////////////////////// - -template <class T> class SkAutoTPlacementDelete { -public: - SkAutoTPlacementDelete(T* obj, void* storage) : fObj(obj), fStorage(storage) - { - } - ~SkAutoTPlacementDelete() - { - if (fObj) - { - if (fObj == fStorage) - fObj->~T(); - else - delete fObj; - } - } - T* detach() - { - T* obj = fObj; - fObj = NULL; - return obj; - } -private: - T* fObj; - void* fStorage; -}; - -#endif |