Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(383)

Unified Diff: src/core/SkPictureFlat.h

Issue 19564007: Start from scratch on a faster SkFlatDictionary. (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: tomhudson Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/core/SkPictureFlat.h
diff --git a/src/core/SkPictureFlat.h b/src/core/SkPictureFlat.h
index 0a147defe8a104da2fcddc205e79dbe86d1f0388..9b3dd74c8ed4d8553f59fe869731c3090e141034 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 SkFlataData objects of type T.
+// searchable set of SkFlatData 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,16 +175,15 @@ public:
SkFlatController();
virtual ~SkFlatController();
/**
- * Provide a new block of memory for the SkFlatDictionary to use.
+ * 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.
*/
virtual void* allocThrow(size_t bytes) = 0;
/**
- * 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.
+ * 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.
*/
virtual void unalloc(void* ptr) = 0;
@@ -400,28 +399,30 @@ private:
SkASSERT(SkIsAlign4(fFlatSize));
this->data32()[fFlatSize >> 2] = value;
}
+
+ void init(int index, int32_t size);
+ template <class T> friend class SkFlatDictionary; // For init().
};
template <class T>
class SkFlatDictionary {
+ static const size_t kWriteBufferGrowthBytes = 1024;
+
public:
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;
+ : fFlattenProc(NULL)
+ , fUnflattenProc(NULL)
+ , fController(SkRef(controller))
+ , fNextIndex(1) // set to 1 since returning a zero from find() indicates failure
+ , fDataSize(0)
+ , fFlatData(this->allocFlatData(fDataSize))
+ , fWriteBuffer(kWriteBufferGrowthBytes)
+ , fWriteBufferReady(false) {
sk_bzero(fHash, sizeof(fHash));
// index 0 is always empty since it is used as a signal that find failed
fIndexedData.push(NULL);
}
- virtual ~SkFlatDictionary() {
- fController->unref();
- }
-
int count() const {
SkASSERT(fIndexedData.count() == fSortedData.count()+1);
return fSortedData.count();
@@ -532,33 +533,36 @@ public:
}
const SkFlatData* findAndReturnFlat(const T& element) {
- SkFlatData* flat = SkFlatData::Create(fController, &element, fNextIndex, fFlattenProc);
+ const SkFlatData& temp = this->getTemporary(element, fNextIndex);
reed1 2013/07/22 18:07:49 scratch
mtklein 2013/07/22 18:54:48 Done.
- int hashIndex = ChecksumToHashIndex(flat->checksum());
+ // See if we have it in the hash?
+ const int hashIndex = ChecksumToHashIndex(temp.checksum());
const SkFlatData* candidate = fHash[hashIndex];
- if (candidate && !SkFlatData::Compare(*flat, *candidate)) {
- fController->unalloc(flat);
- return candidate;
- }
+ if (candidate != NULL && SkFlatData::Compare(temp, *candidate) == 0) return candidate;
- int index = SkTSearch<const SkFlatData,
- SkFlatData::Less>((const SkFlatData**) fSortedData.begin(),
- fSortedData.count(), flat, sizeof(flat));
+ // See if we have it at all?
+ const int index = SkTSearch<const SkFlatData, SkFlatData::Less>(fSortedData.begin(),
+ fSortedData.count(),
+ &temp,
+ sizeof(&temp));
if (index >= 0) {
- fController->unalloc(flat);
+ // Found. Update hash before we return.
fHash[hashIndex] = fSortedData[index];
return fSortedData[index];
}
- index = ~index;
- *fSortedData.insert(index) = flat;
- *fIndexedData.insert(flat->index()) = flat;
+ // We don't have it. Add it.
+ SkFlatData* durable = this->getDurable();
reed1 2013/07/22 18:07:49 Need some clearer naming or something to describe
mtklein 2013/07/22 18:54:48 How's this?
+ *fSortedData.insert(~index) = durable; // SkTSearch returned bit-not of where to insert.
+ *fIndexedData.insert(durable->index()) = durable;
+ fHash[hashIndex] = durable;
+
+ SkASSERT(durable->index() == fNextIndex);
SkASSERT(fSortedData.count() == fNextIndex);
+ SkASSERT(fIndexedData.count() == fNextIndex+1);
fNextIndex++;
- flat->setSentinelInCache();
- fHash[hashIndex] = flat;
- SkASSERT(fIndexedData.count() == fSortedData.count()+1);
- return flat;
+
+ return durable;
}
protected:
@@ -566,6 +570,64 @@ protected:
void (*fUnflattenProc)(SkOrderedReadBuffer&, void*);
private:
+ // Layout: [ SkFlatData header, 20 bytes ] [ data ..., 4-byte aligned ] [ sentinel, 4 bytes]
+ uint8_t* allocFlatData(size_t dataSize) {
+ SkASSERT(SkIsAlign4(dataSize));
+ return (uint8_t*) fController->allocThrow(sizeof(SkFlatData) + dataSize + sizeof(uint32_t));
+ }
+
+ // Returns a pointer to where we should start writing flattened data (just past the header).
+ static uint8_t* dataStart(uint8_t* flatData) {
+ return flatData + sizeof(SkFlatData);
+ }
+
+ // 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;
reed1 2013/07/22 18:07:49 LW nit {}
mtklein 2013/07/22 18:54:48 Done.
+ // 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 getTemporary() or getDurable().
+ const SkFlatData& getTemporary(const T& element, int index) {
+ this->lazyWriteBufferInit();
+
+ // If all the flattened bytes fit into fFlatData, we can skip the call to writeToMemory.
+ fWriteBuffer.reset(this->dataStart(fFlatData), fDataSize);
+ fFlattenProc(fWriteBuffer, &element);
+ const size_t size = fWriteBuffer.size();
reed1 2013/07/22 18:07:49 bytesWritten() ?
mtklein 2013/07/22 18:54:48 Done.
+
+ if (!fWriteBuffer.wroteOnlyToStorage()) {
+ // It didn't all fit. Copy into a bigger replacement fFlatData.
+ SkASSERT(size > fDataSize);
+ uint8_t* bigger = this->allocFlatData(size);
+ fWriteBuffer.writeToMemory(this->dataStart(bigger));
reed1 2013/07/22 18:07:49 can SkFlatData have a dataStart() method, so that
mtklein 2013/07/22 18:54:48 Done.
+ fController->unalloc(fFlatData);
+ fDataSize = size;
+ fFlatData = bigger;
+ }
+
+ // The data is in fFlatData now, but we need to stamp its header and trailing sentinel.
+ SkFlatData* temp = (SkFlatData*)fFlatData;
+ temp->init(index, size);
+ return *temp;
+ }
+
+ // This result is owned by fController and lives as long as it does (unless unalloc'd).
+ SkFlatData* getDurable() {
+ SkFlatData* durable = (SkFlatData*)fFlatData;
+ durable->setSentinelInCache();
+ // The next flat data we see has a good chance of being at least this big.
+ fFlatData = this->allocFlatData(fDataSize);
+ return durable;
+ }
+
void unflatten(T* dst, const SkFlatData* element) const {
element->unflatten(dst, fUnflattenProc,
fController->getBitmapHeap(),
@@ -584,14 +646,18 @@ private:
}
}
- SkFlatController * const fController;
- int fNextIndex;
+ SkAutoTUnref<SkFlatController> fController;
+ size_t fDataSize;
+ uint8_t* fFlatData; // length == sizeof(SkFlatData) + fDataSize + sizeof(uint32_t)
+ SkOrderedWriteBuffer fWriteBuffer;
+ bool fWriteBufferReady;
// 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;
@@ -645,20 +711,19 @@ public:
this->setTypefacePlayback(&fTypefacePlayback);
}
- ~SkChunkFlatController() {
- fTypefaceSet->unref();
- }
-
virtual void* allocThrow(size_t bytes) SK_OVERRIDE {
- return fHeap.allocThrow(bytes);
+ fLastAllocated = fHeap.allocThrow(bytes);
+ return fLastAllocated;
}
virtual void unalloc(void* ptr) SK_OVERRIDE {
- (void) fHeap.unalloc(ptr);
+ // 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 setupPlaybacks() const {
- fTypefacePlayback.reset(fTypefaceSet);
+ fTypefacePlayback.reset(fTypefaceSet.get());
}
void setBitmapStorage(SkBitmapHeap* heap) {
@@ -667,19 +732,11 @@ public:
private:
SkChunkAlloc fHeap;
- SkRefCntSet* fTypefaceSet;
+ SkAutoTUnref<SkRefCntSet> fTypefaceSet;
+ void* fLastAllocated;
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:
SkMatrixDictionary(SkFlatController* controller)

Powered by Google App Engine
This is Rietveld 408576698