Function pointers -> templates in SkPictureFlat.

These flatten/unflatten function pointers were driving me nuts when reading the
generated assembly for this code.  We don't need the flexibility of function
pointers here, so let's use templates to make it more manageable.  You'll
notice we get much better typing now on flatten/unflatten.

BUG=
R=reed@google.com

Author: mtklein@google.com

Review URL: https://codereview.chromium.org/123213004

git-svn-id: http://skia.googlecode.com/svn/trunk@12873 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
commit-bot@chromium.org 2014-01-02 22:20:49 +00:00
parent 78e7b4e1b9
commit 07adb6359f
6 changed files with 119 additions and 175 deletions

View File

@ -90,51 +90,3 @@ SkNamedFactorySet* SkFlatController::setNamedFactorySet(SkNamedFactorySet* set)
return set; return set;
} }
///////////////////////////////////////////////////////////////////////////////
SkFlatData* SkFlatData::Create(SkFlatController* controller,
const void* obj,
int index,
void (*flattenProc)(SkOrderedWriteBuffer&, const void*)) {
// a buffer of 256 bytes should be sufficient for most paints, regions,
// and matrices.
intptr_t storage[256];
SkOrderedWriteBuffer buffer(256, storage, sizeof(storage));
buffer.setBitmapHeap(controller->getBitmapHeap());
buffer.setTypefaceRecorder(controller->getTypefaceSet());
buffer.setNamedFactoryRecorder(controller->getNamedFactorySet());
buffer.setFlags(controller->getWriteBufferFlags());
flattenProc(buffer, obj);
uint32_t size = buffer.size();
SkASSERT(SkIsAlign4(size));
// Allocate enough memory to hold SkFlatData struct and the flat data itself.
size_t allocSize = sizeof(SkFlatData) + size;
SkFlatData* result = (SkFlatData*) controller->allocThrow(allocSize);
// Put the serialized contents into the data section of the new allocation.
buffer.writeToMemory(result->data());
// Stamp the index, size and checksum in the header.
result->stampHeader(index, size);
return result;
}
void SkFlatData::unflatten(void* result,
void (*unflattenProc)(SkOrderedReadBuffer&, void*),
SkBitmapHeap* bitmapHeap,
SkTypefacePlayback* facePlayback) const {
SkOrderedReadBuffer buffer(this->data(), fFlatSize);
if (bitmapHeap) {
buffer.setBitmapStorage(bitmapHeap);
}
if (facePlayback) {
facePlayback->setupBuffer(buffer);
}
unflattenProc(buffer, result);
SkASSERT(fFlatSize == (int32_t)buffer.offset());
}

View File

@ -267,16 +267,49 @@ private:
class SkFlatData { class SkFlatData {
public: public:
// Flatten obj into an SkFlatData with this index. controller owns the SkFlatData*. // Flatten obj into an SkFlatData with this index. controller owns the SkFlatData*.
static SkFlatData* Create(SkFlatController* controller, template <typename Traits, typename T>
const void* obj, static SkFlatData* Create(SkFlatController* controller, const T& obj, int index) {
int index, // A buffer of 256 bytes should fit most paints, regions, and matrices.
void (*flattenProc)(SkOrderedWriteBuffer&, const void*)); uint32_t storage[64];
SkOrderedWriteBuffer buffer(256, storage, sizeof(storage));
// Unflatten this into result, using bitmapHeap and facePlayback for bitmaps and fonts if given. buffer.setBitmapHeap(controller->getBitmapHeap());
void unflatten(void* result, buffer.setTypefaceRecorder(controller->getTypefaceSet());
void (*unflattenProc)(SkOrderedReadBuffer&, void*), buffer.setNamedFactoryRecorder(controller->getNamedFactorySet());
buffer.setFlags(controller->getWriteBufferFlags());
Traits::flatten(buffer, obj);
uint32_t size = buffer.size();
SkASSERT(SkIsAlign4(size));
// Allocate enough memory to hold SkFlatData struct and the flat data itself.
size_t allocSize = sizeof(SkFlatData) + size;
SkFlatData* result = (SkFlatData*) controller->allocThrow(allocSize);
// Put the serialized contents into the data section of the new allocation.
buffer.writeToMemory(result->data());
// Stamp the index, size and checksum in the header.
result->stampHeader(index, size);
return result;
}
// Unflatten this into result, using bitmapHeap and facePlayback for bitmaps and fonts if given
template <typename Traits, typename T>
void unflatten(T* result,
SkBitmapHeap* bitmapHeap = NULL, SkBitmapHeap* bitmapHeap = NULL,
SkTypefacePlayback* facePlayback = NULL) const; SkTypefacePlayback* facePlayback = NULL) const {
SkOrderedReadBuffer buffer(this->data(), fFlatSize);
if (bitmapHeap) {
buffer.setBitmapStorage(bitmapHeap);
}
if (facePlayback) {
facePlayback->setupBuffer(buffer);
}
Traits::unflatten(buffer, result);
SkASSERT(fFlatSize == (int32_t)buffer.offset());
}
// Do these contain the same data? Ignores index() and topBot(). // Do these contain the same data? Ignores index() and topBot().
bool operator==(const SkFlatData& that) const { bool operator==(const SkFlatData& that) const {
@ -333,19 +366,17 @@ private:
mutable SkScalar fTopBot[2]; // Cache of FontMetrics fTop, fBottom. Starts as [NaN,?]. mutable SkScalar fTopBot[2]; // Cache of FontMetrics fTop, fBottom. Starts as [NaN,?].
// uint32_t flattenedData[] implicitly hangs off the end. // uint32_t flattenedData[] implicitly hangs off the end.
template <class T> friend class SkFlatDictionary; template <typename T, typename Traits, int kScratchSizeGuess> friend class SkFlatDictionary;
}; };
template <class T> template <typename T, typename Traits, int kScratchSizeGuess=0>
class SkFlatDictionary { class SkFlatDictionary {
static const size_t kWriteBufferGrowthBytes = 1024; static const size_t kWriteBufferGrowthBytes = 1024;
public: public:
SkFlatDictionary(SkFlatController* controller, size_t scratchSizeGuess = 0) explicit SkFlatDictionary(SkFlatController* controller)
: fFlattenProc(NULL) : fController(SkRef(controller))
, fUnflattenProc(NULL) , fScratchSize(kScratchSizeGuess)
, fController(SkRef(controller))
, fScratchSize(scratchSizeGuess)
, fScratch(AllocScratch(fScratchSize)) , fScratch(AllocScratch(fScratchSize))
, fWriteBuffer(kWriteBufferGrowthBytes) , fWriteBuffer(kWriteBufferGrowthBytes)
, fWriteBufferReady(false) { , fWriteBufferReady(false) {
@ -471,10 +502,6 @@ public:
return this->findAndReturnMutableFlat(element); return this->findAndReturnMutableFlat(element);
} }
protected:
void (*fFlattenProc)(SkOrderedWriteBuffer&, const void*);
void (*fUnflattenProc)(SkOrderedReadBuffer&, void*);
private: private:
// Layout: [ SkFlatData header, 20 bytes ] [ data ..., 4-byte aligned ] // Layout: [ SkFlatData header, 20 bytes ] [ data ..., 4-byte aligned ]
static size_t SizeWithPadding(size_t flatDataSize) { static size_t SizeWithPadding(size_t flatDataSize) {
@ -523,7 +550,7 @@ private:
// Flatten element into fWriteBuffer (using fScratch as storage). // Flatten element into fWriteBuffer (using fScratch as storage).
fWriteBuffer.reset(fScratch->data(), fScratchSize); fWriteBuffer.reset(fScratch->data(), fScratchSize);
fFlattenProc(fWriteBuffer, &element); Traits::flatten(fWriteBuffer, element);
const size_t bytesWritten = fWriteBuffer.bytesWritten(); const size_t bytesWritten = fWriteBuffer.bytesWritten();
// If all the flattened bytes fit into fScratch, we can skip a call to writeToMemory. // If all the flattened bytes fit into fScratch, we can skip a call to writeToMemory.
@ -561,10 +588,9 @@ private:
} }
void unflatten(T* dst, const SkFlatData* element) const { void unflatten(T* dst, const SkFlatData* element) const {
element->unflatten(dst, element->unflatten<Traits>(dst,
fUnflattenProc, fController->getBitmapHeap(),
fController->getBitmapHeap(), fController->getTypefacePlayback());
fController->getTypefacePlayback());
} }
// All SkFlatData* stored in fIndexedData and fHash are owned by the controller. // All SkFlatData* stored in fIndexedData and fHash are owned by the controller.
@ -589,15 +615,37 @@ private:
// Some common dictionaries are defined here for both reference and convenience // Some common dictionaries are defined here for both reference and convenience
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
template <class T> struct SkMatrixTraits {
static void SkFlattenObjectProc(SkOrderedWriteBuffer& buffer, const void* obj) { static void flatten(SkOrderedWriteBuffer& buffer, const SkMatrix& matrix) {
((T*)obj)->flatten(buffer); buffer.getWriter32()->writeMatrix(matrix);
} }
static void unflatten(SkOrderedReadBuffer& buffer, SkMatrix* matrix) {
buffer.getReader32()->readMatrix(matrix);
}
};
typedef SkFlatDictionary<SkMatrix, SkMatrixTraits, 36> SkMatrixDictionary;
template <class T>
static void SkUnflattenObjectProc(SkOrderedReadBuffer& buffer, void* obj) { struct SkRegionTraits {
((T*)obj)->unflatten(buffer); static void flatten(SkOrderedWriteBuffer& buffer, const SkRegion& region) {
} buffer.getWriter32()->writeRegion(region);
}
static void unflatten(SkOrderedReadBuffer& buffer, SkRegion* region) {
buffer.getReader32()->readRegion(region);
}
};
typedef SkFlatDictionary<SkRegion, SkRegionTraits> SkRegionDictionary;
struct SkPaintTraits {
static void flatten(SkOrderedWriteBuffer& buffer, const SkPaint& paint) {
paint.flatten(buffer);
}
static void unflatten(SkOrderedReadBuffer& buffer, SkPaint* paint) {
paint->unflatten(buffer);
}
};
typedef SkFlatDictionary<SkPaint, SkPaintTraits, 512> SkPaintDictionary;
class SkChunkFlatController : public SkFlatController { class SkChunkFlatController : public SkFlatController {
public: public:
@ -635,49 +683,4 @@ private:
mutable SkTypefacePlayback fTypefacePlayback; mutable SkTypefacePlayback fTypefacePlayback;
}; };
class SkMatrixDictionary : public SkFlatDictionary<SkMatrix> {
public:
// All matrices fit in 36 bytes.
SkMatrixDictionary(SkFlatController* controller)
: SkFlatDictionary<SkMatrix>(controller, 36) {
fFlattenProc = &flattenMatrix;
fUnflattenProc = &unflattenMatrix;
}
static void flattenMatrix(SkOrderedWriteBuffer& buffer, const void* obj) {
buffer.getWriter32()->writeMatrix(*(SkMatrix*)obj);
}
static void unflattenMatrix(SkOrderedReadBuffer& buffer, void* obj) {
buffer.getReader32()->readMatrix((SkMatrix*)obj);
}
};
class SkPaintDictionary : public SkFlatDictionary<SkPaint> {
public:
// The largest paint across ~60 .skps was 500 bytes.
SkPaintDictionary(SkFlatController* controller)
: SkFlatDictionary<SkPaint>(controller, 512) {
fFlattenProc = &SkFlattenObjectProc<SkPaint>;
fUnflattenProc = &SkUnflattenObjectProc<SkPaint>;
}
};
class SkRegionDictionary : public SkFlatDictionary<SkRegion> {
public:
SkRegionDictionary(SkFlatController* controller)
: SkFlatDictionary<SkRegion>(controller) {
fFlattenProc = &flattenRegion;
fUnflattenProc = &unflattenRegion;
}
static void flattenRegion(SkOrderedWriteBuffer& buffer, const void* obj) {
buffer.getWriter32()->writeRegion(*(SkRegion*)obj);
}
static void unflattenRegion(SkOrderedReadBuffer& buffer, void* obj) {
buffer.getReader32()->readRegion((SkRegion*)obj);
}
};
#endif #endif

View File

@ -212,9 +212,10 @@ SkPicturePlayback::SkPicturePlayback(const SkPicturePlayback& src, SkPictCopyInf
SkDEBUGCODE(int heapSize = SafeCount(fBitmapHeap.get());) SkDEBUGCODE(int heapSize = SafeCount(fBitmapHeap.get());)
for (int i = 0; i < paintCount; i++) { for (int i = 0; i < paintCount; i++) {
if (needs_deep_copy(src.fPaints->at(i))) { if (needs_deep_copy(src.fPaints->at(i))) {
deepCopyInfo->paintData[i] = SkFlatData::Create(&deepCopyInfo->controller, deepCopyInfo->paintData[i] =
&src.fPaints->at(i), 0, SkFlatData::Create<SkPaintTraits>(&deepCopyInfo->controller,
&SkFlattenObjectProc<SkPaint>); src.fPaints->at(i), 0);
} else { } else {
// this is our sentinel, which we use in the unflatten loop // this is our sentinel, which we use in the unflatten loop
deepCopyInfo->paintData[i] = NULL; deepCopyInfo->paintData[i] = NULL;
@ -233,9 +234,8 @@ SkPicturePlayback::SkPicturePlayback(const SkPicturePlayback& src, SkPictCopyInf
SkTypefacePlayback* tfPlayback = deepCopyInfo->controller.getTypefacePlayback(); SkTypefacePlayback* tfPlayback = deepCopyInfo->controller.getTypefacePlayback();
for (int i = 0; i < paintCount; i++) { for (int i = 0; i < paintCount; i++) {
if (deepCopyInfo->paintData[i]) { if (deepCopyInfo->paintData[i]) {
deepCopyInfo->paintData[i]->unflatten(&fPaints->writableAt(i), deepCopyInfo->paintData[i]->unflatten<SkPaintTraits>(&fPaints->writableAt(i),
&SkUnflattenObjectProc<SkPaint>, bmHeap, tfPlayback);
bmHeap, tfPlayback);
} else { } else {
// needs_deep_copy was false, so just need to assign // needs_deep_copy was false, so just need to assign
fPaints->writableAt(i) = src.fPaints->at(i); fPaints->writableAt(i) = src.fPaints->at(i);

View File

@ -150,20 +150,13 @@ const SkFlatData* FlattenableHeap::flatToReplace() const {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
class FlatDictionary : public SkFlatDictionary<SkFlattenable> { struct SkFlattenableTraits {
public: static void flatten(SkOrderedWriteBuffer& buffer, const SkFlattenable& flattenable) {
FlatDictionary(FlattenableHeap* heap) buffer.writeFlattenable(&flattenable);
: SkFlatDictionary<SkFlattenable>(heap) {
fFlattenProc = &flattenFlattenableProc;
// No need to define fUnflattenProc since the writer will never
// unflatten the data.
} }
static void flattenFlattenableProc(SkOrderedWriteBuffer& buffer, // No need to define unflatten if we never call it.
const void* obj) {
buffer.writeFlattenable((SkFlattenable*)obj);
}
}; };
typedef SkFlatDictionary<SkFlattenable, SkFlattenableTraits> FlatDictionary;
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@ -16,18 +16,12 @@
#include "Test.h" #include "Test.h"
#include "TestClassDef.h" #include "TestClassDef.h"
class FlatDictionary : public SkFlatDictionary<SkShader> { struct SkShaderTraits {
static void flatten(SkOrderedWriteBuffer& buffer, const SkShader& shader) {
public: buffer.writeFlattenable(&shader);
FlatDictionary(SkFlatController* controller)
: SkFlatDictionary<SkShader>(controller) {
fFlattenProc = &flattenFlattenableProc;
// No need for an unflattenProc
}
static void flattenFlattenableProc(SkOrderedWriteBuffer& buffer, const void* obj) {
buffer.writeFlattenable((SkFlattenable*)obj);
} }
}; };
typedef SkFlatDictionary<SkShader, SkShaderTraits> FlatDictionary;
class SkBitmapHeapTester { class SkBitmapHeapTester {

View File

@ -17,10 +17,16 @@
#include "SkShader.h" #include "SkShader.h"
#include "SkXfermode.h" #include "SkXfermode.h"
static void flattenFlattenableProc(SkOrderedWriteBuffer& buffer, struct SkFlattenableTraits {
const void* obj) { static void flatten(SkOrderedWriteBuffer& buffer, const SkFlattenable& flattenable) {
buffer.writeFlattenable((SkFlattenable*)obj); buffer.writeFlattenable(&flattenable);
} }
};
struct SkBitmapTraits {
static void flatten(SkOrderedWriteBuffer& buffer, const SkBitmap& bitmap) {
bitmap.flatten(buffer);
}
};
class Controller : public SkChunkFlatController { class Controller : public SkChunkFlatController {
public: public:
@ -38,13 +44,12 @@ private:
* @param obj Flattenable object to be flattened. * @param obj Flattenable object to be flattened.
* @param flattenProc Function that flattens objects with the same type as obj. * @param flattenProc Function that flattens objects with the same type as obj.
*/ */
static void testCreate(skiatest::Reporter* reporter, const void* obj, template <typename Traits, typename T>
void (*flattenProc)(SkOrderedWriteBuffer&, const void*)) { static void testCreate(skiatest::Reporter* reporter, const T& obj) {
Controller controller; Controller controller;
// No need to delete data because that will be taken care of by the // No need to delete data because that will be taken care of by the controller.
// controller. SkFlatData* data1 = SkFlatData::Create<Traits>(&controller, obj, 0);
SkFlatData* data1 = SkFlatData::Create(&controller, obj, 0, flattenProc); SkFlatData* data2 = SkFlatData::Create<Traits>(&controller, obj, 1);
SkFlatData* data2 = SkFlatData::Create(&controller, obj, 1, flattenProc);
REPORTER_ASSERT(reporter, *data1 == *data2); REPORTER_ASSERT(reporter, *data1 == *data2);
} }
@ -56,10 +61,10 @@ DEF_TEST(FlatData, reporter) {
SkColor colors[2]; SkColor colors[2];
colors[0] = SK_ColorRED; colors[0] = SK_ColorRED;
colors[1] = SK_ColorBLUE; colors[1] = SK_ColorBLUE;
SkShader* shader = SkGradientShader::CreateLinear(points, colors, NULL,
2, SkShader::kRepeat_TileMode); SkAutoTUnref<SkShader> shader(SkGradientShader::CreateLinear(points, colors, NULL, 2,
SkAutoUnref aur(shader); SkShader::kRepeat_TileMode));
testCreate(reporter, shader, flattenFlattenableProc); testCreate<SkFlattenableTraits>(reporter, *shader);
// Test SkBitmap // Test SkBitmap
{ {
@ -70,17 +75,14 @@ DEF_TEST(FlatData, reporter) {
SkPaint paint; SkPaint paint;
paint.setShader(shader); paint.setShader(shader);
canvas.drawPaint(paint); canvas.drawPaint(paint);
testCreate(reporter, &bm, &SkFlattenObjectProc<SkBitmap>); testCreate<SkBitmapTraits>(reporter, bm);
} }
// Test SkColorFilter // Test SkColorFilter
SkColorFilter* cf = SkColorFilter::CreateLightingFilter(SK_ColorBLUE, SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateLightingFilter(SK_ColorBLUE, SK_ColorRED));
SK_ColorRED); testCreate<SkFlattenableTraits>(reporter, *cf);
SkAutoUnref aurcf(cf);
testCreate(reporter, cf, &flattenFlattenableProc);
// Test SkXfermode // Test SkXfermode
SkXfermode* xfer = SkXfermode::Create(SkXfermode::kDstOver_Mode); SkAutoTUnref<SkXfermode> xfer(SkXfermode::Create(SkXfermode::kDstOver_Mode));
SkAutoUnref aurxf(xfer); testCreate<SkFlattenableTraits>(reporter, *xfer);
testCreate(reporter, xfer, &flattenFlattenableProc);
} }