Convert SkWriter32 to use an SkTDArray for its internal storage.
This reduces the allocation overhead of a null picture (create, beginRecording(), endRecording) from about 18K to about 1.9K. (There's still lots more to prune.)
SkPictureFlat can exploit the fact that Writer32 is contiguous simplify its memory management. The Writer32 itself becomes the scratch buffer.
Remove lots and lots of arbitrary magic numbers that were size guesses and minimum allocation sizes. Keep your eyes open for the big obvious DUH why we save 16K per picture! (Spoiler alert. It's because that first save we issue in beginRecording() forces the old SkWriter32 to allocate 16K.)
Tests passing, DM passing.
bench --match writer: ~20% faster
null bench_record: ~30% faster
bench_record on buildbot .skps: ~3-6% slower, ranging 25% faster to 20% slower
bench_pictures on buildbot .skps: ~1-2% faster, ranging 13% faster to 28% slower
BUG=skia:1850
R=reed@google.com
Author: mtklein@google.com
Review URL: https://codereview.chromium.org/137433003
git-svn-id: http://skia.googlecode.com/svn/trunk@13073 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkWriter32.cpp b/src/core/SkWriter32.cpp
index e5befba..5e89ed6 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 @@
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);