aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core
diff options
context:
space:
mode:
authorGravatar mtklein@google.com <mtklein@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-07-24 19:11:15 +0000
committerGravatar mtklein@google.com <mtklein@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-07-24 19:11:15 +0000
commit5174286bc5697e290d052fed994e8759fa5a4ed3 (patch)
treef48b740e82eb61dd908bd7353673f0eace24f5a6 /src/core
parentcae5d8d5705081cb4d22af7a30be0f01bffce745 (diff)
Revert "Start from scratch on a faster SkFlatDictionary."
This reverts commit fec9bfa02d5d2b27bfa2dad3e37e5825a720784d. git-svn-id: http://skia.googlecode.com/svn/trunk@10331 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/core')
-rw-r--r--src/core/SkOrderedWriteBuffer.h13
-rw-r--r--src/core/SkPictureFlat.cpp15
-rw-r--r--src/core/SkPictureFlat.h188
3 files changed, 63 insertions, 153 deletions
diff --git a/src/core/SkOrderedWriteBuffer.h b/src/core/SkOrderedWriteBuffer.h
index 180f9a4d63..ebec7d1c21 100644
--- a/src/core/SkOrderedWriteBuffer.h
+++ b/src/core/SkOrderedWriteBuffer.h
@@ -26,25 +26,18 @@ class SkRefCntSet;
class SkOrderedWriteBuffer : public SkFlattenableWriteBuffer {
public:
SkOrderedWriteBuffer(size_t minSize);
- SkOrderedWriteBuffer(size_t minSize, void* initialStorage, size_t storageSize);
+ SkOrderedWriteBuffer(size_t minSize, void* initialStorage,
+ size_t storageSize);
virtual ~SkOrderedWriteBuffer();
virtual bool isOrderedBinaryBuffer() SK_OVERRIDE { return true; }
virtual SkOrderedWriteBuffer* getOrderedBinaryBuffer() SK_OVERRIDE { return this; }
SkWriter32* getWriter32() { return &fWriter; }
- void reset(void* storage, size_t storageSize) { fWriter.reset(storage, storageSize); }
-
- // Returns true if we've written only into the storage passed into constructor or reset.
- // (You may be able to use this to avoid a call to writeToMemory.)
- bool wroteOnlyToStorage() const { return fWriter.wroteOnlyToStorage(); }
void writeToMemory(void* dst) { fWriter.flatten(dst); }
uint32_t* reserve(size_t size) { return fWriter.reserve(size); }
-
- uint32_t bytesWritten() const { return fWriter.bytesWritten(); }
- // Deprecated. Please call bytesWritten instead. TODO(mtklein): clean up
- uint32_t size() const { return this->bytesWritten(); }
+ uint32_t size() { return fWriter.size(); }
virtual void writeByteArray(const void* data, size_t size) SK_OVERRIDE;
virtual void writeBool(bool value) SK_OVERRIDE;
diff --git a/src/core/SkPictureFlat.cpp b/src/core/SkPictureFlat.cpp
index 2c6efa2a8f..e9eec0fb00 100644
--- a/src/core/SkPictureFlat.cpp
+++ b/src/core/SkPictureFlat.cpp
@@ -94,14 +94,6 @@ SkNamedFactorySet* SkFlatController::setNamedFactorySet(SkNamedFactorySet* set)
///////////////////////////////////////////////////////////////////////////////
-void SkFlatData::stampHeaderAndSentinel(int index, int32_t size) {
- fIndex = index;
- fFlatSize = size;
- fChecksum = SkChecksum::Compute(this->data32(), size);
- this->setTopBotUnwritten();
- this->setSentinelAsCandidate();
-}
-
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,
@@ -127,9 +119,14 @@ SkFlatData* SkFlatData::Create(SkFlatController* controller, const void* obj,
size_t allocSize = sizeof(SkFlatData) + size + sizeof(uint32_t);
SkFlatData* result = (SkFlatData*) controller->allocThrow(allocSize);
+ result->setIndex(index);
+ result->setTopBotUnwritten();
+ result->fFlatSize = size;
+
// put the serialized contents into the data section of the new allocation
buffer.writeToMemory(result->data());
- result->stampHeaderAndSentinel(index, size);
+ result->fChecksum = SkChecksum::Compute(result->data32(), size);
+ result->setSentinelAsCandidate();
return result;
}
diff --git a/src/core/SkPictureFlat.h b/src/core/SkPictureFlat.h
index 3ac1d2d907..0a147defe8 100644
--- a/src/core/SkPictureFlat.h
+++ b/src/core/SkPictureFlat.h
@@ -151,9 +151,9 @@ private:
// also responsible for flattening/unflattening objects but
// details of that operation are hidden in the provided procs
// SkFlatDictionary: is an abstract templated dictionary that maintains a
-// searchable set of SkFlatData objects of type T.
+// searchable set of SkFlataData objects of type T.
// SkFlatController: is an interface provided to SkFlatDictionary which handles
-// allocation (and unallocation in some cases). It also holds
+// allocation and unallocation in some cases. It also holds
// ref count recorders and the like.
//
// NOTE: any class that wishes to be used in conjunction with SkFlatDictionary
@@ -175,15 +175,16 @@ public:
SkFlatController();
virtual ~SkFlatController();
/**
- * Return a new block of memory for the SkFlatDictionary to use.
- * This memory is owned by the controller and has the same lifetime unless you
- * call unalloc(), in which case it may be freed early.
+ * Provide a new block of memory for the SkFlatDictionary to use.
*/
virtual void* allocThrow(size_t bytes) = 0;
/**
- * Hint that this block, which was allocated with allocThrow, is no longer needed.
- * The implementation may choose to free this memory any time beteween now and destruction.
+ * Unallocate a previously allocated block, returned by allocThrow.
+ * Implementation should at least perform an unallocation if passed the last
+ * pointer returned by allocThrow. If findAndReplace() is intended to be
+ * used, unalloc should also be able to unallocate the SkFlatData that is
+ * provided.
*/
virtual void unalloc(void* ptr) = 0;
@@ -399,33 +400,26 @@ private:
SkASSERT(SkIsAlign4(fFlatSize));
this->data32()[fFlatSize >> 2] = value;
}
-
- // This does not modify the payload flat data, in case it's already been written.
- void stampHeaderAndSentinel(int index, int32_t size);
- template <class T> friend class SkFlatDictionary; // For stampHeaderAndSentinel().
};
template <class T>
class SkFlatDictionary {
- static const size_t kWriteBufferGrowthBytes = 1024;
-
public:
- SkFlatDictionary(SkFlatController* controller, size_t scratchSizeGuess = 0)
- : fFlattenProc(NULL)
- , fUnflattenProc(NULL)
- , fController(SkRef(controller))
- , fScratchSize(scratchSizeGuess)
- , fScratch(this->allocScratch(fScratchSize))
- , fWriteBuffer(kWriteBufferGrowthBytes)
- , fWriteBufferReady(false)
- , fNextIndex(1) { // set to 1 since returning a zero from find() indicates failure
+ SkFlatDictionary(SkFlatController* controller)
+ : fController(controller) {
+ fFlattenProc = NULL;
+ fUnflattenProc = NULL;
+ SkASSERT(controller);
+ fController->ref();
+ // set to 1 since returning a zero from find() indicates failure
+ fNextIndex = 1;
sk_bzero(fHash, sizeof(fHash));
// index 0 is always empty since it is used as a signal that find failed
fIndexedData.push(NULL);
}
- ~SkFlatDictionary() {
- sk_free(fScratch);
+ virtual ~SkFlatDictionary() {
+ fController->unref();
}
int count() const {
@@ -538,40 +532,33 @@ public:
}
const SkFlatData* findAndReturnFlat(const T& element) {
- // Only valid until the next call to resetScratch().
- const SkFlatData& scratch = this->resetScratch(element, fNextIndex);
+ SkFlatData* flat = SkFlatData::Create(fController, &element, fNextIndex, fFlattenProc);
- // See if we have it in the hash?
- const int hashIndex = ChecksumToHashIndex(scratch.checksum());
+ int hashIndex = ChecksumToHashIndex(flat->checksum());
const SkFlatData* candidate = fHash[hashIndex];
- if (candidate != NULL && SkFlatData::Compare(scratch, *candidate) == 0) {
+ if (candidate && !SkFlatData::Compare(*flat, *candidate)) {
+ fController->unalloc(flat);
return candidate;
}
- // See if we have it at all?
- const int index = SkTSearch<const SkFlatData, SkFlatData::Less>(fSortedData.begin(),
- fSortedData.count(),
- &scratch,
- sizeof(&scratch));
+ int index = SkTSearch<const SkFlatData,
+ SkFlatData::Less>((const SkFlatData**) fSortedData.begin(),
+ fSortedData.count(), flat, sizeof(flat));
if (index >= 0) {
- // Found. Update hash before we return.
+ fController->unalloc(flat);
fHash[hashIndex] = fSortedData[index];
return fSortedData[index];
}
- // We don't have it. Add it.
- SkFlatData* detached = this->detachScratch();
- // detached will live beyond the next call to resetScratch(), but is owned by fController.
- *fSortedData.insert(~index) = detached; // SkTSearch returned bit-not of where to insert.
- *fIndexedData.insert(detached->index()) = detached;
- fHash[hashIndex] = detached;
-
- SkASSERT(detached->index() == fNextIndex);
+ index = ~index;
+ *fSortedData.insert(index) = flat;
+ *fIndexedData.insert(flat->index()) = flat;
SkASSERT(fSortedData.count() == fNextIndex);
- SkASSERT(fIndexedData.count() == fNextIndex+1);
fNextIndex++;
-
- return detached;
+ flat->setSentinelInCache();
+ fHash[hashIndex] = flat;
+ SkASSERT(fIndexedData.count() == fSortedData.count()+1);
+ return flat;
}
protected:
@@ -579,76 +566,6 @@ protected:
void (*fUnflattenProc)(SkOrderedReadBuffer&, void*);
private:
- // Layout: [ SkFlatData header, 20 bytes ] [ data ..., 4-byte aligned ] [ sentinel, 4 bytes]
- static size_t SizeWithPadding(size_t flatDataSize) {
- SkASSERT(SkIsAlign4(flatDataSize));
- return sizeof(SkFlatData) + flatDataSize + sizeof(uint32_t);
- }
-
- // Allocate a new scratch SkFlatData owned by this dictionary. Must be sk_freed.
- SkFlatData* allocScratch(size_t scratchSize) const {
- return (SkFlatData*) sk_malloc_throw(SizeWithPadding(scratchSize));
- }
-
- // We have to delay fWriteBuffer's initialization until its first use; fController might not
- // be fully set up by the time we get it in the constructor.
- void lazyWriteBufferInit() {
- if (fWriteBufferReady) {
- return;
- }
- // Without a bitmap heap, we'll flatten bitmaps into paints. That's never what you want.
- SkASSERT(fController->getBitmapHeap() != NULL);
- fWriteBuffer.setBitmapHeap(fController->getBitmapHeap());
- fWriteBuffer.setTypefaceRecorder(fController->getTypefaceSet());
- fWriteBuffer.setNamedFactoryRecorder(fController->getNamedFactorySet());
- fWriteBuffer.setFlags(fController->getWriteBufferFlags());
- fWriteBufferReady = true;
- }
-
- // This reference is valid only until the next call to resetScratch() or detachScratch().
- const SkFlatData& resetScratch(const T& element, int index) {
- this->lazyWriteBufferInit();
-
- // Flatten element into fWriteBuffer (using fScratch as storage).
- fWriteBuffer.reset(fScratch->data(), fScratchSize);
- fFlattenProc(fWriteBuffer, &element);
- const size_t bytesWritten = fWriteBuffer.bytesWritten();
-
- // If all the flattened bytes fit into fScratch, we can skip a call to writeToMemory.
- if (!fWriteBuffer.wroteOnlyToStorage()) {
- SkASSERT(bytesWritten > fScratchSize);
- // It didn't all fit. Copy into a larger replacement SkFlatData.
- // We can't just realloc because it might move the pointer and confuse writeToMemory.
- SkFlatData* larger = this->allocScratch(bytesWritten);
- fWriteBuffer.writeToMemory(larger->data());
-
- // Carry on with this larger scratch to minimize the likelihood of future resizing.
- sk_free(fScratch);
- fScratchSize = bytesWritten;
- fScratch = larger;
- }
-
- // The data is in fScratch now, but we need to stamp its header and trailing sentinel.
- fScratch->stampHeaderAndSentinel(index, bytesWritten);
- return *fScratch;
- }
-
- // This result is owned by fController and lives as long as it does (unless unalloc'd).
- SkFlatData* detachScratch() {
- // Allocate a new SkFlatData exactly big enough to hold our current scratch.
- // We use the controller for this allocation to extend the allocation's lifetime and allow
- // the controller to do whatever memory management it wants.
- const size_t paddedSize = SizeWithPadding(fScratch->flatSize());
- SkFlatData* detached = (SkFlatData*)fController->allocThrow(paddedSize);
-
- // Copy scratch into the new SkFlatData, setting the sentinel for cache storage.
- memcpy(detached, fScratch, paddedSize);
- detached->setSentinelInCache();
-
- // We can now reuse fScratch, and detached will live until fController dies.
- return detached;
- }
-
void unflatten(T* dst, const SkFlatData* element) const {
element->unflatten(dst, fUnflattenProc,
fController->getBitmapHeap(),
@@ -667,18 +584,14 @@ private:
}
}
- SkAutoTUnref<SkFlatController> fController;
- size_t fScratchSize; // How many bytes fScratch has allocated for data itself.
- SkFlatData* fScratch; // Owned, must be freed with sk_free.
- SkOrderedWriteBuffer fWriteBuffer;
- bool fWriteBufferReady;
+ SkFlatController * const fController;
+ int fNextIndex;
// SkFlatDictionary has two copies of the data one indexed by the
// SkFlatData's index and the other sorted. The sorted data is used
// for finding and uniquification while the indexed copy is used
// for standard array-style lookups based on the SkFlatData's index
// (as in 'unflatten').
- int fNextIndex;
SkTDArray<const SkFlatData*> fIndexedData;
// fSortedData is sorted by checksum/size/data.
SkTDArray<const SkFlatData*> fSortedData;
@@ -732,19 +645,20 @@ public:
this->setTypefacePlayback(&fTypefacePlayback);
}
+ ~SkChunkFlatController() {
+ fTypefaceSet->unref();
+ }
+
virtual void* allocThrow(size_t bytes) SK_OVERRIDE {
- fLastAllocated = fHeap.allocThrow(bytes);
- return fLastAllocated;
+ return fHeap.allocThrow(bytes);
}
virtual void unalloc(void* ptr) SK_OVERRIDE {
- // fHeap can only free a pointer if it was the last one allocated. Otherwise, we'll just
- // have to wait until fHeap is destroyed.
- if (ptr == fLastAllocated) (void)fHeap.unalloc(ptr);
+ (void) fHeap.unalloc(ptr);
}
void setupPlaybacks() const {
- fTypefacePlayback.reset(fTypefaceSet.get());
+ fTypefacePlayback.reset(fTypefaceSet);
}
void setBitmapStorage(SkBitmapHeap* heap) {
@@ -753,16 +667,23 @@ public:
private:
SkChunkAlloc fHeap;
- SkAutoTUnref<SkRefCntSet> fTypefaceSet;
- void* fLastAllocated;
+ SkRefCntSet* fTypefaceSet;
mutable SkTypefacePlayback fTypefacePlayback;
};
+class SkBitmapDictionary : public SkFlatDictionary<SkBitmap> {
+public:
+ SkBitmapDictionary(SkFlatController* controller)
+ : SkFlatDictionary<SkBitmap>(controller) {
+ fFlattenProc = &SkFlattenObjectProc<SkBitmap>;
+ fUnflattenProc = &SkUnflattenObjectProc<SkBitmap>;
+ }
+};
+
class SkMatrixDictionary : public SkFlatDictionary<SkMatrix> {
public:
- // All matrices fit in 36 bytes.
SkMatrixDictionary(SkFlatController* controller)
- : SkFlatDictionary<SkMatrix>(controller, 36) {
+ : SkFlatDictionary<SkMatrix>(controller) {
fFlattenProc = &flattenMatrix;
fUnflattenProc = &unflattenMatrix;
}
@@ -778,9 +699,8 @@ class SkMatrixDictionary : public SkFlatDictionary<SkMatrix> {
class SkPaintDictionary : public SkFlatDictionary<SkPaint> {
public:
- // The largest paint across ~60 .skps was 500 bytes.
SkPaintDictionary(SkFlatController* controller)
- : SkFlatDictionary<SkPaint>(controller, 512) {
+ : SkFlatDictionary<SkPaint>(controller) {
fFlattenProc = &SkFlattenObjectProc<SkPaint>;
fUnflattenProc = &SkUnflattenObjectProc<SkPaint>;
}