Introduce SkArenaAlloc - should be fast for POD types and RAII for types with dtors.
- Implementation. - Use in SkLinearPipeline. TBR=mtklein@google.com Change-Id: Ia8efd09b2f3139a57182889ba84d1610eae92749 Reviewed-on: https://skia-review.googlesource.com/6352 Reviewed-by: Herb Derby <herb@google.com> Commit-Queue: Herb Derby <herb@google.com>
This commit is contained in:
parent
7704754049
commit
6ff51aedda
@ -149,8 +149,7 @@ struct SkBitmapFPGeneral final : public CommonBitmapFPBenchmark {
|
||||
|
||||
|
||||
char storage[600];
|
||||
SkFixedAlloc fixedAlloc{storage, sizeof(storage)};
|
||||
SkFallbackAlloc allocator{&fixedAlloc};
|
||||
SkArenaAlloc allocator{storage, sizeof(storage), 512};
|
||||
SkLinearBitmapPipeline pipeline{
|
||||
fInvert, filterQuality, fXTile, fYTile, SK_ColorBLACK, srcPixmap, &allocator};
|
||||
|
||||
|
@ -117,8 +117,7 @@ static void draw_rect_fp(SkCanvas* canvas, const SkRect& r, SkColor c, const SkM
|
||||
auto procN = SkXfermode::GetD32Proc(SkBlendMode::kSrcOver, flags);
|
||||
|
||||
char storage[512];
|
||||
SkFixedAlloc fixedAlloc{storage, sizeof(storage)};
|
||||
SkFallbackAlloc allocator{&fixedAlloc};
|
||||
SkArenaAlloc allocator{storage, sizeof(storage)};
|
||||
SkLinearBitmapPipeline pipeline{
|
||||
inv, filterQuality,
|
||||
SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode,
|
||||
|
@ -171,8 +171,7 @@ public:
|
||||
|
||||
private:
|
||||
char fStorage[512 + 96];
|
||||
SkFixedAlloc fFixedAlloc {fStorage, sizeof(fStorage)};
|
||||
SkFallbackAlloc fAllocator {&fFixedAlloc};
|
||||
SkArenaAlloc fAllocator {fStorage, sizeof(fStorage)};
|
||||
SkLinearBitmapPipeline* fShaderPipeline;
|
||||
SkLinearBitmapPipeline* fBlitterPipeline;
|
||||
SkXfermode::D32Proc fSrcModeProc;
|
||||
|
@ -7,6 +7,8 @@
|
||||
|
||||
#include "SkFixedAlloc.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
SkFixedAlloc::SkFixedAlloc(void* ptr, size_t len)
|
||||
: fStorage((char*)ptr), fCursor(fStorage), fEnd(fStorage + len) {}
|
||||
|
||||
@ -49,3 +51,136 @@ void SkFallbackAlloc::reset() {
|
||||
}
|
||||
fFixedAlloc->reset();
|
||||
}
|
||||
|
||||
struct Skipper {
|
||||
char* operator()(char* objEnd, ptrdiff_t size) { return objEnd + size; }
|
||||
};
|
||||
|
||||
struct NextBlock {
|
||||
char* operator()(char* objEnd, ptrdiff_t size) { delete [] objEnd; return objEnd + size; }
|
||||
};
|
||||
|
||||
SkArenaAlloc::SkArenaAlloc(char* block, size_t size, size_t extraSize)
|
||||
: fDtorCursor{block}
|
||||
, fCursor {block}
|
||||
, fEnd {block + size}
|
||||
, fExtraSize {extraSize}
|
||||
{
|
||||
if (size < sizeof(Footer)) {
|
||||
fEnd = fCursor = fDtorCursor = nullptr;
|
||||
}
|
||||
|
||||
if (fCursor != nullptr) {
|
||||
this->installFooter(EndChain, 0);
|
||||
}
|
||||
}
|
||||
|
||||
SkArenaAlloc::~SkArenaAlloc() {
|
||||
this->reset();
|
||||
}
|
||||
|
||||
void SkArenaAlloc::reset() {
|
||||
char* releaser = fDtorCursor;
|
||||
while (releaser != nullptr) {
|
||||
releaser = this->callFooterAction(releaser);
|
||||
}
|
||||
}
|
||||
|
||||
void SkArenaAlloc::installFooter(FooterAction* releaser, ptrdiff_t padding) {
|
||||
ptrdiff_t releaserDiff = (char *)releaser - (char *)EndChain;
|
||||
ptrdiff_t footerData = SkLeftShift((int64_t)releaserDiff, 5) | padding;
|
||||
if (padding >= 32 || !SkTFitsIn<int32_t>(footerData)) {
|
||||
// Footer data will not fit.
|
||||
SkFAIL("Constraints are busted.");
|
||||
}
|
||||
|
||||
Footer footer = (Footer)(footerData);
|
||||
memmove(fCursor, &footer, sizeof(Footer));
|
||||
fCursor += sizeof(Footer);
|
||||
fDtorCursor = fCursor;
|
||||
}
|
||||
|
||||
void SkArenaAlloc::ensureSpace(size_t size, size_t alignment) {
|
||||
constexpr size_t headerSize = sizeof(Footer) + sizeof(ptrdiff_t);
|
||||
// The chrome c++ library we use does not define std::max_align_t.
|
||||
// This must be conservative to add the right amount of extra memory to handle the alignment
|
||||
// padding.
|
||||
constexpr size_t alignof_max_align_t = 8;
|
||||
auto objSizeAndOverhead = size + headerSize + sizeof(Footer);
|
||||
if (alignment > alignof_max_align_t) {
|
||||
objSizeAndOverhead += alignment - 1;
|
||||
}
|
||||
|
||||
auto allocationSize = std::max(objSizeAndOverhead, fExtraSize);
|
||||
|
||||
// Round up to a nice size. If > 32K align to 4K boundary else up to max_align_t. The > 32K
|
||||
// heuristic is from the JEMalloc behavior.
|
||||
{
|
||||
size_t mask = allocationSize > (1 << 15) ? (1 << 12) - 1 : 32 - 1;
|
||||
allocationSize = (allocationSize + mask) & ~mask;
|
||||
}
|
||||
|
||||
char* newBlock = new char[allocationSize];
|
||||
|
||||
auto previousDtor = fDtorCursor;
|
||||
fCursor = newBlock;
|
||||
fDtorCursor = newBlock;
|
||||
fEnd = fCursor + allocationSize;
|
||||
this->installIntFooter<NextBlock>(previousDtor - fCursor, 0);
|
||||
}
|
||||
|
||||
char* SkArenaAlloc::allocObject(size_t size, size_t alignment) {
|
||||
size_t mask = alignment - 1;
|
||||
char* objStart = (char*)((uintptr_t)(fCursor + mask) & ~mask);
|
||||
if (objStart + size > fEnd) {
|
||||
this->ensureSpace(size, alignment);
|
||||
objStart = (char*)((uintptr_t)(fCursor + mask) & ~mask);
|
||||
}
|
||||
return objStart;
|
||||
}
|
||||
|
||||
// * sizeAndFooter - the memory for the footer in addition to the size for the object.
|
||||
// * alignment - alignment needed by the object.
|
||||
char* SkArenaAlloc::allocObjectWithFooter(size_t sizeIncludingFooter, size_t alignment) {
|
||||
size_t mask = alignment - 1;
|
||||
|
||||
restart:
|
||||
size_t skipOverhead = 0;
|
||||
bool needsSkipFooter = fCursor != fDtorCursor;
|
||||
if (needsSkipFooter) {
|
||||
size_t skipSize = SkTFitsIn<int32_t>(fDtorCursor - fCursor)
|
||||
? sizeof(int32_t)
|
||||
: sizeof(ptrdiff_t);
|
||||
skipOverhead = sizeof(Footer) + skipSize;
|
||||
}
|
||||
char* objStart = (char*)((uintptr_t)(fCursor + skipOverhead + mask) & ~mask);
|
||||
size_t totalSize = sizeIncludingFooter + skipOverhead;
|
||||
|
||||
if (objStart + totalSize > fEnd) {
|
||||
this->ensureSpace(totalSize, alignment);
|
||||
goto restart;
|
||||
}
|
||||
|
||||
SkASSERT(objStart + totalSize <= fEnd);
|
||||
|
||||
// Install a skip footer if needed, thus terminating a run of POD data. The calling code is
|
||||
// responsible for installing the footer after the object.
|
||||
if (needsSkipFooter) {
|
||||
this->installIntFooter<Skipper>(fDtorCursor - fCursor, 0);
|
||||
}
|
||||
|
||||
return objStart;
|
||||
}
|
||||
|
||||
char* SkArenaAlloc::callFooterAction(char* end) {
|
||||
Footer footer;
|
||||
memcpy(&footer, end - sizeof(Footer), sizeof(Footer));
|
||||
|
||||
FooterAction* releaser = (FooterAction*)((char*)EndChain + (footer >> 5));
|
||||
ptrdiff_t padding = footer & 31;
|
||||
|
||||
return releaser(end) - padding;
|
||||
}
|
||||
|
||||
char* SkArenaAlloc::EndChain(char*) { return nullptr; }
|
||||
|
||||
|
@ -10,7 +10,9 @@
|
||||
|
||||
#include "SkTFitsIn.h"
|
||||
#include "SkTypes.h"
|
||||
#include <cstddef>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@ -96,13 +98,14 @@ public:
|
||||
return new (ptr) T(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Destroys the last object allocated and frees any space it used in the SkFixedAlloc.
|
||||
void undo();
|
||||
|
||||
// Destroys all objects and frees all space in the SkFixedAlloc.
|
||||
void reset();
|
||||
|
||||
private:
|
||||
// Destroys the last object allocated and frees any space it used in the SkFixedAlloc.
|
||||
void undo();
|
||||
|
||||
struct HeapAlloc {
|
||||
void (*deleter)(char*);
|
||||
char* ptr;
|
||||
@ -112,4 +115,183 @@ private:
|
||||
std::vector<HeapAlloc> fHeapAllocs;
|
||||
};
|
||||
|
||||
// SkArenaAlloc allocates object and destroys the allocated objects when destroyed. It's designed
|
||||
// to minimize the number of underlying block allocations. SkArenaAlloc allocates first out of an
|
||||
// (optional) user-provided block of memory, and when that's exhausted it allocates on the heap,
|
||||
// starting with an allocation of extraSize bytes. If your data (plus a small overhead) fits in
|
||||
// the user-provided block, SkArenaAlloc never uses the heap, and if it fits in extraSize bytes,
|
||||
// it'll use the heap only once. If you pass extraSize = 0, it allocates blocks for each call to
|
||||
// make<T>.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// char block[mostCasesSize];
|
||||
// SkArenaAlloc arena(block, almostAllCasesSize);
|
||||
//
|
||||
// If mostCasesSize is too large for the stack, you can use the following pattern.
|
||||
//
|
||||
// std::unique_ptr<char[]> block{new char[mostCasesSize]};
|
||||
// SkArenaAlloc arena(block.get(), mostCasesSize, almostAllCasesSize);
|
||||
//
|
||||
// If the program only sometimes allocates memory, use the following.
|
||||
//
|
||||
// SkArenaAlloc arena(nullptr, 0, almostAllCasesSize);
|
||||
//
|
||||
// The storage does not necessarily need to be on the stack. Embedding the storage in a class also
|
||||
// works.
|
||||
//
|
||||
// class Foo {
|
||||
// char storage[mostCasesSize];
|
||||
// SkArenaAlloc arena (storage, almostAllCasesSize);
|
||||
// };
|
||||
//
|
||||
// In addition, the system is optimized to handle POD data including arrays of PODs (where
|
||||
// POD is really data with no destructors). For POD data it has zero overhead per item, and a
|
||||
// typical block overhead of 8 bytes. For non-POD objects there is a per item overhead of 4 bytes.
|
||||
// For arrays of non-POD objects there is a per array overhead of typically 8 bytes. There is an
|
||||
// addition overhead when switching from POD data to non-POD data of typically 8 bytes.
|
||||
class SkArenaAlloc {
|
||||
public:
|
||||
SkArenaAlloc(char* block, size_t size, size_t extraSize = 0);
|
||||
|
||||
template <size_t kSize>
|
||||
SkArenaAlloc(char (&block)[kSize], size_t extraSize = 0)
|
||||
: SkArenaAlloc(block, kSize, extraSize)
|
||||
{}
|
||||
|
||||
~SkArenaAlloc();
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T* make(Args&&... args) {
|
||||
char* objStart;
|
||||
if (std::is_trivially_destructible<T>::value) {
|
||||
objStart = this->allocObject(sizeof(T), alignof(T));
|
||||
fCursor = objStart + sizeof(T);
|
||||
} else {
|
||||
objStart = this->allocObjectWithFooter(sizeof(T) + sizeof(Footer), alignof(T));
|
||||
size_t padding = objStart - fCursor;
|
||||
|
||||
// Advance to end of object to install footer.
|
||||
fCursor = objStart + sizeof(T);
|
||||
FooterAction* releaser = [](char* objEnd) {
|
||||
char* objStart = objEnd - (sizeof(T) + sizeof(Footer));
|
||||
((T*)objStart)->~T();
|
||||
return objStart;
|
||||
};
|
||||
this->installFooter(releaser, padding);
|
||||
}
|
||||
|
||||
// This must be last to make objects with nested use of this allocator work.
|
||||
return new(objStart) T(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* makeArrayDefault(size_t count) {
|
||||
char* objStart = this->commonArrayAlloc<T>(count);
|
||||
|
||||
// If T is primitive then no initialization takes place.
|
||||
return new(objStart) T[count];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* makeArray(size_t count) {
|
||||
char* objStart = this->commonArrayAlloc<T>(count);
|
||||
|
||||
// If T is primitive then the memory is initialized. For example, an array of chars will
|
||||
// be zeroed.
|
||||
return new(objStart) T[count]();
|
||||
}
|
||||
|
||||
// Destroy all allocated objects, free any heap allocations.
|
||||
void reset();
|
||||
|
||||
private:
|
||||
using Footer = int32_t;
|
||||
using FooterAction = char* (char*);
|
||||
|
||||
void installFooter(FooterAction* releaser, ptrdiff_t padding);
|
||||
|
||||
// N.B. Action is different than FooterAction. FooterAction expects the end of the Footer,
|
||||
// and returns the start of the object. An Action expects the end of the *Object* and returns
|
||||
// the start of the object.
|
||||
template<typename Action>
|
||||
void installIntFooter(ptrdiff_t size, ptrdiff_t padding) {
|
||||
if (SkTFitsIn<int32_t>(size)) {
|
||||
int32_t smallSize = static_cast<int32_t>(size);
|
||||
memmove(fCursor, &smallSize, sizeof(int32_t));
|
||||
fCursor += sizeof(int32_t);
|
||||
this->installFooter(
|
||||
[](char* footerEnd) {
|
||||
char* objEnd = footerEnd - (sizeof(Footer) + sizeof(int32_t));
|
||||
int32_t data;
|
||||
memmove(&data, objEnd, sizeof(int32_t));
|
||||
return Action()(objEnd, data);
|
||||
},
|
||||
padding);
|
||||
} else {
|
||||
memmove(fCursor, &size, sizeof(ptrdiff_t));
|
||||
fCursor += sizeof(ptrdiff_t);
|
||||
this->installFooter(
|
||||
[](char* footerEnd) {
|
||||
char* objEnd = footerEnd - (sizeof(Footer) + sizeof(ptrdiff_t));
|
||||
ptrdiff_t data;
|
||||
memmove(&data, objEnd, sizeof(ptrdiff_t));
|
||||
return Action()(objEnd, data);
|
||||
},
|
||||
padding);
|
||||
}
|
||||
}
|
||||
|
||||
void ensureSpace(size_t size, size_t alignment);
|
||||
|
||||
char* allocObject(size_t size, size_t alignment);
|
||||
|
||||
char* allocObjectWithFooter(size_t sizeIncludingFooter, size_t alignment);
|
||||
|
||||
template <typename T>
|
||||
char* commonArrayAlloc(size_t count) {
|
||||
char* objStart;
|
||||
size_t arraySize = count * sizeof(T);
|
||||
|
||||
SkASSERT(arraySize > 0);
|
||||
|
||||
if (std::is_trivially_destructible<T>::value) {
|
||||
objStart = this->allocObject(arraySize, alignof(T));
|
||||
fCursor = objStart + arraySize;
|
||||
} else {
|
||||
size_t countSize = SkTFitsIn<int32_t>(count) ? sizeof(int32_t) : sizeof(ptrdiff_t);
|
||||
size_t totalSize = arraySize + sizeof(Footer) + countSize;
|
||||
objStart = this->allocObjectWithFooter(totalSize, alignof(T));
|
||||
size_t padding = objStart - fCursor;
|
||||
|
||||
// Advance to end of array to install footer.
|
||||
fCursor = objStart + arraySize;
|
||||
this->installIntFooter<ArrayDestructor<T>> (count, padding);
|
||||
}
|
||||
|
||||
return objStart;
|
||||
}
|
||||
|
||||
char* callFooterAction(char* end);
|
||||
|
||||
static char* EndChain(char*);
|
||||
|
||||
template<typename T>
|
||||
struct ArrayDestructor {
|
||||
char* operator()(char* objEnd, ptrdiff_t count) {
|
||||
char* objStart = objEnd - count * sizeof(T);
|
||||
T* array = (T*) objStart;
|
||||
for (int i = 0; i < count; i++) {
|
||||
array[i].~T();
|
||||
}
|
||||
return objStart;
|
||||
}
|
||||
};
|
||||
|
||||
char* fDtorCursor;
|
||||
char* fCursor;
|
||||
char* fEnd;
|
||||
size_t fExtraSize;
|
||||
};
|
||||
|
||||
#endif//SkFixedAlloc_DEFINED
|
||||
|
@ -351,7 +351,7 @@ SkLinearBitmapPipeline::SkLinearBitmapPipeline(
|
||||
SkShader::TileMode xTile, SkShader::TileMode yTile,
|
||||
SkColor paintColor,
|
||||
const SkPixmap& srcPixmap,
|
||||
SkFallbackAlloc* allocator)
|
||||
SkArenaAlloc* allocator)
|
||||
{
|
||||
SkISize dimensions = srcPixmap.info().dimensions();
|
||||
const SkImageInfo& srcImageInfo = srcPixmap.info();
|
||||
@ -393,7 +393,7 @@ SkLinearBitmapPipeline::SkLinearBitmapPipeline(
|
||||
const SkPixmap& srcPixmap,
|
||||
SkBlendMode mode,
|
||||
const SkImageInfo& dstInfo,
|
||||
SkFallbackAlloc* allocator)
|
||||
SkArenaAlloc* allocator)
|
||||
{
|
||||
SkASSERT(mode == SkBlendMode::kSrc || mode == SkBlendMode::kSrcOver);
|
||||
SkASSERT(srcPixmap.info().colorType() == dstInfo.colorType()
|
||||
@ -425,7 +425,7 @@ SkLinearBitmapPipeline* SkLinearBitmapPipeline::ClonePipelineForBlitting(
|
||||
float finalAlpha,
|
||||
SkBlendMode blendMode,
|
||||
const SkImageInfo& dstInfo,
|
||||
SkFallbackAlloc* allocator)
|
||||
SkArenaAlloc* allocator)
|
||||
{
|
||||
if (blendMode == SkBlendMode::kSrcOver && srcPixmap.info().alphaType() == kOpaque_SkAlphaType) {
|
||||
blendMode = SkBlendMode::kSrc;
|
||||
@ -469,7 +469,7 @@ SkLinearBitmapPipeline::PointProcessorInterface*
|
||||
SkLinearBitmapPipeline::chooseMatrix(
|
||||
PointProcessorInterface* next,
|
||||
const SkMatrix& inverse,
|
||||
SkFallbackAlloc* allocator)
|
||||
SkArenaAlloc* allocator)
|
||||
{
|
||||
if (inverse.hasPerspective()) {
|
||||
auto matrixStage = allocator->make<PerspectiveMatrix<>>(
|
||||
@ -480,7 +480,7 @@ SkLinearBitmapPipeline::chooseMatrix(
|
||||
SkVector{inverse.getPerspX(), inverse.getPerspY()},
|
||||
inverse.get(SkMatrix::kMPersp2));
|
||||
fMatrixStageCloner =
|
||||
[matrixStage](PointProcessorInterface* cloneNext, SkFallbackAlloc* memory) {
|
||||
[matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
|
||||
return memory->make<PerspectiveMatrix<>>(cloneNext, matrixStage);
|
||||
};
|
||||
return matrixStage;
|
||||
@ -491,7 +491,7 @@ SkLinearBitmapPipeline::chooseMatrix(
|
||||
SkVector{inverse.getScaleX(), inverse.getScaleY()},
|
||||
SkVector{inverse.getSkewX(), inverse.getSkewY()});
|
||||
fMatrixStageCloner =
|
||||
[matrixStage](PointProcessorInterface* cloneNext, SkFallbackAlloc* memory) {
|
||||
[matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
|
||||
return memory->make<AffineMatrix<>>(cloneNext, matrixStage);
|
||||
};
|
||||
return matrixStage;
|
||||
@ -501,7 +501,7 @@ SkLinearBitmapPipeline::chooseMatrix(
|
||||
SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
|
||||
SkVector{inverse.getScaleX(), inverse.getScaleY()});
|
||||
fMatrixStageCloner =
|
||||
[matrixStage](PointProcessorInterface* cloneNext, SkFallbackAlloc* memory) {
|
||||
[matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
|
||||
return memory->make<ScaleMatrix<>>(cloneNext, matrixStage);
|
||||
};
|
||||
return matrixStage;
|
||||
@ -510,12 +510,12 @@ SkLinearBitmapPipeline::chooseMatrix(
|
||||
next,
|
||||
SkVector{inverse.getTranslateX(), inverse.getTranslateY()});
|
||||
fMatrixStageCloner =
|
||||
[matrixStage](PointProcessorInterface* cloneNext, SkFallbackAlloc* memory) {
|
||||
[matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
|
||||
return memory->make<TranslateMatrix<>>(cloneNext, matrixStage);
|
||||
};
|
||||
return matrixStage;
|
||||
} else {
|
||||
fMatrixStageCloner = [](PointProcessorInterface* cloneNext, SkFallbackAlloc* memory) {
|
||||
fMatrixStageCloner = [](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
|
||||
return cloneNext;
|
||||
};
|
||||
return next;
|
||||
@ -526,12 +526,12 @@ template <typename Tiler>
|
||||
SkLinearBitmapPipeline::PointProcessorInterface* SkLinearBitmapPipeline::createTiler(
|
||||
SampleProcessorInterface* next,
|
||||
SkISize dimensions,
|
||||
SkFallbackAlloc* allocator)
|
||||
SkArenaAlloc* allocator)
|
||||
{
|
||||
auto tilerStage = allocator->make<Tiler>(next, dimensions);
|
||||
fTileStageCloner =
|
||||
[tilerStage](SampleProcessorInterface* cloneNext,
|
||||
SkFallbackAlloc* memory) -> PointProcessorInterface* {
|
||||
SkArenaAlloc* memory) -> PointProcessorInterface* {
|
||||
return memory->make<Tiler>(cloneNext, tilerStage);
|
||||
};
|
||||
return tilerStage;
|
||||
@ -542,7 +542,7 @@ SkLinearBitmapPipeline::PointProcessorInterface* SkLinearBitmapPipeline::chooseT
|
||||
SampleProcessorInterface* next,
|
||||
SkShader::TileMode yMode,
|
||||
SkISize dimensions,
|
||||
SkFallbackAlloc* allocator)
|
||||
SkArenaAlloc* allocator)
|
||||
{
|
||||
switch (yMode) {
|
||||
case SkShader::kClamp_TileMode: {
|
||||
@ -571,7 +571,7 @@ SkLinearBitmapPipeline::PointProcessorInterface* SkLinearBitmapPipeline::chooseT
|
||||
SkShader::TileMode yMode,
|
||||
SkFilterQuality filterQuality,
|
||||
SkScalar dx,
|
||||
SkFallbackAlloc* allocator)
|
||||
SkArenaAlloc* allocator)
|
||||
{
|
||||
switch (xMode) {
|
||||
case SkShader::kClamp_TileMode:
|
||||
@ -597,7 +597,7 @@ template <SkColorType colorType>
|
||||
SkLinearBitmapPipeline::PixelAccessorInterface*
|
||||
SkLinearBitmapPipeline::chooseSpecificAccessor(
|
||||
const SkPixmap& srcPixmap,
|
||||
SkFallbackAlloc* allocator)
|
||||
SkArenaAlloc* allocator)
|
||||
{
|
||||
if (srcPixmap.info().gammaCloseToSRGB()) {
|
||||
using Accessor = PixelAccessor<colorType, kSRGB_SkGammaType>;
|
||||
@ -611,7 +611,7 @@ SkLinearBitmapPipeline::PixelAccessorInterface*
|
||||
SkLinearBitmapPipeline::PixelAccessorInterface* SkLinearBitmapPipeline::choosePixelAccessor(
|
||||
const SkPixmap& srcPixmap,
|
||||
const SkColor A8TintColor,
|
||||
SkFallbackAlloc* allocator)
|
||||
SkArenaAlloc* allocator)
|
||||
{
|
||||
const SkImageInfo& imageInfo = srcPixmap.info();
|
||||
|
||||
@ -649,7 +649,7 @@ SkLinearBitmapPipeline::SampleProcessorInterface* SkLinearBitmapPipeline::choose
|
||||
SkShader::TileMode xTile, SkShader::TileMode yTile,
|
||||
const SkPixmap& srcPixmap,
|
||||
const SkColor A8TintColor,
|
||||
SkFallbackAlloc* allocator)
|
||||
SkArenaAlloc* allocator)
|
||||
{
|
||||
const SkImageInfo& imageInfo = srcPixmap.info();
|
||||
SkISize dimensions = imageInfo.dimensions();
|
||||
@ -707,7 +707,7 @@ SkLinearBitmapPipeline::SampleProcessorInterface* SkLinearBitmapPipeline::choose
|
||||
Blender* SkLinearBitmapPipeline::chooseBlenderForShading(
|
||||
SkAlphaType alphaType,
|
||||
float postAlpha,
|
||||
SkFallbackAlloc* allocator)
|
||||
SkArenaAlloc* allocator)
|
||||
{
|
||||
if (alphaType == kUnpremul_SkAlphaType) {
|
||||
return allocator->make<SrcFPPixel<kUnpremul_SkAlphaType>>(postAlpha);
|
||||
|
@ -34,14 +34,14 @@ public:
|
||||
SkShader::TileMode xTile, SkShader::TileMode yTile,
|
||||
SkColor paintColor,
|
||||
const SkPixmap& srcPixmap,
|
||||
SkFallbackAlloc* allocator);
|
||||
SkArenaAlloc* allocator);
|
||||
|
||||
SkLinearBitmapPipeline(
|
||||
const SkLinearBitmapPipeline& pipeline,
|
||||
const SkPixmap& srcPixmap,
|
||||
SkBlendMode,
|
||||
const SkImageInfo& dstInfo,
|
||||
SkFallbackAlloc* allocator);
|
||||
SkArenaAlloc* allocator);
|
||||
|
||||
static SkLinearBitmapPipeline* ClonePipelineForBlitting(
|
||||
const SkLinearBitmapPipeline& pipeline,
|
||||
@ -51,7 +51,7 @@ public:
|
||||
float finalAlpha,
|
||||
SkBlendMode,
|
||||
const SkImageInfo& dstInfo,
|
||||
SkFallbackAlloc* allocator);
|
||||
SkArenaAlloc* allocator);
|
||||
|
||||
~SkLinearBitmapPipeline();
|
||||
|
||||
@ -65,23 +65,23 @@ public:
|
||||
class PixelAccessorInterface;
|
||||
|
||||
using MatrixCloner =
|
||||
std::function<PointProcessorInterface* (PointProcessorInterface*, SkFallbackAlloc*)>;
|
||||
std::function<PointProcessorInterface* (PointProcessorInterface*, SkArenaAlloc*)>;
|
||||
using TilerCloner =
|
||||
std::function<PointProcessorInterface* (SampleProcessorInterface*, SkFallbackAlloc*)>;
|
||||
std::function<PointProcessorInterface* (SampleProcessorInterface*, SkArenaAlloc*)>;
|
||||
|
||||
PointProcessorInterface* chooseMatrix(
|
||||
PointProcessorInterface* next,
|
||||
const SkMatrix& inverse,
|
||||
SkFallbackAlloc* allocator);
|
||||
SkArenaAlloc* allocator);
|
||||
|
||||
template <typename Tiler>
|
||||
PointProcessorInterface* createTiler(SampleProcessorInterface* next, SkISize dimensions,
|
||||
SkFallbackAlloc* allocator);
|
||||
SkArenaAlloc* allocator);
|
||||
|
||||
template <typename XStrategy>
|
||||
PointProcessorInterface* chooseTilerYMode(
|
||||
SampleProcessorInterface* next, SkShader::TileMode yMode, SkISize dimensions,
|
||||
SkFallbackAlloc* allocator);
|
||||
SkArenaAlloc* allocator);
|
||||
|
||||
PointProcessorInterface* chooseTiler(
|
||||
SampleProcessorInterface* next,
|
||||
@ -89,16 +89,16 @@ public:
|
||||
SkShader::TileMode xMode, SkShader::TileMode yMode,
|
||||
SkFilterQuality filterQuality,
|
||||
SkScalar dx,
|
||||
SkFallbackAlloc* allocator);
|
||||
SkArenaAlloc* allocator);
|
||||
|
||||
template <SkColorType colorType>
|
||||
PixelAccessorInterface* chooseSpecificAccessor(const SkPixmap& srcPixmap,
|
||||
SkFallbackAlloc* allocator);
|
||||
SkArenaAlloc* allocator);
|
||||
|
||||
PixelAccessorInterface* choosePixelAccessor(
|
||||
const SkPixmap& srcPixmap,
|
||||
const SkColor A8TintColor,
|
||||
SkFallbackAlloc* allocator);
|
||||
SkArenaAlloc* allocator);
|
||||
|
||||
SampleProcessorInterface* chooseSampler(
|
||||
BlendProcessorInterface* next,
|
||||
@ -106,12 +106,12 @@ public:
|
||||
SkShader::TileMode xTile, SkShader::TileMode yTile,
|
||||
const SkPixmap& srcPixmap,
|
||||
const SkColor A8TintColor,
|
||||
SkFallbackAlloc* allocator);
|
||||
SkArenaAlloc* allocator);
|
||||
|
||||
BlendProcessorInterface* chooseBlenderForShading(
|
||||
SkAlphaType alphaType,
|
||||
float postAlpha,
|
||||
SkFallbackAlloc* allocator);
|
||||
SkArenaAlloc* allocator);
|
||||
|
||||
PointProcessorInterface* fFirstStage;
|
||||
MatrixCloner fMatrixStageCloner;
|
||||
|
@ -13,7 +13,8 @@ namespace {
|
||||
static int created, destroyed;
|
||||
|
||||
struct Foo {
|
||||
Foo(int X, float Y) : x(X), y(Y) { created++; }
|
||||
Foo() : x(-2), y(-3.0f) { created++; }
|
||||
Foo(int X, float Y) : x(X), y(Y) { created++; }
|
||||
~Foo() { destroyed++; }
|
||||
|
||||
int x;
|
||||
@ -111,3 +112,90 @@ DEF_TEST(FallbackAlloc, r) {
|
||||
REPORTER_ASSERT(r, !in_buf(big));
|
||||
REPORTER_ASSERT(r, !in_buf(smallB));
|
||||
}
|
||||
|
||||
struct WithDtor {
|
||||
~WithDtor() { }
|
||||
};
|
||||
|
||||
DEF_TEST(ArenaAlloc, r) {
|
||||
{
|
||||
created = 0;
|
||||
destroyed = 0;
|
||||
|
||||
SkArenaAlloc arena{nullptr, 0};
|
||||
REPORTER_ASSERT(r, *arena.make<int>(3) == 3);
|
||||
Foo* foo = arena.make<Foo>(3, 4.0f);
|
||||
REPORTER_ASSERT(r, foo->x == 3);
|
||||
REPORTER_ASSERT(r, foo->y == 4.0f);
|
||||
REPORTER_ASSERT(r, created == 1);
|
||||
REPORTER_ASSERT(r, destroyed == 0);
|
||||
arena.makeArrayDefault<int>(10);
|
||||
int* zeroed = arena.makeArray<int>(10);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
REPORTER_ASSERT(r, zeroed[i] == 0);
|
||||
}
|
||||
Foo* fooArray = arena.makeArrayDefault<Foo>(10);
|
||||
REPORTER_ASSERT(r, fooArray[3].x == -2);
|
||||
REPORTER_ASSERT(r, fooArray[4].y == -3.0f);
|
||||
REPORTER_ASSERT(r, created == 11);
|
||||
REPORTER_ASSERT(r, destroyed == 0);
|
||||
arena.make<typename std::aligned_storage<10,8>::type>();
|
||||
}
|
||||
REPORTER_ASSERT(r, created == 11);
|
||||
REPORTER_ASSERT(r, destroyed == 11);
|
||||
|
||||
{
|
||||
created = 0;
|
||||
destroyed = 0;
|
||||
char block[1024];
|
||||
SkArenaAlloc arena{block};
|
||||
|
||||
REPORTER_ASSERT(r, *arena.make<int>(3) == 3);
|
||||
Foo* foo = arena.make<Foo>(3, 4.0f);
|
||||
REPORTER_ASSERT(r, foo->x == 3);
|
||||
REPORTER_ASSERT(r, foo->y == 4.0f);
|
||||
REPORTER_ASSERT(r, created == 1);
|
||||
REPORTER_ASSERT(r, destroyed == 0);
|
||||
arena.makeArrayDefault<int>(10);
|
||||
int* zeroed = arena.makeArray<int>(10);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
REPORTER_ASSERT(r, zeroed[i] == 0);
|
||||
}
|
||||
Foo* fooArray = arena.makeArrayDefault<Foo>(10);
|
||||
REPORTER_ASSERT(r, fooArray[3].x == -2);
|
||||
REPORTER_ASSERT(r, fooArray[4].y == -3.0f);
|
||||
REPORTER_ASSERT(r, created == 11);
|
||||
REPORTER_ASSERT(r, destroyed == 0);
|
||||
arena.make<typename std::aligned_storage<10,8>::type>();
|
||||
}
|
||||
REPORTER_ASSERT(r, created == 11);
|
||||
REPORTER_ASSERT(r, destroyed == 11);
|
||||
|
||||
{
|
||||
created = 0;
|
||||
destroyed = 0;
|
||||
std::unique_ptr<char[]> block{new char[1024]};
|
||||
SkArenaAlloc arena{block.get(), 1024};
|
||||
|
||||
REPORTER_ASSERT(r, *arena.make<int>(3) == 3);
|
||||
Foo* foo = arena.make<Foo>(3, 4.0f);
|
||||
REPORTER_ASSERT(r, foo->x == 3);
|
||||
REPORTER_ASSERT(r, foo->y == 4.0f);
|
||||
REPORTER_ASSERT(r, created == 1);
|
||||
REPORTER_ASSERT(r, destroyed == 0);
|
||||
arena.makeArrayDefault<int>(10);
|
||||
int* zeroed = arena.makeArray<int>(10);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
REPORTER_ASSERT(r, zeroed[i] == 0);
|
||||
}
|
||||
Foo* fooArray = arena.makeArrayDefault<Foo>(10);
|
||||
REPORTER_ASSERT(r, fooArray[3].x == -2);
|
||||
REPORTER_ASSERT(r, fooArray[4].y == -3.0f);
|
||||
REPORTER_ASSERT(r, created == 11);
|
||||
REPORTER_ASSERT(r, destroyed == 0);
|
||||
arena.make<typename std::aligned_storage<10,8>::type>();
|
||||
}
|
||||
REPORTER_ASSERT(r, created == 11);
|
||||
REPORTER_ASSERT(r, destroyed == 11);
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user