diff options
-rw-r--r-- | bench/WriterBench.cpp | 2 | ||||
-rw-r--r-- | include/core/SkWriter32.h | 245 | ||||
-rw-r--r-- | src/core/SkFlattenableSerialization.cpp | 2 | ||||
-rw-r--r-- | src/core/SkOrderedWriteBuffer.cpp | 7 | ||||
-rw-r--r-- | src/core/SkOrderedWriteBuffer.h | 12 | ||||
-rw-r--r-- | src/core/SkPaint.cpp | 6 | ||||
-rw-r--r-- | src/core/SkPictureFlat.h | 90 | ||||
-rw-r--r-- | src/core/SkPicturePlayback.cpp | 3 | ||||
-rw-r--r-- | src/core/SkPictureRecord.cpp | 2 | ||||
-rw-r--r-- | src/core/SkScalerContext.cpp | 2 | ||||
-rw-r--r-- | src/core/SkWriter32.cpp | 234 | ||||
-rw-r--r-- | src/pipe/SkGPipeWrite.cpp | 4 | ||||
-rw-r--r-- | src/utils/SkCanvasStateUtils.cpp | 8 | ||||
-rw-r--r-- | tests/AndroidPaintTest.cpp | 2 | ||||
-rw-r--r-- | tests/ColorFilterTest.cpp | 2 | ||||
-rw-r--r-- | tests/PathTest.cpp | 2 | ||||
-rw-r--r-- | tests/SerializationTest.cpp | 6 | ||||
-rw-r--r-- | tests/Writer32Test.cpp | 106 |
18 files changed, 211 insertions, 524 deletions
diff --git a/bench/WriterBench.cpp b/bench/WriterBench.cpp index 46b26b1efa..7696eab832 100644 --- a/bench/WriterBench.cpp +++ b/bench/WriterBench.cpp @@ -24,7 +24,7 @@ protected: virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { static const char gStr[] = "abcdefghimjklmnopqrstuvwxyz"; static const size_t gLen = strlen(gStr); - SkWriter32 writer(256 * 4); + SkWriter32 writer; for (int i = 0; i < loops; i++) { for (size_t j = 0; j <= gLen; j++) { writer.writeString(gStr, j); diff --git a/include/core/SkWriter32.h b/include/core/SkWriter32.h index 9fb1f7b85b..61d4a95f7e 100644 --- a/include/core/SkWriter32.h +++ b/include/core/SkWriter32.h @@ -10,74 +10,96 @@ #ifndef SkWriter32_DEFINED #define SkWriter32_DEFINED -#include "SkTypes.h" - -#include "SkScalar.h" +#include "SkMatrix.h" #include "SkPath.h" #include "SkPoint.h" -#include "SkRect.h" #include "SkRRect.h" -#include "SkMatrix.h" +#include "SkRect.h" #include "SkRegion.h" - -class SkStream; -class SkWStream; +#include "SkScalar.h" +#include "SkStream.h" +#include "SkTDArray.h" +#include "SkTypes.h" class SkWriter32 : SkNoncopyable { - struct BlockHeader; public: /** * The caller can specify an initial block of storage, which the caller manages. - * SkWriter32 will not attempt to free this in its destructor. It is up to the - * implementation to decide if, and how much, of the storage to utilize, and it - * is possible that it may be ignored entirely. + * + * SkWriter32 will try to back reserve and write calls with this external storage until the + * first time an allocation doesn't fit. From then it will use dynamically allocated storage. + * This used to be optional behavior, but pipe now relies on it. */ - SkWriter32(size_t minSize, void* initialStorage, size_t storageSize); - - SkWriter32(size_t minSize) - : fHead(NULL) - , fTail(NULL) - , fMinSize(minSize) - , fSize(0) - , fWrittenBeforeLastBlock(0) - {} - - ~SkWriter32(); + SkWriter32(void* external = NULL, size_t externalBytes = 0) { + this->reset(external, externalBytes); + } // return the current offset (will always be a multiple of 4) - size_t bytesWritten() const { return fSize; } + size_t bytesWritten() const { return fCount * 4; } SK_ATTR_DEPRECATED("use bytesWritten") size_t size() const { return this->bytesWritten(); } - // 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 flatten.) - bool wroteOnlyToStorage() const { - return fHead == &fExternalBlock && this->bytesWritten() <= fExternalBlock.fSizeOfBlock; + void reset(void* external = NULL, size_t externalBytes = 0) { + SkASSERT(SkIsAlign4((uintptr_t)external)); + SkASSERT(SkIsAlign4(externalBytes)); + fExternal = (uint32_t*)external; + fExternalLimit = externalBytes/4; + fCount = 0; + fInternal.rewind(); } - void reset(); - void reset(void* storage, size_t size); + // If all data written is contiguous, then this returns a pointer to it, otherwise NULL. + // This will work if we've only written to the externally supplied block of storage, or if we've + // only written to our internal dynamic storage, but will fail if we have written into both. + const uint32_t* contiguousArray() const { + if (this->externalCount() == 0) { + return fInternal.begin(); + } else if (fInternal.isEmpty()) { + return fExternal; + } + return NULL; + } // size MUST be multiple of 4 uint32_t* reserve(size_t size) { SkASSERT(SkAlign4(size) == size); + const int count = size/4; + + uint32_t* p; + // Once we start writing to fInternal, we never write to fExternal again. + // This simplifies tracking what data is where. + if (fInternal.isEmpty() && this->externalCount() + count <= fExternalLimit) { + p = fExternal + fCount; + } else { + p = fInternal.append(count); + } + + fCount += count; + return p; + } - Block* block = fTail; - if (NULL == block || block->available() < size) { - block = this->doReserve(size); + // return the address of the 4byte int at the specified offset (which must + // be a multiple of 4. This does not allocate any new space, so the returned + // address is only valid for 1 int. + uint32_t* peek32(size_t offset) { + SkASSERT(SkAlign4(offset) == offset); + const int count = offset/4; + SkASSERT(count < fCount); + + if (count < this->externalCount()) { + return fExternal + count; } - fSize += size; - return block->alloc(size); + return &fInternal[count - this->externalCount()]; } bool writeBool(bool value) { - this->writeInt(value); + this->write32(value); return value; } void writeInt(int32_t value) { - *(int32_t*)this->reserve(sizeof(value)) = value; + this->write32(value); } void write8(int32_t value) { @@ -92,15 +114,8 @@ public: *(int32_t*)this->reserve(sizeof(value)) = value; } - void writePtr(void* ptr) { - // Since we "know" that we're always 4-byte aligned, we can tell the - // compiler that here, by assigning to an int32 ptr. - int32_t* addr = (int32_t*)this->reserve(sizeof(void*)); - if (4 == sizeof(void*)) { - *(void**)addr = ptr; - } else { - memcpy(addr, &ptr, sizeof(void*)); - } + void writePtr(void* value) { + *(void**)this->reserve(sizeof(value)) = value; } void writeScalar(SkScalar value) { @@ -152,9 +167,8 @@ public: */ void write(const void* values, size_t size) { SkASSERT(SkAlign4(size) == size); - // if we could query how much is avail in the current block, we might - // copy that much, and then alloc the rest. That would reduce the waste - // in the current block + // TODO: If we're going to spill from fExternal to fInternal, we might want to fill + // fExternal as much as possible before writing to fInternal. memcpy(this->reserve(size), values, size); } @@ -162,12 +176,25 @@ public: * Reserve size bytes. Does not need to be 4 byte aligned. The remaining space (if any) will be * filled in with zeroes. */ - uint32_t* reservePad(size_t size); + uint32_t* reservePad(size_t size) { + uint32_t* p = this->reserve(SkAlign4(size)); + uint8_t* tail = (uint8_t*)p + size; + switch (SkAlign4(size) - size) { + default: SkDEBUGFAIL("SkAlign4(x) - x should always be 0, 1, 2, or 3."); + case 3: *tail++ = 0x00; // fallthrough is intentional + case 2: *tail++ = 0x00; // fallthrough is intentional + case 1: *tail++ = 0x00; + case 0: ;/*nothing to do*/ + } + return p; + } /** * Write size bytes from src, and pad to 4 byte alignment with zeroes. */ - void writePad(const void* src, size_t size); + void writePad(const void* src, size_t size) { + memcpy(this->reservePad(size), src, size); + } /** * Writes a string to the writer, which can be retrieved with @@ -186,103 +213,49 @@ public: */ static size_t WriteStringSize(const char* str, size_t len = (size_t)-1); - // return the address of the 4byte int at the specified offset (which must - // be a multiple of 4. This does not allocate any new space, so the returned - // address is only valid for 1 int. - uint32_t* peek32(size_t offset); - /** * Move the cursor back to offset bytes from the beginning. * This has the same restrictions as peek32: offset must be <= size() and * offset must be a multiple of 4. */ - void rewindToOffset(size_t offset); + void rewindToOffset(size_t offset) { + SkASSERT(SkAlign4(offset) == offset); + const int count = offset/4; + if (count < this->externalCount()) { + fInternal.setCount(0); + } else { + fInternal.setCount(count - this->externalCount()); + } + fCount = count; + } // copy into a single buffer (allocated by caller). Must be at least size() - void flatten(void* dst) const; + void flatten(void* dst) const { + const size_t externalBytes = this->externalCount()*4; + memcpy(dst, fExternal, externalBytes); + dst = (uint8_t*)dst + externalBytes; + memcpy(dst, fInternal.begin(), fInternal.bytes()); + } + + bool writeToStream(SkWStream* stream) const { + return stream->write(fExternal, this->externalCount()*4) + && stream->write(fInternal.begin(), fInternal.bytes()); + } // read from the stream, and write up to length bytes. Return the actual // number of bytes written. - size_t readFromStream(SkStream*, size_t length); - - bool writeToStream(SkWStream*); - -private: - struct Block { - Block* fNext; - char* fBasePtr; - size_t fSizeOfBlock; // total space allocated (after this) - size_t fAllocatedSoFar; // space used so far - - size_t available() const { return fSizeOfBlock - fAllocatedSoFar; } - char* base() { return fBasePtr; } - const char* base() const { return fBasePtr; } - - uint32_t* alloc(size_t size) { - SkASSERT(SkAlign4(size) == size); - SkASSERT(this->available() >= size); - void* ptr = this->base() + fAllocatedSoFar; - fAllocatedSoFar += size; - SkASSERT(fAllocatedSoFar <= fSizeOfBlock); - return (uint32_t*)ptr; - } - - uint32_t* peek32(size_t offset) { - SkASSERT(offset <= fAllocatedSoFar + 4); - void* ptr = this->base() + offset; - return (uint32_t*)ptr; - } - - void rewind() { - fNext = NULL; - fAllocatedSoFar = 0; - // keep fSizeOfBlock as is - } - - static Block* Create(size_t size) { - SkASSERT(SkIsAlign4(size)); - Block* block = (Block*)sk_malloc_throw(sizeof(Block) + size); - block->fNext = NULL; - block->fBasePtr = (char*)(block + 1); - block->fSizeOfBlock = size; - block->fAllocatedSoFar = 0; - return block; - } - - Block* initFromStorage(void* storage, size_t size) { - SkASSERT(SkIsAlign4((intptr_t)storage)); - SkASSERT(SkIsAlign4(size)); - Block* block = this; - block->fNext = NULL; - block->fBasePtr = (char*)storage; - block->fSizeOfBlock = size; - block->fAllocatedSoFar = 0; - return block; - } - }; - - enum { - MIN_BLOCKSIZE = sizeof(SkWriter32::Block) + sizeof(intptr_t) - }; - - Block fExternalBlock; - Block* fHead; - Block* fTail; - size_t fMinSize; - size_t fSize; - // sum of bytes written in all blocks *before* fTail - size_t fWrittenBeforeLastBlock; - - bool isHeadExternallyAllocated() const { - return fHead == &fExternalBlock; + size_t readFromStream(SkStream* stream, size_t length) { + return stream->read(this->reservePad(length), length); } - Block* newBlock(size_t bytes); - - // only call from reserve() - Block* doReserve(size_t bytes); +private: + // Number of uint32_t written into fExternal. <= fExternalLimit. + int externalCount() const { return fCount - fInternal.count(); } - SkDEBUGCODE(void validate() const;) + int fCount; // Total number of uint32_t written. + int fExternalLimit; // Number of uint32_t we can write to fExternal. + uint32_t* fExternal; // Unmanaged memory block. + SkTDArray<uint32_t> fInternal; // Managed memory block. }; /** @@ -293,7 +266,7 @@ private: */ template <size_t SIZE> class SkSWriter32 : public SkWriter32 { public: - SkSWriter32(size_t minSize) : SkWriter32(minSize, fData.fStorage, SIZE) {} + SkSWriter32() : SkWriter32(fData.fStorage, SIZE) {} private: union { diff --git a/src/core/SkFlattenableSerialization.cpp b/src/core/SkFlattenableSerialization.cpp index b98d935ca7..5c83101eaf 100644 --- a/src/core/SkFlattenableSerialization.cpp +++ b/src/core/SkFlattenableSerialization.cpp @@ -12,7 +12,7 @@ #include "SkOrderedWriteBuffer.h" SkData* SkValidatingSerializeFlattenable(SkFlattenable* flattenable) { - SkOrderedWriteBuffer writer(1024); + SkOrderedWriteBuffer writer; writer.setFlags(SkOrderedWriteBuffer::kValidation_Flag); writer.writeFlattenable(flattenable); uint32_t size = writer.bytesWritten(); diff --git a/src/core/SkOrderedWriteBuffer.cpp b/src/core/SkOrderedWriteBuffer.cpp index 50fdc72869..9107ecd828 100644 --- a/src/core/SkOrderedWriteBuffer.cpp +++ b/src/core/SkOrderedWriteBuffer.cpp @@ -14,21 +14,20 @@ #include "SkStream.h" #include "SkTypeface.h" -SkOrderedWriteBuffer::SkOrderedWriteBuffer(size_t minSize) +SkOrderedWriteBuffer::SkOrderedWriteBuffer() : INHERITED() , fFactorySet(NULL) , fNamedFactorySet(NULL) - , fWriter(minSize) , fBitmapHeap(NULL) , fTFSet(NULL) , fBitmapEncoder(NULL) { } -SkOrderedWriteBuffer::SkOrderedWriteBuffer(size_t minSize, void* storage, size_t storageSize) +SkOrderedWriteBuffer::SkOrderedWriteBuffer(void* storage, size_t storageSize) : INHERITED() , fFactorySet(NULL) , fNamedFactorySet(NULL) - , fWriter(minSize, storage, storageSize) + , fWriter(storage, storageSize) , fBitmapHeap(NULL) , fTFSet(NULL) , fBitmapEncoder(NULL) { diff --git a/src/core/SkOrderedWriteBuffer.h b/src/core/SkOrderedWriteBuffer.h index f3b414e104..1f10152293 100644 --- a/src/core/SkOrderedWriteBuffer.h +++ b/src/core/SkOrderedWriteBuffer.h @@ -25,19 +25,17 @@ class SkRefCntSet; class SkOrderedWriteBuffer : public SkFlattenableWriteBuffer { public: - SkOrderedWriteBuffer(size_t minSize); - SkOrderedWriteBuffer(size_t minSize, void* initialStorage, size_t storageSize); + SkOrderedWriteBuffer(); + SkOrderedWriteBuffer(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 reset(void* storage = NULL, size_t storageSize = 0) { + fWriter.reset(storage, storageSize); + } void writeToMemory(void* dst) { fWriter.flatten(dst); } uint32_t* reserve(size_t size) { return fWriter.reserve(size); } diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp index 94ffa8d31b..af032d001e 100644 --- a/src/core/SkPaint.cpp +++ b/src/core/SkPaint.cpp @@ -1815,9 +1815,7 @@ void SkPaint::descriptorProc(const SkDeviceProperties* deviceProperties, SkMaskFilter* mf = this->getMaskFilter(); SkRasterizer* ra = this->getRasterizer(); - SkOrderedWriteBuffer peBuffer(MIN_SIZE_FOR_EFFECT_BUFFER); - SkOrderedWriteBuffer mfBuffer(MIN_SIZE_FOR_EFFECT_BUFFER); - SkOrderedWriteBuffer raBuffer(MIN_SIZE_FOR_EFFECT_BUFFER); + SkOrderedWriteBuffer peBuffer, mfBuffer, raBuffer; if (pe) { peBuffer.writeFlattenable(pe); @@ -1845,7 +1843,7 @@ void SkPaint::descriptorProc(const SkDeviceProperties* deviceProperties, } #ifdef SK_BUILD_FOR_ANDROID - SkOrderedWriteBuffer androidBuffer(128); + SkOrderedWriteBuffer androidBuffer; fPaintOptionsAndroid.flatten(androidBuffer); descSize += androidBuffer.size(); entryCount += 1; diff --git a/src/core/SkPictureFlat.h b/src/core/SkPictureFlat.h index c3623eec69..8db9609b97 100644 --- a/src/core/SkPictureFlat.h +++ b/src/core/SkPictureFlat.h @@ -271,7 +271,7 @@ public: static SkFlatData* Create(SkFlatController* controller, const T& obj, int index) { // A buffer of 256 bytes should fit most paints, regions, and matrices. uint32_t storage[64]; - SkOrderedWriteBuffer buffer(256, storage, sizeof(storage)); + SkOrderedWriteBuffer buffer(storage, sizeof(storage)); buffer.setBitmapHeap(controller->getBitmapHeap()); buffer.setTypefaceRecorder(controller->getTypefaceSet()); @@ -366,19 +366,14 @@ private: mutable SkScalar fTopBot[2]; // Cache of FontMetrics fTop, fBottom. Starts as [NaN,?]. // uint32_t flattenedData[] implicitly hangs off the end. - template <typename T, typename Traits, int kScratchSizeGuess> friend class SkFlatDictionary; + template <typename T, typename Traits> friend class SkFlatDictionary; }; -template <typename T, typename Traits, int kScratchSizeGuess=0> +template <typename T, typename Traits> class SkFlatDictionary { - static const size_t kWriteBufferGrowthBytes = 1024; - public: explicit SkFlatDictionary(SkFlatController* controller) : fController(SkRef(controller)) - , fScratchSize(0) - , fScratch(NULL) - , fWriteBuffer(kWriteBufferGrowthBytes) , fReady(false) { this->reset(); } @@ -391,10 +386,6 @@ public: fIndexedData.rewind(); } - ~SkFlatDictionary() { - sk_free(fScratch); - } - int count() const { SkASSERT(fHash.count() == fIndexedData.count()); return fHash.count(); @@ -500,35 +491,19 @@ public: } private: - // Layout: [ SkFlatData header, 20 bytes ] [ data ..., 4-byte aligned ] - static size_t SizeWithPadding(size_t flatDataSize) { - SkASSERT(SkIsAlign4(flatDataSize)); - return sizeof(SkFlatData) + flatDataSize; - } - - // Allocate a new scratch SkFlatData. Must be sk_freed. - static SkFlatData* AllocScratch(size_t scratchSize) { - 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. We also delay allocating fScratch - // to avoid unnecessary heap allocations, since we're paying the price of the conditional - // anyway. + // We have to delay fScratch's initialization until its first use; fController might not + // be fully set up by the time we get it in the constructor. void lazyInit() { if (fReady) { return; } - fScratchSize = kScratchSizeGuess; - fScratch = AllocScratch(fScratchSize); - // 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()); + fScratch.setBitmapHeap(fController->getBitmapHeap()); + fScratch.setTypefaceRecorder(fController->getTypefaceSet()); + fScratch.setNamedFactoryRecorder(fController->getNamedFactorySet()); + fScratch.setFlags(fController->getWriteBufferFlags()); fReady = true; } @@ -551,28 +526,17 @@ private: const SkFlatData& resetScratch(const T& element, int index) { this->lazyInit(); - // Flatten element into fWriteBuffer (using fScratch as storage). - fWriteBuffer.reset(fScratch->data(), fScratchSize); - Traits::flatten(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 = 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; - } + // Layout of fScratch: [ SkFlatData header, 20 bytes ] [ data ..., 4-byte aligned ] + fScratch.reset(); + fScratch.reserve(sizeof(SkFlatData)); + Traits::flatten(fScratch, element); + const size_t dataSize = fScratch.bytesWritten() - sizeof(SkFlatData); - // The data is in fScratch now but we need to stamp its header. - fScratch->stampHeader(index, bytesWritten); - return *fScratch; + // Reinterpret data in fScratch as an SkFlatData. + SkFlatData* scratch = (SkFlatData*)fScratch.getWriter32()->contiguousArray(); + SkASSERT(scratch != NULL); + scratch->stampHeader(index, dataSize); + return *scratch; } // This result is owned by fController and lives as long as it does (unless unalloc'd). @@ -580,12 +544,12 @@ private: // 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. - SkASSERT(fScratch != NULL); - const size_t paddedSize = SizeWithPadding(fScratch->flatSize()); - SkFlatData* detached = (SkFlatData*)fController->allocThrow(paddedSize); + SkFlatData* detached = (SkFlatData*)fController->allocThrow(fScratch.bytesWritten()); // Copy scratch into the new SkFlatData. - memcpy(detached, fScratch, paddedSize); + SkFlatData* scratch = (SkFlatData*)fScratch.getWriter32()->contiguousArray(); + SkASSERT(scratch != NULL); + memcpy(detached, scratch, fScratch.bytesWritten()); // We can now reuse fScratch, and detached will live until fController dies. return detached; @@ -599,9 +563,7 @@ private: // All SkFlatData* stored in fIndexedData and fHash are owned by the controller. SkAutoTUnref<SkFlatController> fController; - size_t fScratchSize; // How many bytes fScratch has allocated for data itself. - SkFlatData* fScratch; // Owned, lazily allocated, must be freed with sk_free. - SkOrderedWriteBuffer fWriteBuffer; + SkOrderedWriteBuffer fScratch; bool fReady; // For index -> SkFlatData. 0-based, while all indices in the API are 1-based. Careful! @@ -624,7 +586,7 @@ struct SkMatrixTraits { buffer.getReader32()->readMatrix(matrix); } }; -typedef SkFlatDictionary<SkMatrix, SkMatrixTraits, 36> SkMatrixDictionary; +typedef SkFlatDictionary<SkMatrix, SkMatrixTraits> SkMatrixDictionary; struct SkRegionTraits { @@ -646,7 +608,7 @@ struct SkPaintTraits { paint->unflatten(buffer); } }; -typedef SkFlatDictionary<SkPaint, SkPaintTraits, 512> SkPaintDictionary; +typedef SkFlatDictionary<SkPaint, SkPaintTraits> SkPaintDictionary; class SkChunkFlatController : public SkFlatController { public: diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp index 97e566764b..27f0c58c6d 100644 --- a/src/core/SkPicturePlayback.cpp +++ b/src/core/SkPicturePlayback.cpp @@ -438,8 +438,7 @@ void SkPicturePlayback::serialize(SkWStream* stream, SkRefCntSet typefaceSet; SkFactorySet factSet; - SkOrderedWriteBuffer buffer(1024); - + SkOrderedWriteBuffer buffer; buffer.setFlags(SkFlattenableWriteBuffer::kCrossProcess_Flag); buffer.setTypefaceRecorder(&typefaceSet); buffer.setFactoryRecorder(&factSet); diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp index b7508b3623..4ae1c6b7df 100644 --- a/src/core/SkPictureRecord.cpp +++ b/src/core/SkPictureRecord.cpp @@ -13,7 +13,6 @@ #include "SkDevice.h" #include "SkPictureStateTree.h" -#define MIN_WRITER_SIZE 16384 #define HEAP_BLOCK_SIZE 4096 enum { @@ -36,7 +35,6 @@ SkPictureRecord::SkPictureRecord(uint32_t flags, SkBaseDevice* device) : fMatrices(&fFlattenableHeap), fPaints(&fFlattenableHeap), fRegions(&fFlattenableHeap), - fWriter(MIN_WRITER_SIZE), fRecordFlags(flags) { #ifdef SK_DEBUG_SIZE fPointBytes = fRectBytes = fTextBytes = 0; diff --git a/src/core/SkScalerContext.cpp b/src/core/SkScalerContext.cpp index 04ef2a9222..2a4e9d3d58 100644 --- a/src/core/SkScalerContext.cpp +++ b/src/core/SkScalerContext.cpp @@ -147,7 +147,7 @@ SkScalerContext* SkScalerContext::allocNextContext() const { SkAutoTUnref<SkTypeface> aur(newFace); uint32_t newFontID = newFace->uniqueID(); - SkOrderedWriteBuffer androidBuffer(128); + SkOrderedWriteBuffer androidBuffer; fPaintOptionsAndroid.flatten(androidBuffer); SkAutoDescriptor ad(sizeof(fRec) + androidBuffer.size() + SkDescriptor::ComputeOverhead(2)); diff --git a/src/core/SkWriter32.cpp b/src/core/SkWriter32.cpp index e5befbafb4..5e89ed655b 100644 --- a/src/core/SkWriter32.cpp +++ b/src/core/SkWriter32.cpp @@ -5,239 +5,9 @@ * found in the LICENSE file. */ -#include "SkWriter32.h" - -SkWriter32::SkWriter32(size_t minSize, void* storage, size_t storageSize) { - fMinSize = minSize; - fSize = 0; - fWrittenBeforeLastBlock = 0; - fHead = fTail = NULL; - - if (storageSize) { - this->reset(storage, storageSize); - } -} - -SkWriter32::~SkWriter32() { - this->reset(); -} - -void SkWriter32::reset() { - Block* block = fHead; - - if (this->isHeadExternallyAllocated()) { - SkASSERT(block); - // don't 'free' the first block, since it is owned by the caller - block = block->fNext; - } - while (block) { - Block* next = block->fNext; - sk_free(block); - block = next; - } - - fSize = 0; - fWrittenBeforeLastBlock = 0; - fHead = fTail = NULL; -} - -void SkWriter32::reset(void* storage, size_t storageSize) { - this->reset(); - - storageSize &= ~3; // trunc down to multiple of 4 - if (storageSize > 0 && SkIsAlign4((intptr_t)storage)) { - fHead = fTail = fExternalBlock.initFromStorage(storage, storageSize); - } -} - -SkWriter32::Block* SkWriter32::doReserve(size_t size) { - SkASSERT(SkAlign4(size) == size); - - Block* block = fTail; - SkASSERT(NULL == block || block->available() < size); - - if (NULL == block) { - SkASSERT(NULL == fHead); - fHead = fTail = block = Block::Create(SkMax32(size, fMinSize)); - SkASSERT(0 == fWrittenBeforeLastBlock); - } else { - fWrittenBeforeLastBlock = fSize; - - fTail = Block::Create(SkMax32(size, fMinSize)); - block->fNext = fTail; - block = fTail; - } - return block; -} - -uint32_t* SkWriter32::peek32(size_t offset) { - SkDEBUGCODE(this->validate();) - - SkASSERT(SkAlign4(offset) == offset); - SkASSERT(offset <= fSize); - - // try the fast case, where offset is within fTail - if (offset >= fWrittenBeforeLastBlock) { - return fTail->peek32(offset - fWrittenBeforeLastBlock); - } - - Block* block = fHead; - SkASSERT(NULL != block); - - while (offset >= block->fAllocatedSoFar) { - offset -= block->fAllocatedSoFar; - block = block->fNext; - SkASSERT(NULL != block); - } - return block->peek32(offset); -} - -void SkWriter32::rewindToOffset(size_t offset) { - if (offset >= fSize) { - return; - } - if (0 == offset) { - this->reset(); - return; - } - - SkDEBUGCODE(this->validate();) - - SkASSERT(SkAlign4(offset) == offset); - SkASSERT(offset <= fSize); - fSize = offset; - - // Try the fast case, where offset is within fTail - if (offset >= fWrittenBeforeLastBlock) { - fTail->fAllocatedSoFar = offset - fWrittenBeforeLastBlock; - } else { - // Similar to peek32, except that we free up any following blocks. - // We have to re-compute fWrittenBeforeLastBlock as well. - - size_t globalOffset = offset; - Block* block = fHead; - SkASSERT(NULL != block); - while (offset >= block->fAllocatedSoFar) { - offset -= block->fAllocatedSoFar; - block = block->fNext; - SkASSERT(NULL != block); - } - - // this has to be recomputed, since we may free up fTail - fWrittenBeforeLastBlock = globalOffset - offset; - - // update the size on the "last" block - block->fAllocatedSoFar = offset; - // end our list - fTail = block; - Block* next = block->fNext; - block->fNext = NULL; - // free up any trailing blocks - block = next; - while (block) { - Block* next = block->fNext; - sk_free(block); - block = next; - } - } - SkDEBUGCODE(this->validate();) -} - -void SkWriter32::flatten(void* dst) const { - const Block* block = fHead; - SkDEBUGCODE(size_t total = 0;) - - while (block) { - size_t allocated = block->fAllocatedSoFar; - memcpy(dst, block->base(), allocated); - dst = (char*)dst + allocated; - block = block->fNext; - - SkDEBUGCODE(total += allocated;) - SkASSERT(total <= fSize); - } - SkASSERT(total == fSize); -} - -uint32_t* SkWriter32::reservePad(size_t size) { - if (size > 0) { - size_t alignedSize = SkAlign4(size); - char* dst = (char*)this->reserve(alignedSize); - // Pad the last four bytes with zeroes in one step. - uint32_t* padding = (uint32_t*)(dst + (alignedSize - 4)); - *padding = 0; - return (uint32_t*) dst; - } - return this->reserve(0); -} - -void SkWriter32::writePad(const void* src, size_t size) { - if (size > 0) { - char* dst = (char*)this->reservePad(size); - // Copy the actual data. - memcpy(dst, src, size); - } -} - -#include "SkStream.h" - -size_t SkWriter32::readFromStream(SkStream* stream, size_t length) { - char scratch[1024]; - const size_t MAX = sizeof(scratch); - size_t remaining = length; - - while (remaining != 0) { - size_t n = remaining; - if (n > MAX) { - n = MAX; - } - size_t bytes = stream->read(scratch, n); - this->writePad(scratch, bytes); - remaining -= bytes; - if (bytes != n) { - break; - } - } - return length - remaining; -} - -bool SkWriter32::writeToStream(SkWStream* stream) { - const Block* block = fHead; - while (block) { - if (!stream->write(block->base(), block->fAllocatedSoFar)) { - return false; - } - block = block->fNext; - } - return true; -} - -#ifdef SK_DEBUG -void SkWriter32::validate() const { - SkASSERT(SkIsAlign4(fSize)); - - size_t accum = 0; - const Block* block = fHead; - while (block) { - SkASSERT(SkIsAlign4(block->fSizeOfBlock)); - SkASSERT(SkIsAlign4(block->fAllocatedSoFar)); - SkASSERT(block->fAllocatedSoFar <= block->fSizeOfBlock); - if (NULL == block->fNext) { - SkASSERT(fTail == block); - SkASSERT(fWrittenBeforeLastBlock == accum); - } - accum += block->fAllocatedSoFar; - SkASSERT(accum <= fSize); - block = block->fNext; - } - SkASSERT(accum == fSize); -} -#endif - -/////////////////////////////////////////////////////////////////////////////// - #include "SkReader32.h" #include "SkString.h" +#include "SkWriter32.h" /* * Strings are stored as: length[4-bytes] + string_data + '\0' + pad_to_mul_4 @@ -247,7 +17,7 @@ const char* SkReader32::readString(size_t* outLen) { size_t len = this->readInt(); const void* ptr = this->peek(); - // skip over teh string + '\0' and then pad to a multiple of 4 + // skip over the string + '\0' and then pad to a multiple of 4 size_t alignedSize = SkAlign4(len + 1); this->skip(alignedSize); diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp index 68acc179e7..2948f25d27 100644 --- a/src/pipe/SkGPipeWrite.cpp +++ b/src/pipe/SkGPipeWrite.cpp @@ -370,7 +370,7 @@ void SkGPipeCanvas::flattenFactoryNames() { bool SkGPipeCanvas::shuttleBitmap(const SkBitmap& bm, int32_t slot) { SkASSERT(shouldFlattenBitmaps(fFlags)); - SkOrderedWriteBuffer buffer(1024); + SkOrderedWriteBuffer buffer; buffer.setNamedFactoryRecorder(fFactorySet); buffer.writeBitmap(bm); this->flattenFactoryNames(); @@ -1146,7 +1146,7 @@ void SkGPipeCanvas::writePaint(const SkPaint& paint) { this->writeOp(kSetAnnotation_DrawOp, 0, 0); } } else { - SkOrderedWriteBuffer buffer(1024); + SkOrderedWriteBuffer buffer; paint.getAnnotation()->writeToBuffer(buffer); const size_t size = buffer.bytesWritten(); if (this->needOpBytes(size)) { diff --git a/src/utils/SkCanvasStateUtils.cpp b/src/utils/SkCanvasStateUtils.cpp index 9c7d8fab3a..eb92c37b19 100644 --- a/src/utils/SkCanvasStateUtils.cpp +++ b/src/utils/SkCanvasStateUtils.cpp @@ -155,9 +155,7 @@ static void setup_MC_state(SkMCState* state, const SkMatrix& matrix, const SkReg * and some more common complex clips (e.g. a clipRect with a sub-rect * clipped out of its interior) without needing to malloc any additional memory. */ - const int clipBufferSize = 4 * sizeof(ClipRect); - char clipBuffer[clipBufferSize]; - SkWriter32 clipWriter(sizeof(ClipRect), clipBuffer, clipBufferSize); + SkSWriter32<4*sizeof(ClipRect)> clipWriter; if (!clip.isEmpty()) { // only returns the b/w clip so aa clips fail @@ -201,9 +199,7 @@ SkCanvasState* SkCanvasStateUtils::CaptureCanvasState(SkCanvas* canvas) { * some view systems (e.g. Android) that a few non-clipped layers are present * and we will not need to malloc any additional memory in those cases. */ - const int layerBufferSize = 3 * sizeof(SkCanvasLayerState); - char layerBuffer[layerBufferSize]; - SkWriter32 layerWriter(sizeof(SkCanvasLayerState), layerBuffer, layerBufferSize); + SkSWriter32<3*sizeof(SkCanvasLayerState)> layerWriter; int layerCount = 0; for (SkCanvas::LayerIter layer(canvas, true/*skipEmptyClips*/); !layer.done(); layer.next()) { diff --git a/tests/AndroidPaintTest.cpp b/tests/AndroidPaintTest.cpp index a638da9351..0f6c1e9a96 100644 --- a/tests/AndroidPaintTest.cpp +++ b/tests/AndroidPaintTest.cpp @@ -9,7 +9,7 @@ #include "TestClassDef.h" static size_t Reconstruct(const SkPaint& src, SkPaint* dst) { - SkOrderedWriteBuffer writer(64 /*arbitrary*/); + SkOrderedWriteBuffer writer; src.flatten(writer); const size_t size = writer.bytesWritten(); diff --git a/tests/ColorFilterTest.cpp b/tests/ColorFilterTest.cpp index 8444b73a1d..7ad19b7aff 100644 --- a/tests/ColorFilterTest.cpp +++ b/tests/ColorFilterTest.cpp @@ -17,7 +17,7 @@ #include "SkOrderedWriteBuffer.h" static SkColorFilter* reincarnate_colorfilter(SkFlattenable* obj) { - SkOrderedWriteBuffer wb(1024); + SkOrderedWriteBuffer wb; wb.writeFlattenable(obj); size_t size = wb.size(); diff --git a/tests/PathTest.cpp b/tests/PathTest.cpp index 3f07ae04bc..063f05d5ed 100644 --- a/tests/PathTest.cpp +++ b/tests/PathTest.cpp @@ -1838,7 +1838,7 @@ static void test_isNestedRects(skiatest::Reporter* reporter) { static void write_and_read_back(skiatest::Reporter* reporter, const SkPath& p) { - SkWriter32 writer(100); + SkWriter32 writer; writer.writePath(p); size_t size = writer.bytesWritten(); SkAutoMalloc storage(size); diff --git a/tests/SerializationTest.cpp b/tests/SerializationTest.cpp index a2601d22a7..38e7051d59 100644 --- a/tests/SerializationTest.cpp +++ b/tests/SerializationTest.cpp @@ -111,7 +111,7 @@ template<> struct SerializationUtils<SkScalar> { template<typename T> static void TestObjectSerialization(T* testObj, skiatest::Reporter* reporter) { - SkOrderedWriteBuffer writer(1024); + SkOrderedWriteBuffer writer; writer.setFlags(SkOrderedWriteBuffer::kValidation_Flag); SerializationUtils<T>::Write(writer, testObj); size_t bytesWritten = writer.bytesWritten(); @@ -142,7 +142,7 @@ static void TestObjectSerialization(T* testObj, skiatest::Reporter* reporter) { template<typename T> static T* TestFlattenableSerialization(T* testObj, bool shouldSucceed, skiatest::Reporter* reporter) { - SkOrderedWriteBuffer writer(1024); + SkOrderedWriteBuffer writer; writer.setFlags(SkOrderedWriteBuffer::kValidation_Flag); SerializationUtils<T>::Write(writer, testObj); size_t bytesWritten = writer.bytesWritten(); @@ -181,7 +181,7 @@ static T* TestFlattenableSerialization(T* testObj, bool shouldSucceed, template<typename T> static void TestArraySerialization(T* data, skiatest::Reporter* reporter) { - SkOrderedWriteBuffer writer(1024); + SkOrderedWriteBuffer writer; writer.setFlags(SkOrderedWriteBuffer::kValidation_Flag); SerializationUtils<T>::Write(writer, data, kArraySize); size_t bytesWritten = writer.bytesWritten(); diff --git a/tests/Writer32Test.cpp b/tests/Writer32Test.cpp index 2032fefae7..a76c35d34c 100644 --- a/tests/Writer32Test.cpp +++ b/tests/Writer32Test.cpp @@ -24,13 +24,13 @@ static void test_reserve(skiatest::Reporter* reporter) { // There used to be a bug where we'd assert your first reservation had to // fit in external storage if you used it. This would crash in debug mode. uint8_t storage[4]; - SkWriter32 writer(0, storage, sizeof(storage)); + SkWriter32 writer(storage, sizeof(storage)); writer.reserve(40); } static void test_string_null(skiatest::Reporter* reporter) { uint8_t storage[8]; - SkWriter32 writer(0, storage, sizeof(storage)); + SkWriter32 writer(storage, sizeof(storage)); // Can we write NULL? writer.writeString(NULL); @@ -39,7 +39,7 @@ static void test_string_null(skiatest::Reporter* reporter) { } static void test_rewind(skiatest::Reporter* reporter) { - SkSWriter32<32> writer(32); + SkSWriter32<32> writer; int32_t array[3] = { 1, 2, 4 }; REPORTER_ASSERT(reporter, 0 == writer.bytesWritten()); @@ -58,7 +58,7 @@ static void test_rewind(skiatest::Reporter* reporter) { // test rewinding past allocated chunks. This used to crash because we // didn't truncate our link-list after freeing trailing blocks { - SkWriter32 writer(64); + SkWriter32 writer; for (int i = 0; i < 100; ++i) { writer.writeInt(i); } @@ -71,7 +71,7 @@ static void test_rewind(skiatest::Reporter* reporter) { } static void test_ptr(skiatest::Reporter* reporter) { - SkSWriter32<32> writer(32); + SkSWriter32<32> writer; void* p0 = reporter; void* p1 = &writer; @@ -186,65 +186,59 @@ static void testWritePad(skiatest::Reporter* reporter, SkWriter32* writer) { } } -DEF_TEST(Writer32, reporter) { - // dynamic allocator - { - SkWriter32 writer(256 * 4); - test1(reporter, &writer); +DEF_TEST(Writer32_dynamic, reporter) { + SkWriter32 writer; + test1(reporter, &writer); - writer.reset(); - test2(reporter, &writer); + writer.reset(); + test2(reporter, &writer); - writer.reset(); - testWritePad(reporter, &writer); - } + writer.reset(); + testWritePad(reporter, &writer); +} - // storage-block - { - SkWriter32 writer(0); - uint32_t storage[256]; - writer.reset(storage, sizeof(storage)); - // These three writes are small enough to fit in storage. - test1(reporter, &writer); - REPORTER_ASSERT(reporter, writer.wroteOnlyToStorage()); - - writer.reset(storage, sizeof(storage)); - test2(reporter, &writer); - REPORTER_ASSERT(reporter, writer.wroteOnlyToStorage()); - - writer.reset(storage, sizeof(storage)); - testWritePad(reporter, &writer); - REPORTER_ASSERT(reporter, writer.wroteOnlyToStorage()); - - // Try overflowing the storage-block. - uint32_t smallStorage[8]; - writer.reset(smallStorage, sizeof(smallStorage)); - test2(reporter, &writer); - REPORTER_ASSERT(reporter, !writer.wroteOnlyToStorage()); - } +DEF_TEST(Writer32_contiguous, reporter) { + uint32_t storage[256]; + SkWriter32 writer; + writer.reset(storage, sizeof(storage)); + // This write is small enough to fit in storage, so it's contiguous. + test1(reporter, &writer); + REPORTER_ASSERT(reporter, writer.contiguousArray() != NULL); + + // This write is too big for the 32 byte storage block we provide. + writer.reset(storage, 32); + test2(reporter, &writer); + // Some data is in storage, some in writer's internal storage. + REPORTER_ASSERT(reporter, writer.contiguousArray() == NULL); + + writer.reset(); + test2(reporter, &writer); + // There is no external storage. All the data is in internal storage, + // so we can always read it contiguously. + REPORTER_ASSERT(reporter, writer.contiguousArray() != NULL); +} - // small storage - { - SkSWriter32<8 * sizeof(intptr_t)> writer(100); - test1(reporter, &writer); - writer.reset(); // should just rewind our storage - test2(reporter, &writer); +DEF_TEST(Writer32_small, reporter) { + SkSWriter32<8 * sizeof(intptr_t)> writer; + test1(reporter, &writer); + writer.reset(); // should just rewind our storage + test2(reporter, &writer); - writer.reset(); - testWritePad(reporter, &writer); - } + writer.reset(); + testWritePad(reporter, &writer); +} - // large storage - { - SkSWriter32<1024 * sizeof(intptr_t)> writer(100); - test1(reporter, &writer); - writer.reset(); // should just rewind our storage - test2(reporter, &writer); +DEF_TEST(Writer32_large, reporter) { + SkSWriter32<1024 * sizeof(intptr_t)> writer; + test1(reporter, &writer); + writer.reset(); // should just rewind our storage + test2(reporter, &writer); - writer.reset(); - testWritePad(reporter, &writer); - } + writer.reset(); + testWritePad(reporter, &writer); +} +DEF_TEST(Writer32_misc, reporter) { test_reserve(reporter); test_string_null(reporter); test_ptr(reporter); |