aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/core/SkPictureFlat.cpp10
-rw-r--r--src/core/SkPictureFlat.h219
-rw-r--r--src/core/SkPictureRecord.cpp8
-rw-r--r--src/core/SkPictureRecord.h8
-rw-r--r--src/pipe/SkGPipeRead.cpp13
-rw-r--r--src/pipe/SkGPipeWrite.cpp286
6 files changed, 337 insertions, 207 deletions
diff --git a/src/core/SkPictureFlat.cpp b/src/core/SkPictureFlat.cpp
index 34d05fce66..763ed60c5c 100644
--- a/src/core/SkPictureFlat.cpp
+++ b/src/core/SkPictureFlat.cpp
@@ -60,11 +60,10 @@ SkRefCnt* SkRefCntPlayback::set(int index, SkRefCnt* obj) {
///////////////////////////////////////////////////////////////////////////////
-SkFlatData* SkFlatData::Create(SkChunkAlloc* heap, const void* obj,
+SkFlatData* SkFlatData::Create(SkFlatController* controller, const void* obj,
int index, void (*flattenProc)(SkOrderedWriteBuffer&, const void*),
SkRefCntSet* refCntRecorder, SkRefCntSet* faceRecorder,
- uint32_t writeBufferflags) {
-
+ uint32_t writeBufferflags, SkFactorySet* fset) {
// a buffer of 256 bytes should be sufficient for most paints, regions,
// and matrices.
intptr_t storage[256];
@@ -76,7 +75,8 @@ SkFlatData* SkFlatData::Create(SkChunkAlloc* heap, const void* obj,
buffer.setTypefaceRecorder(faceRecorder);
}
buffer.setFlags(writeBufferflags);
-
+ buffer.setFactoryRecorder(fset);
+
flattenProc(buffer, obj);
uint32_t size = buffer.size();
SkASSERT(SkIsAlign4(size));
@@ -88,7 +88,7 @@ SkFlatData* SkFlatData::Create(SkChunkAlloc* heap, const void* obj,
* 3. 4-byte sentinel
*/
size_t allocSize = sizeof(SkFlatData) + size + sizeof(uint32_t);
- SkFlatData* result = (SkFlatData*) heap->allocThrow(allocSize);
+ SkFlatData* result = (SkFlatData*) controller->allocThrow(allocSize);
result->fIndex = index;
result->fFlatSize = size;
diff --git a/src/core/SkPictureFlat.h b/src/core/SkPictureFlat.h
index b8f0b083f8..c746c01251 100644
--- a/src/core/SkPictureFlat.h
+++ b/src/core/SkPictureFlat.h
@@ -142,17 +142,40 @@ private:
// which is agnostic to the type of data is is indexing. It is
// also responsible for flattening/unflattening objects but
// details of that operation are hidden in the provided procs
-// SkFlatDictionary: is a abstract templated dictionary that maintains a
+// SkFlatDictionary: is an abstract templated dictionary that maintains a
// searchable set of SkFlataData objects of type T.
+// SkFlatController: is an interface provided to SkFlatDictionary which handles
+// allocation and unallocation in some cases
//
// NOTE: any class that wishes to be used in conjunction with SkFlatDictionary
// must subclass the dictionary and provide the necessary flattening procs.
// The end of this header contains dictionary subclasses for some common classes
-// like SkBitmap, SkMatrix, SkPaint, and SkRegion.
+// like SkBitmap, SkMatrix, SkPaint, and SkRegion. SkFlatController must also
+// be implemented, or SkChunkFlatController can be used to use an
+// SkChunkAllocator and never do replacements.
//
//
///////////////////////////////////////////////////////////////////////////////
+class SkFlatData;
+
+class SkFlatController : public SkRefCnt {
+public:
+ /**
+ * Provide a new block of memory for the SkFlatDictionary to use.
+ */
+ 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.
+ */
+ virtual void unalloc(void* ptr) = 0;
+};
+
class SkFlatData {
public:
/**
@@ -192,6 +215,8 @@ public:
void* data() { return (char*)this + sizeof(*this); }
// Our data is always 32bit aligned, so we can offer this accessor
uint32_t* data32() { return (uint32_t*)this->data(); }
+ // Returns the size of the flattened data.
+ size_t flatSize() const { return fFlatSize; }
void setSentinelInCache() {
this->setSentinel(kInCache_Sentinel);
@@ -210,16 +235,22 @@ public:
}
#endif
- static SkFlatData* Create(SkChunkAlloc* heap, const void* obj, int index,
+ static SkFlatData* Create(SkFlatController* controller, const void* obj, int index,
void (*flattenProc)(SkOrderedWriteBuffer&, const void*),
SkRefCntSet* refCntRecorder = NULL,
SkRefCntSet* faceRecorder = NULL,
- uint32_t writeBufferflags = 0);
+ uint32_t writeBufferflags = 0,
+ SkFactorySet* fset = NULL);
+
void unflatten(void* result,
void (*unflattenProc)(SkOrderedReadBuffer&, void*),
SkRefCntPlayback* refCntPlayback = NULL,
SkTypefacePlayback* facePlayback = NULL) const;
+ // When we purge an entry, we want to reuse an old index for the new entry,
+ // so we expose this setter.
+ void setIndex(int index) { fIndex = index; }
+
// for unittesting
friend bool operator==(const SkFlatData& a, const SkFlatData& b) {
size_t N = (const char*)a.dataStop() - (const char*)a.dataToCompare();
@@ -257,15 +288,30 @@ private:
template <class T>
class SkFlatDictionary {
public:
- SkFlatDictionary(SkChunkAlloc* heap) {
+ SkFlatDictionary(SkFlatController* controller, SkRefCntSet* refSet = NULL,
+ SkRefCntSet* typeFaceSet = NULL,
+ SkFactorySet* factorySet = NULL)
+ : fController(controller), fRefSet(refSet), fTypefaceSet(typeFaceSet)
+ , fFactorySet(factorySet) {
fFlattenProc = NULL;
fUnflattenProc = NULL;
- fHeap = heap;
+ SkASSERT(controller);
+ fController->ref();
+ SkSafeRef(refSet);
+ SkSafeRef(typeFaceSet);
+ SkSafeRef(factorySet);
// set to 1 since returning a zero from find() indicates failure
fNextIndex = 1;
sk_bzero(fHash, sizeof(fHash));
}
+ virtual ~SkFlatDictionary() {
+ fController->unref();
+ SkSafeUnref(fRefSet);
+ SkSafeUnref(fTypefaceSet);
+ SkSafeUnref(fFactorySet);
+ }
+
int count() const { return fData.count(); }
const SkFlatData* operator[](int index) const {
@@ -282,49 +328,66 @@ public:
fNextIndex = 1;
sk_bzero(fHash, sizeof(fHash));
}
-
+
/**
- * Given an element of type T it returns its index in the dictionary. If
- * the element wasn't previously in the dictionary it is automatically added
- *
- * To make the Compare function fast, we write a sentinel value at the end
- * of each block. The blocks in our fData[] all have a 0 sentinel. The
- * newly created block we're comparing against has a -1 in the sentinel.
- *
- * This trick allows Compare to always loop until failure. If it fails on
- * the sentinal value, we know the blocks are equal.
+ * Similar to find. Allows the caller to specify an SkFlatData to replace in
+ * the case of an add. Also tells the caller whether a new SkFlatData was
+ * added and whether the old one was replaced. The parameters added and
+ * replaced are required to be non-NULL. Rather than returning the index of
+ * the entry in the dictionary, it returns the actual SkFlatData.
*/
- int find(const T& element, SkRefCntSet* refCntRecorder = NULL,
- SkRefCntSet* faceRecorder = NULL, uint32_t writeBufferflags = 0) {
-
- SkFlatData* flat = SkFlatData::Create(fHeap, &element, fNextIndex,
- fFlattenProc, refCntRecorder, faceRecorder, writeBufferflags);
-
- int hashIndex = ChecksumToHashIndex(flat->checksum());
- const SkFlatData* candidate = fHash[hashIndex];
- if (candidate && !SkFlatData::Compare(flat, candidate)) {
- (void)fHeap->unalloc(flat);
- return candidate->index();
- }
-
- int index = SkTSearch<SkFlatData>((const SkFlatData**) fData.begin(),
- fData.count(), flat, sizeof(flat), &SkFlatData::Compare);
- if (index >= 0) {
- (void)fHeap->unalloc(flat);
- fHash[hashIndex] = fData[index];
- return fData[index]->index();
+ const SkFlatData* findAndReplace(const T& element,
+ uint32_t writeBufferFlags,
+ const SkFlatData* toReplace, bool* added,
+ bool* replaced) {
+ SkASSERT(added != NULL && replaced != NULL);
+ int oldCount = fData.count();
+ const SkFlatData* flat = this->findAndReturnFlat(element,
+ writeBufferFlags);
+ *added = fData.count() == oldCount + 1;
+ *replaced = false;
+ if (*added && toReplace != NULL) {
+ // First, find the index of the one to replace
+ int indexToReplace = fData.find(toReplace);
+ if (indexToReplace >= 0) {
+ // findAndReturnFlat set the index to fNextIndex and increased
+ // fNextIndex by one. Reuse the index from the one being
+ // replaced and reset fNextIndex to the proper value.
+ const_cast<SkFlatData*>(flat)->setIndex(toReplace->index());
+ fNextIndex--;
+ // Remove from the array.
+ fData.remove(indexToReplace);
+ // Remove from the hash table.
+ int oldHash = ChecksumToHashIndex(toReplace->checksum());
+ if (fHash[oldHash] == toReplace) {
+ fHash[oldHash] = NULL;
+ }
+ // Delete the actual object.
+ fController->unalloc((void*)toReplace);
+ *replaced = true;
+ }
}
+ return flat;
+ }
- index = ~index;
- *fData.insert(index) = flat;
- flat->setSentinelInCache();
- fHash[hashIndex] = flat;
- SkASSERT(fData.count() == fNextIndex);
- return fNextIndex++;
+ /**
+ * Given an element of type T return its 1-based index in the dictionary. If
+ * the element wasn't previously in the dictionary it is automatically
+ * added.
+ *
+ * To make the Compare function fast, we write a sentinel value at the end
+ * of each block. The blocks in our fData[] all have a 0 sentinel. The
+ * newly created block we're comparing against has a -1 in the sentinel.
+ *
+ * This trick allows Compare to always loop until failure. If it fails on
+ * the sentinal value, we know the blocks are equal.
+ */
+ int find(const T& element, uint32_t writeBufferflags = 0) {
+ return this->findAndReturnFlat(element, writeBufferflags)->index();
}
/**
- * Given a pointer to a array of type T we allocate the array and fill it
+ * Given a pointer to an array of type T we allocate the array and fill it
* with the unflattened dictionary contents. The return value is the size of
* the allocated array.
*/
@@ -349,9 +412,45 @@ protected:
void (*fUnflattenProc)(SkOrderedReadBuffer&, void*);
private:
- SkChunkAlloc* fHeap;
- int fNextIndex;
+ SkFlatController * const fController;
+ int fNextIndex;
SkTDArray<const SkFlatData*> fData;
+ SkRefCntSet* fRefSet;
+ SkRefCntSet* fTypefaceSet;
+ SkFactorySet* fFactorySet;
+
+ const SkFlatData* findAndReturnFlat(const T& element,
+ uint32_t writeBufferflags) {
+ SkFlatData* flat = SkFlatData::Create(fController, &element, fNextIndex,
+ fFlattenProc, fRefSet,
+ fTypefaceSet, writeBufferflags,
+ fFactorySet);
+
+ int hashIndex = ChecksumToHashIndex(flat->checksum());
+ const SkFlatData* candidate = fHash[hashIndex];
+ if (candidate && !SkFlatData::Compare(flat, candidate)) {
+ fController->unalloc(flat);
+ return candidate;
+ }
+
+ int index = SkTSearch<SkFlatData>((const SkFlatData**) fData.begin(),
+ fData.count(), flat, sizeof(flat),
+ &SkFlatData::Compare);
+ if (index >= 0) {
+ fController->unalloc(flat);
+ fHash[hashIndex] = fData[index];
+ return fData[index];
+ }
+
+ index = ~index;
+ *fData.insert(index) = flat;
+ SkASSERT(fData.count() == fNextIndex);
+ fNextIndex++;
+ flat->setSentinelInCache();
+ fHash[hashIndex] = flat;
+ return flat;
+ }
+
enum {
// Determined by trying diff values on picture-recording benchmarks
@@ -393,9 +492,29 @@ static void SkUnflattenObjectProc(SkOrderedReadBuffer& buffer, void* obj) {
((T*)obj)->unflatten(buffer);
}
+class SkChunkFlatController : public SkFlatController {
+public:
+ SkChunkFlatController(size_t minSize)
+ : fHeap(minSize) {}
+
+ virtual void* allocThrow(size_t bytes) {
+ return fHeap.allocThrow(bytes);
+ }
+
+ virtual void unalloc(void* ptr) {
+ (void) fHeap.unalloc(ptr);
+ }
+ void reset() { fHeap.reset(); }
+private:
+ SkChunkAlloc fHeap;
+};
+
class SkBitmapDictionary : public SkFlatDictionary<SkBitmap> {
public:
- SkBitmapDictionary(SkChunkAlloc* heap) : SkFlatDictionary<SkBitmap>(heap) {
+ SkBitmapDictionary(SkFlatController* controller, SkRefCntSet* refSet = NULL,
+ SkRefCntSet* typefaceSet = NULL,
+ SkFactorySet* factorySet = NULL)
+ : SkFlatDictionary<SkBitmap>(controller, refSet, typefaceSet, factorySet) {
fFlattenProc = &SkFlattenObjectProc<SkBitmap>;
fUnflattenProc = &SkUnflattenObjectProc<SkBitmap>;
}
@@ -403,7 +522,8 @@ public:
class SkMatrixDictionary : public SkFlatDictionary<SkMatrix> {
public:
- SkMatrixDictionary(SkChunkAlloc* heap) : SkFlatDictionary<SkMatrix>(heap) {
+ SkMatrixDictionary(SkFlatController* controller)
+ : SkFlatDictionary<SkMatrix>(controller) {
fFlattenProc = &flattenMatrix;
fUnflattenProc = &unflattenMatrix;
}
@@ -419,7 +539,9 @@ class SkMatrixDictionary : public SkFlatDictionary<SkMatrix> {
class SkPaintDictionary : public SkFlatDictionary<SkPaint> {
public:
- SkPaintDictionary(SkChunkAlloc* heap) : SkFlatDictionary<SkPaint>(heap) {
+ SkPaintDictionary(SkFlatController* controller, SkRefCntSet* refSet,
+ SkRefCntSet* typefaceSet)
+ : SkFlatDictionary<SkPaint>(controller, refSet, typefaceSet) {
fFlattenProc = &SkFlattenObjectProc<SkPaint>;
fUnflattenProc = &SkUnflattenObjectProc<SkPaint>;
}
@@ -427,7 +549,8 @@ class SkPaintDictionary : public SkFlatDictionary<SkPaint> {
class SkRegionDictionary : public SkFlatDictionary<SkRegion> {
public:
- SkRegionDictionary(SkChunkAlloc* heap) : SkFlatDictionary<SkRegion>(heap) {
+ SkRegionDictionary(SkFlatController* controller)
+ : SkFlatDictionary<SkRegion>(controller) {
fFlattenProc = &flattenRegion;
fUnflattenProc = &unflattenRegion;
}
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp
index ed528f293c..9f5a1c22dc 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -18,9 +18,9 @@ enum {
SkPictureRecord::SkPictureRecord(uint32_t flags) :
fHeap(HEAP_BLOCK_SIZE),
- fBitmaps(&fHeap),
+ fBitmaps(&fHeap, &fRCSet),
fMatrices(&fHeap),
- fPaints(&fHeap),
+ fPaints(&fHeap, &fRCSet, &fTFSet),
fRegions(&fHeap),
fWriter(MIN_WRITER_SIZE),
fRecordFlags(flags) {
@@ -555,7 +555,7 @@ void SkPictureRecord::addPaint(const SkPaint& paint) {
}
void SkPictureRecord::addPaintPtr(const SkPaint* paint) {
- this->addInt(paint ? fPaints.find(*paint, &fRCSet, &fTFSet) : 0);
+ this->addInt(paint ? fPaints.find(*paint) : 0);
}
void SkPictureRecord::addPath(const SkPath& path) {
@@ -666,7 +666,7 @@ int SkPictureRecord::find(const SkBitmap& bitmap) {
uint32_t writeFlags = flattenPixels ?
SkFlattenableWriteBuffer::kForceFlattenBitmapPixels_Flag : 0;
- int index = fBitmaps.find(bitmap, &fRCSet, NULL, writeFlags);
+ int index = fBitmaps.find(bitmap, writeFlags);
if (flattenPixels) {
entry.fIndex = index;
diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h
index 13b9db55c5..23d0828b97 100644
--- a/src/core/SkPictureRecord.h
+++ b/src/core/SkPictureRecord.h
@@ -187,8 +187,11 @@ public:
#endif
private:
- SkChunkAlloc fHeap;
+ SkChunkFlatController fHeap;
+ SkRefCntSet fRCSet;
+ SkRefCntSet fTFSet;
+
SkTDArray<PixelRefDictionaryEntry> fPixelRefDictionary;
SkBitmapDictionary fBitmaps;
SkMatrixDictionary fMatrices;
@@ -201,9 +204,6 @@ private:
// we ref each item in these arrays
SkTDArray<SkPicture*> fPictureRefs;
- SkRefCntSet fRCSet;
- SkRefCntSet fTFSet;
-
uint32_t fRecordFlags;
int fInitialSaveCount;
diff --git a/src/pipe/SkGPipeRead.cpp b/src/pipe/SkGPipeRead.cpp
index 6f79e51f9a..e2cd151d28 100644
--- a/src/pipe/SkGPipeRead.cpp
+++ b/src/pipe/SkGPipeRead.cpp
@@ -105,14 +105,19 @@ public:
}
void addBitmap(int index) {
- SkASSERT(fBitmaps.count() == index);
- SkBitmap* bm = new SkBitmap();
+ index--;
+ SkBitmap* bm;
+ if(fBitmaps.count() == index) {
+ bm = SkNEW(SkBitmap);
+ *fBitmaps.append() = bm;
+ } else {
+ bm = fBitmaps[index];
+ }
bm->unflatten(*fReader);
- *fBitmaps.append() = bm;
}
SkBitmap* getBitmap(unsigned index) {
- return fBitmaps[index];
+ return fBitmaps[index - 1];
}
void addTypeface() {
diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp
index 13b1f843e6..9007163365 100644
--- a/src/pipe/SkGPipeWrite.cpp
+++ b/src/pipe/SkGPipeWrite.cpp
@@ -26,6 +26,7 @@
#include "SkRasterizer.h"
#include "SkShader.h"
#include "SkOrderedWriteBuffer.h"
+#include "SkPictureFlat.h"
static SkFlattenable* get_paintflat(const SkPaint& paint, unsigned paintFlat) {
SkASSERT(paintFlat < kCount_PaintFlats);
@@ -58,6 +59,94 @@ static size_t writeTypeface(SkWriter32* writer, SkTypeface* typeface) {
///////////////////////////////////////////////////////////////////////////////
+class FlattenableHeap : public SkFlatController {
+public:
+ FlattenableHeap(int numFlatsToKeep) : fNumFlatsToKeep(numFlatsToKeep) {}
+
+ ~FlattenableHeap() {
+ fPointers.freeAll();
+ }
+
+ virtual void* allocThrow(size_t bytes) SK_OVERRIDE;
+
+ virtual void unalloc(void* ptr) SK_OVERRIDE;
+
+ const SkFlatData* flatToReplace() const;
+
+ // Mark an SkFlatData as one that should not be returned by flatToReplace.
+ // Takes the result of SkFlatData::index() as its parameter.
+ void markFlatForKeeping(int index) {
+ *fFlatsThatMustBeKept.append() = index;
+ }
+
+ void markAllFlatsSafeToDelete() {
+ fFlatsThatMustBeKept.reset();
+ }
+
+private:
+ // Keep track of the indices (i.e. the result of SkFlatData::index()) of
+ // flats that must be kept, since they are on the current paint.
+ SkTDArray<int> fFlatsThatMustBeKept;
+ SkTDArray<void*> fPointers;
+ const int fNumFlatsToKeep;
+};
+
+void FlattenableHeap::unalloc(void* ptr) {
+ int indexToRemove = fPointers.rfind(ptr);
+ if (indexToRemove >= 0) {
+ sk_free(ptr);
+ fPointers.remove(indexToRemove);
+ }
+}
+
+void* FlattenableHeap::allocThrow(size_t bytes) {
+ void* ptr = sk_malloc_throw(bytes);
+ *fPointers.append() = ptr;
+ return ptr;
+}
+
+const SkFlatData* FlattenableHeap::flatToReplace() const {
+ // First, determine whether we should replace one.
+ if (fPointers.count() > fNumFlatsToKeep) {
+ // Look through the flattenable heap.
+ // TODO: Return the LRU flat.
+ for (int i = 0; i < fPointers.count(); i++) {
+ SkFlatData* potential = (SkFlatData*)fPointers[i];
+ // Make sure that it is not one that must be kept.
+ bool mustKeep = false;
+ for (int j = 0; j < fFlatsThatMustBeKept.count(); j++) {
+ if (potential->index() == fFlatsThatMustBeKept[j]) {
+ mustKeep = true;
+ break;
+ }
+ }
+ if (!mustKeep) {
+ return potential;
+ }
+ }
+ }
+ return NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class FlatDictionary : public SkFlatDictionary<SkFlattenable> {
+public:
+ FlatDictionary(FlattenableHeap* heap, SkFactorySet* factorySet)
+ : SkFlatDictionary<SkFlattenable>(heap, NULL, NULL, factorySet) {
+ fFlattenProc = &flattenFlattenableProc;
+ // No need to define fUnflattenProc since the writer will never
+ // unflatten the data.
+ }
+ static void flattenFlattenableProc(SkOrderedWriteBuffer& buffer,
+ const void* obj) {
+ buffer.writeFlattenable((SkFlattenable*)obj);
+ }
+
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
/*
* Shared heap for storing large things that can be shared, for a stream
* used by multiple readers.
@@ -65,15 +154,15 @@ static size_t writeTypeface(SkWriter32* writer, SkTypeface* typeface) {
* TODO: Store paths (others?)
* TODO: Generalize the LRU caching mechanism
*/
-class Heap {
+class SharedHeap {
public:
- Heap(bool shallow, int numOfReaders)
+ SharedHeap(bool shallow, int numOfReaders)
: fBitmapCount(0)
, fMostRecentlyUsed(NULL)
, fLeastRecentlyUsed(NULL)
, fCanDoShallowCopies(shallow)
, fNumberOfReaders(numOfReaders) {}
- ~Heap() {
+ ~SharedHeap() {
BitmapInfo* iter = fMostRecentlyUsed;
while (iter != NULL) {
BitmapInfo* next = iter->fLessRecentlyUsed;
@@ -179,7 +268,7 @@ private:
};
// We just "used" info. Update our LRU accordingly
-void Heap::setMostRecentlyUsed(BitmapInfo* info) {
+void SharedHeap::setMostRecentlyUsed(BitmapInfo* info) {
SkASSERT(info != NULL);
if (info == fMostRecentlyUsed) {
return;
@@ -214,7 +303,7 @@ void Heap::setMostRecentlyUsed(BitmapInfo* info) {
* Given a new bitmap to be added to the cache, return an existing one that
* should be removed to make room, or NULL if there is already room.
*/
-BitmapInfo* Heap::bitmapToReplace(const SkBitmap& bm) const {
+BitmapInfo* SharedHeap::bitmapToReplace(const SkBitmap& bm) const {
// Arbitrarily set a limit of 5. We should test to find the best tradeoff
// between time and space. A lower limit means that we use less space, but
// it also means that we may have to insert the same bitmap into the heap
@@ -312,8 +401,7 @@ public:
virtual void drawData(const void*, size_t) SK_OVERRIDE;
private:
- Heap fHeap;
- SkFactorySet* fFactorySet; // optional, only used if cross-process
+ SharedHeap fSharedHeap;
SkGPipeController* fController;
SkWriter32& fWriter;
size_t fBlockSize; // amount allocated for writer
@@ -345,27 +433,16 @@ private:
}
}
- struct FlatData {
- uint32_t fIndex; // always > 0
- PaintFlats fPaintFlat; // deliberately before fSize so that Compare
- // will ignore it.
- uint32_t fSize;
-
- void* data() { return (char*)this + sizeof(*this); }
-
- static int Compare(const FlatData* a, const FlatData* b) {
- return memcmp(&a->fSize, &b->fSize, a->fSize + sizeof(a->fSize));
- }
- };
-
- SkTDArray<FlatData*> fBitmapArray;
+ // These are only used when in cross process, but with no shared address
+ // space, so bitmaps are flattened.
+ FlattenableHeap fBitmapHeap;
+ SkBitmapDictionary fBitmapDictionary;
int flattenToIndex(const SkBitmap&);
- SkTDArray<FlatData*> fFlatArray;
- size_t fBytesOfFlatData;
+ FlattenableHeap fFlattenableHeap;
+ FlatDictionary fFlatDictionary;
int fCurrFlatIndex[kCount_PaintFlats];
int flattenToIndex(SkFlattenable* obj, PaintFlats);
- int flattenableToReplace(const FlatData& newFlat);
SkPaint fPaint;
void writePaint(const SkPaint&);
@@ -384,58 +461,18 @@ private:
int SkGPipeCanvas::flattenToIndex(const SkBitmap & bitmap) {
SkASSERT(shouldFlattenBitmaps(fFlags));
- SkOrderedWriteBuffer tmpWriter(1024);
- tmpWriter.setFlags((SkFlattenableWriteBuffer::Flags)
- (SkFlattenableWriteBuffer::kInlineFactoryNames_Flag
- | SkFlattenableWriteBuffer::kCrossProcess_Flag));
- tmpWriter.setFactoryRecorder(fFactorySet);
- bitmap.flatten(tmpWriter);
-
- size_t len = tmpWriter.size();
- size_t allocSize = len + sizeof(FlatData);
-
- SkAutoSMalloc<1024> storage(allocSize);
- FlatData* flat = (FlatData*)storage.get();
- flat->fSize = len;
- tmpWriter.flatten(flat->data());
-
- int index = SkTSearch<FlatData>((const FlatData**)fBitmapArray.begin(),
- fBitmapArray.count(), flat, sizeof(flat),
- &FlatData::Compare);
- if (index < 0) {
- index = ~index;
- FlatData* copy = (FlatData*)sk_malloc_throw(allocSize);
- memcpy(copy, flat, allocSize);
- // For bitmaps, we can use zero based indices, since we will never ask
- // for a NULL bitmap (unlike with paint flattenables).
- copy->fIndex = fBitmapArray.count();
- *fBitmapArray.insert(index) = copy;
- if (this->needOpBytes(len)) {
- this->writeOp(kDef_Bitmap_DrawOp, 0, copy->fIndex);
- fWriter.write(copy->data(), len);
- }
- }
- return fBitmapArray[index]->fIndex;
-}
-
-// Return -1 if there is no need to replace a flattenable, or there was not an
-// appropriate one to replace. Otherwise return the index of a flattenable to
-// replace.
-int SkGPipeCanvas::flattenableToReplace(const FlatData& newFlat) {
- // For now, set an arbitrary limit on the size of FlatData we have stored.
- // Note that this is currently a soft limit. If we have reached the limit,
- // we replace one, but do not ensure that we return to below the limit.
- if (fBytesOfFlatData + fFlatArray.bytes() > 1024) {
- for (int i = 0; i < fFlatArray.count(); i++) {
- // Only replace the same paint flat. Since a paint can only have
- // one of each type, replacing one of the same type means that
- // we will not be purging a flat on the same paint.
- if (newFlat.fPaintFlat == fFlatArray[i]->fPaintFlat) {
- return i;
- }
- }
- }
- return -1;
+ uint32_t flags = SkFlattenableWriteBuffer::kInlineFactoryNames_Flag
+ | SkFlattenableWriteBuffer::kCrossProcess_Flag;
+ bool added, replaced;
+ const SkFlatData* flat = fBitmapDictionary.findAndReplace(
+ bitmap, flags, fBitmapHeap.flatToReplace(), &added, &replaced);
+
+ int index = flat->index();
+ if (added && this->needOpBytes(flat->flatSize())) {
+ this->writeOp(kDef_Bitmap_DrawOp, 0, index);
+ fWriter.write(flat->data(), flat->flatSize());
+ }
+ return index;
}
// return 0 for NULL (or unflattenable obj), or index-base-1
@@ -445,79 +482,41 @@ int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) {
return 0;
}
- SkOrderedWriteBuffer tmpWriter(1024);
-
+ uint32_t writeBufferFlags;
if (fFlags & SkGPipeWriter::kCrossProcess_Flag) {
- tmpWriter.setFlags((SkFlattenableWriteBuffer::Flags)
- (SkFlattenableWriteBuffer::kInlineFactoryNames_Flag
- | SkFlattenableWriteBuffer::kCrossProcess_Flag));
- tmpWriter.setFactoryRecorder(fFactorySet);
+ writeBufferFlags = (SkFlattenableWriteBuffer::kInlineFactoryNames_Flag
+ | SkFlattenableWriteBuffer::kCrossProcess_Flag);
} else {
// Needed for bitmap shaders.
- tmpWriter.setFlags(SkFlattenableWriteBuffer::kForceFlattenBitmapPixels_Flag);
+ writeBufferFlags = SkFlattenableWriteBuffer::kForceFlattenBitmapPixels_Flag;
}
- tmpWriter.writeFlattenable(obj);
- size_t len = tmpWriter.size();
- size_t allocSize = len + sizeof(FlatData);
-
- SkAutoSMalloc<1024> storage(allocSize);
- FlatData* flat = (FlatData*)storage.get();
- flat->fSize = len;
- tmpWriter.flatten(flat->data());
-
- int index = SkTSearch<FlatData>((const FlatData**)fFlatArray.begin(),
- fFlatArray.count(), flat, sizeof(FlatData*),
- &FlatData::Compare);
- bool replacedAFlat = false;
- if (index < 0) {
- index = ~index;
- FlatData* copy = (FlatData*)sk_malloc_throw(allocSize);
- memcpy(copy, flat, allocSize);
- copy->fPaintFlat = paintflat;
- int indexToReplace = this->flattenableToReplace(*copy);
- if (indexToReplace >= 0) {
- replacedAFlat = true;
- FlatData* oldData = fFlatArray[indexToReplace];
- copy->fIndex = oldData->fIndex;
- fBytesOfFlatData -= (sizeof(FlatData) + oldData->fSize);
- sk_free(oldData);
- fFlatArray.remove(indexToReplace);
- if (indexToReplace < index) {
- index--;
- }
- }
- *fFlatArray.insert(index) = copy;
- fBytesOfFlatData += allocSize;
- if (!replacedAFlat) {
- // Call this after the insert, so that count() will have been grown
- // (unless we replaced one, in which case fIndex has already been
- // set properly).
- copy->fIndex = fFlatArray.count();
-// SkDebugf("--- add flattenable[%d] size=%d index=%d\n", paintflat, len, copy->fIndex);
- }
-
- if (this->needOpBytes(len)) {
- this->writeOp(kDef_Flattenable_DrawOp, paintflat, copy->fIndex);
- fWriter.write(copy->data(), len);
- }
+ bool added, replaced;
+ const SkFlatData* flat = fFlatDictionary.findAndReplace(
+ *obj, writeBufferFlags, fFlattenableHeap.flatToReplace(), &added, &replaced);
+ int index = flat->index();
+ if (added && this->needOpBytes(flat->flatSize())) {
+ this->writeOp(kDef_Flattenable_DrawOp, paintflat, index);
+ fWriter.write(flat->data(), flat->flatSize());
}
- int retVal = fFlatArray[index]->fIndex;
- if (replacedAFlat) {
- retVal = ~retVal;
+ if (replaced) {
+ index = ~index;
}
- return retVal;
+ return index;
}
///////////////////////////////////////////////////////////////////////////////
#define MIN_BLOCK_SIZE (16 * 1024)
+#define BITMAPS_TO_KEEP 5
+#define FLATTENABLES_TO_KEEP 10
SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
SkWriter32* writer, SkFactorySet* fset, uint32_t flags)
-: fHeap(!(flags & SkGPipeWriter::kCrossProcess_Flag), controller->numberOfReaders())
-, fWriter(*writer), fFlags(flags), fBytesOfFlatData(0) {
- fFactorySet = fset;
+: fSharedHeap(!(flags & SkGPipeWriter::kCrossProcess_Flag), controller->numberOfReaders())
+, fWriter(*writer), fFlags(flags)
+, fBitmapHeap(BITMAPS_TO_KEEP), fBitmapDictionary(&fBitmapHeap, NULL, NULL, fset)
+, fFlattenableHeap(FLATTENABLES_TO_KEEP), fFlatDictionary(&fFlattenableHeap, fset) {
fController = controller;
fDone = false;
fBlockSize = 0; // need first block from controller
@@ -539,9 +538,6 @@ SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
SkGPipeCanvas::~SkGPipeCanvas() {
this->finish();
-
- fFlatArray.freeAll();
- fBitmapArray.freeAll();
}
bool SkGPipeCanvas::needOpBytes(size_t needed) {
@@ -791,7 +787,7 @@ void SkGPipeCanvas::drawBitmap(const SkBitmap& bm, SkScalar left, SkScalar top,
if (flatten) {
bitmapIndex = this->flattenToIndex(bm);
} else {
- ptr = fHeap.addBitmap(bm);
+ ptr = fSharedHeap.addBitmap(bm);
if (NULL == ptr) {
return;
}
@@ -825,7 +821,7 @@ void SkGPipeCanvas::drawBitmapRect(const SkBitmap& bm, const SkIRect* src,
if (flatten) {
bitmapIndex = this->flattenToIndex(bm);
} else {
- ptr = fHeap.addBitmap(bm);
+ ptr = fSharedHeap.addBitmap(bm);
if (NULL == ptr) {
return;
}
@@ -874,7 +870,7 @@ void SkGPipeCanvas::drawBitmapNine(const SkBitmap& bm, const SkIRect& center,
if (flatten) {
bitmapIndex = this->flattenToIndex(bm);
} else {
- ptr = fHeap.addBitmap(bm);
+ ptr = fSharedHeap.addBitmap(bm);
if (NULL == ptr) {
return;
}
@@ -911,7 +907,7 @@ void SkGPipeCanvas::drawSprite(const SkBitmap& bm, int left, int top,
if (flatten) {
bitmapIndex = this->flattenToIndex(bm);
} else {
- ptr = fHeap.addBitmap(bm);
+ ptr = fSharedHeap.addBitmap(bm);
if (NULL == ptr) {
return;
}
@@ -1162,13 +1158,19 @@ void SkGPipeCanvas::writePaint(const SkPaint& paint) {
base.setTypeface(paint.getTypeface());
}
+ // This is a new paint, so all old flats can be safely purged, if necessary.
+ fFlattenableHeap.markAllFlatsSafeToDelete();
for (int i = 0; i < kCount_PaintFlats; i++) {
int index = this->flattenToIndex(get_paintflat(paint, i), (PaintFlats)i);
bool replaced = index < 0;
if (replaced) {
index = ~index;
}
- SkASSERT(index >= 0 && index <= fFlatArray.count());
+ // Store the index of any flat that needs to be kept. 0 means no flat.
+ if (index > 0) {
+ fFlattenableHeap.markFlatForKeeping(index);
+ }
+ SkASSERT(index >= 0 && index <= fFlatDictionary.count());
if (index != fCurrFlatIndex[i] || replaced) {
*ptr++ = PaintOp_packOpFlagData(kFlatIndex_PaintOp, i, index);
fCurrFlatIndex[i] = index;