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) |