diff options
author | reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2011-05-23 12:21:05 +0000 |
---|---|---|
committer | reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2011-05-23 12:21:05 +0000 |
commit | dde0956375e87027df2fdd80d430dd819c217aac (patch) | |
tree | d44bf1f374734fe72de229b3f12a1464f0ae2cac | |
parent | c7d9f9d8ae3283accf17e77e70fc64cfbfd8121a (diff) |
add cross-process option to gpipe
add unittests for reader32 and writer32
git-svn-id: http://skia.googlecode.com/svn/trunk@1397 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r-- | include/core/SkReader32.h | 9 | ||||
-rw-r--r-- | include/core/SkWriter32.h | 17 | ||||
-rw-r--r-- | include/pipe/SkGPipe.h | 9 | ||||
-rw-r--r-- | samplecode/SampleApp.cpp | 4 | ||||
-rw-r--r-- | src/core/SkWriter32.cpp | 69 | ||||
-rw-r--r-- | src/pipe/SkGPipePriv.h | 2 | ||||
-rw-r--r-- | src/pipe/SkGPipeRead.cpp | 26 | ||||
-rw-r--r-- | src/pipe/SkGPipeWrite.cpp | 34 | ||||
-rw-r--r-- | tests/Reader32Test.cpp | 93 | ||||
-rw-r--r-- | tests/Writer32Test.cpp | 90 | ||||
-rw-r--r-- | tests/tests_files.mk | 2 |
11 files changed, 345 insertions, 10 deletions
diff --git a/include/core/SkReader32.h b/include/core/SkReader32.h index 03a34c7ca6..654ebd5f19 100644 --- a/include/core/SkReader32.h +++ b/include/core/SkReader32.h @@ -101,7 +101,14 @@ public: uint16_t readU16() { return (uint16_t)this->readInt(); } int32_t readS32() { return this->readInt(); } uint32_t readU32() { return this->readInt(); } - + + /** + * Read the length of a string written by SkWriter32::writeString() + * (if len is not NULL) and return the null-ternimated address of the + * string. + */ + const char* readString(size_t* len = NULL); + private: // these are always 4-byte aligned const char* fCurr; // current position within buffer diff --git a/include/core/SkWriter32.h b/include/core/SkWriter32.h index 8e133c2202..c8ebb6a6ef 100644 --- a/include/core/SkWriter32.h +++ b/include/core/SkWriter32.h @@ -100,7 +100,22 @@ public: } void writePad(const void* src, size_t size); - + + /** + * Writes a string to the writer, which can be retrieved with + * SkReader32::readString(). + * The length can be specified, or if -1 is passed, it will be computed by + * calling strlen(). The length must be < 0xFFFF + */ + void writeString(const char* str, size_t len = (size_t)-1); + + /** + * Computes the size (aligned to multiple of 4) need to write the string + * in a call to writeString(). If the length is not specified, it will be + * computed by calling strlen(). + */ + static size_t WriteStringSize(const char* str, size_t len = (size_t)-1); + // return the current offset (will always be a multiple of 4) uint32_t size() const { return fSize; } void reset(); diff --git a/include/pipe/SkGPipe.h b/include/pipe/SkGPipe.h index e9f850260e..0ca66ab9cb 100644 --- a/include/pipe/SkGPipe.h +++ b/include/pipe/SkGPipe.h @@ -19,6 +19,7 @@ #define SkGPipe_DEFINED #include "SkWriter32.h" +#include "SkFlattenable.h" class SkCanvas; @@ -74,7 +75,12 @@ public: ~SkGPipeWriter(); bool isRecording() const { return NULL != fCanvas; } - SkCanvas* startRecording(SkGPipeController*); + + enum Flags { + kCrossProcess_Flag = 1 << 0, + }; + + SkCanvas* startRecording(SkGPipeController*, uint32_t flags = 0); // called in destructor, but can be called sooner once you know there // should be no more drawing calls made into the recording canvas. @@ -83,6 +89,7 @@ public: private: class SkGPipeCanvas* fCanvas; SkGPipeController* fController; + SkFactorySet fFactorySet; SkWriter32 fWriter; }; diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp index 76f4da1e26..fe998ee732 100644 --- a/samplecode/SampleApp.cpp +++ b/samplecode/SampleApp.cpp @@ -1470,7 +1470,9 @@ void SampleView::onDraw(SkCanvas* canvas) { SimplePC controller(canvas); SkGPipeWriter writer; if (fUsePipe) { - canvas = writer.startRecording(&controller); + uint32_t flags = SkGPipeWriter::kCrossProcess_Flag; +// flags = 0; + canvas = writer.startRecording(&controller, flags); } #endif diff --git a/src/core/SkWriter32.cpp b/src/core/SkWriter32.cpp index 141f751982..9a60b8e66f 100644 --- a/src/core/SkWriter32.cpp +++ b/src/core/SkWriter32.cpp @@ -185,3 +185,72 @@ bool SkWriter32::writeToStream(SkWStream* stream) { return true; } +/////////////////////////////////////////////////////////////////////////////// + +#include "SkReader32.h" + +const char* SkReader32::readString(size_t* outLen) { + // we need to read at least 1-4 bytes + SkASSERT(this->isAvailable(4)); + const uint8_t* base = (const uint8_t*)this->peek(); + const uint8_t* ptr = base; + + size_t len = *ptr++; + if (0xFF == len) { + len = (ptr[0] << 8) | ptr[1]; + ptr += 2; + SkASSERT(len < 0xFFFF); + } + + // skip what we've read, and 0..3 pad bytes + // add 1 for the terminating 0 that writeString() included + size_t alignedSize = SkAlign4(len + (ptr - base) + 1); + this->skip(alignedSize); + + if (outLen) { + *outLen = len; + } + return (const char*)ptr; +} + +void SkWriter32::writeString(const char str[], size_t len) { + if ((long)len < 0) { + SkASSERT(str); + len = strlen(str); + } + size_t lenBytes = 1; + if (len >= 0xFF) { + lenBytes = 3; + SkASSERT(len < 0xFFFF); + } + // add 1 since we also write a terminating 0 + size_t alignedLen = SkAlign4(lenBytes + len + 1); + uint8_t* ptr = (uint8_t*)this->reserve(alignedLen); + if (1 == lenBytes) { + *ptr++ = SkToU8(len); + } else { + *ptr++ = 0xFF; + *ptr++ = SkToU8(len >> 8); + *ptr++ = len & 0xFF; + } + memcpy(ptr, str, len); + ptr[len] = 0; + // we may have left 0,1,2,3 bytes uninitialized, since we reserved align4 + // number of bytes. That's ok, since the reader will know to skip those +} + +size_t SkWriter32::WriteStringSize(const char* str, size_t len) { + if ((long)len < 0) { + SkASSERT(str); + len = strlen(str); + } + size_t lenBytes = 1; + if (len >= 0xFF) { + lenBytes = 3; + SkASSERT(len < 0xFFFF); + } + // add 1 since we also write a terminating 0 + return SkAlign4(lenBytes + len + 1); +} + + diff --git a/src/pipe/SkGPipePriv.h b/src/pipe/SkGPipePriv.h index 06ba7b6aaa..fb1553693d 100644 --- a/src/pipe/SkGPipePriv.h +++ b/src/pipe/SkGPipePriv.h @@ -75,6 +75,8 @@ enum DrawOps { kDef_Typeface_DrawOp, kDef_Flattenable_DrawOp, + kName_Flattenable_DrawOp, // index <--> name + // these are signals to playback, not drawing verbs kDone_DrawOp, }; diff --git a/src/pipe/SkGPipeRead.cpp b/src/pipe/SkGPipeRead.cpp index 5e6c632b91..c72aa572d4 100644 --- a/src/pipe/SkGPipeRead.cpp +++ b/src/pipe/SkGPipeRead.cpp @@ -70,7 +70,10 @@ public: SkGPipeState(); ~SkGPipeState(); - void setReader(SkFlattenableReadBuffer* reader) { fReader = reader; } + void setReader(SkFlattenableReadBuffer* reader) { + fReader = reader; + fReader->setFactoryPlayback(fFactoryArray.begin(), fFactoryArray.count()); + } const SkPaint& paint() const { return fPaint; } SkPaint* editPaint() { return &fPaint; } @@ -83,11 +86,21 @@ public: } void defFlattenable(PaintFlats pf, unsigned index) { + SkASSERT(index == fFlatArray.count() + 1); SkFlattenable* obj = fReader->readFlattenable(); *fFlatArray.append() = obj; - SkASSERT(index == fFlatArray.count()); } + void nameFlattenable(PaintFlats pf, unsigned index) { + SkASSERT(index == fFactoryArray.count() + 1); + const char* name = fReader->readString(); + SkFlattenable::Factory fact = SkFlattenable::NameToFactory(name); + *fFactoryArray.append() = fact; + + // update this each time we grow the array + fReader->setFactoryPlayback(fFactoryArray.begin(), fFactoryArray.count()); + } + void addTypeface() { size_t size = fReader->readU32(); const void* data = fReader->skip(SkAlign4(size)); @@ -104,6 +117,7 @@ private: SkPaint fPaint; SkTDArray<SkFlattenable*> fFlatArray; SkTDArray<SkTypeface*> fTypefaces; + SkTDArray<SkFlattenable::Factory> fFactoryArray; }; /////////////////////////////////////////////////////////////////////////////// @@ -430,6 +444,13 @@ static void def_PaintFlat_rp(SkCanvas*, SkReader32*, uint32_t op32, state->defFlattenable(pf, index); } +static void name_PaintFlat_rp(SkCanvas*, SkReader32*, uint32_t op32, + SkGPipeState* state) { + PaintFlats pf = (PaintFlats)DrawOp_unpackFlags(op32); + unsigned index = DrawOp_unpackData(op32); + state->nameFlattenable(pf, index); +} + /////////////////////////////////////////////////////////////////////////////// static void skip_rp(SkCanvas*, SkReader32* reader, uint32_t op32, SkGPipeState*) { @@ -476,6 +497,7 @@ static const ReadProc gReadTable[] = { paintOp_rp, def_Typeface_rp, def_PaintFlat_rp, + name_PaintFlat_rp, done_rp }; diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp index aa6ed821b6..5e8ba3dd2a 100644 --- a/src/pipe/SkGPipeWrite.cpp +++ b/src/pipe/SkGPipeWrite.cpp @@ -77,7 +77,7 @@ static size_t writeTypeface(SkWriter32* writer, SkTypeface* typeface) { class SkGPipeCanvas : public SkCanvas { public: - SkGPipeCanvas(SkGPipeController*, SkWriter32*); + SkGPipeCanvas(SkGPipeController*, SkWriter32*, SkFactorySet*); virtual ~SkGPipeCanvas(); void finish() { @@ -133,6 +133,7 @@ public: virtual void drawData(const void*, size_t); private: + SkFactorySet* fFactorySet; // optional, only used if cross-process SkGPipeController* fController; SkWriter32& fWriter; size_t fBlockSize; // amount allocated for writer @@ -201,7 +202,27 @@ int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) { return 0; } + if (fFactorySet) { + uint32_t id = fFactorySet->find((void*)fact); + if (0 == id) { + const char* name = SkFlattenable::FactoryToName(fact); + if (NULL == name) { + return 0; + } + size_t len = strlen(name); + size_t size = SkWriter32::WriteStringSize(name, len); + if (!this->needOpBytes(size)) { + return 0; + } + unsigned id = fFactorySet->add(fact); + this->writeOp(kName_Flattenable_DrawOp, paintflat, id); + fWriter.writeString(name, len); + } + } + SkFlattenableWriteBuffer tmpWriter(1024); + tmpWriter.setFactoryRecorder(fFactorySet); + tmpWriter.writeFlattenable(obj); size_t len = tmpWriter.size(); size_t allocSize = len + sizeof(FlatData); @@ -236,7 +257,8 @@ int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) { #define MIN_BLOCK_SIZE (16 * 1024) SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller, - SkWriter32* writer) : fWriter(*writer) { + SkWriter32* writer, SkFactorySet* fset) + : fWriter(*writer), fFactorySet(fset) { fController = controller; fDone = false; fBlockSize = 0; // need first block from controller @@ -768,10 +790,14 @@ SkGPipeWriter::~SkGPipeWriter() { SkSafeUnref(fCanvas); } -SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller) { +SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller, + uint32_t flags) { if (NULL == fCanvas) { fWriter.reset(NULL, 0); - fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter)); + fFactorySet.reset(); + fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter, + (flags & kCrossProcess_Flag) ? + &fFactorySet : NULL)); } return fCanvas; } diff --git a/tests/Reader32Test.cpp b/tests/Reader32Test.cpp new file mode 100644 index 0000000000..f57df71d53 --- /dev/null +++ b/tests/Reader32Test.cpp @@ -0,0 +1,93 @@ +/* + Copyright 2011 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +#include "SkReader32.h" +#include "Test.h" + +static void assert_eof(skiatest::Reporter* reporter, const SkReader32& reader) { + REPORTER_ASSERT(reporter, reader.eof()); + REPORTER_ASSERT(reporter, reader.size() == reader.offset()); + REPORTER_ASSERT(reporter, (const char*)reader.peek() == + (const char*)reader.base() + reader.size()); +} + +static void assert_start(skiatest::Reporter* reporter, const SkReader32& reader) { + REPORTER_ASSERT(reporter, 0 == reader.offset()); + REPORTER_ASSERT(reporter, reader.size() == reader.available()); + REPORTER_ASSERT(reporter, reader.isAvailable(reader.size())); + REPORTER_ASSERT(reporter, !reader.isAvailable(reader.size() + 1)); + REPORTER_ASSERT(reporter, reader.peek() == reader.base()); +} + +static void assert_empty(skiatest::Reporter* reporter, const SkReader32& reader) { + REPORTER_ASSERT(reporter, 0 == reader.size()); + REPORTER_ASSERT(reporter, 0 == reader.offset()); + REPORTER_ASSERT(reporter, 0 == reader.available()); + REPORTER_ASSERT(reporter, !reader.isAvailable(1)); + assert_eof(reporter, reader); + assert_start(reporter, reader); +} + +static void Tests(skiatest::Reporter* reporter) { + SkReader32 reader; + assert_empty(reporter, reader); + REPORTER_ASSERT(reporter, NULL == reader.base()); + REPORTER_ASSERT(reporter, NULL == reader.peek()); + + size_t i; + + const int32_t data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + const SkScalar data2[] = { 0, SK_Scalar1, -SK_Scalar1, SK_Scalar1/2 }; + char buffer[SkMax32(sizeof(data), sizeof(data2))]; + + reader.setMemory(data, sizeof(data)); + for (i = 0; i < SK_ARRAY_COUNT(data); ++i) { + REPORTER_ASSERT(reporter, sizeof(data) == reader.size()); + REPORTER_ASSERT(reporter, i*4 == reader.offset()); + REPORTER_ASSERT(reporter, (const void*)data == reader.base()); + REPORTER_ASSERT(reporter, (const void*)&data[i] == reader.peek()); + REPORTER_ASSERT(reporter, data[i] == reader.readInt()); + } + assert_eof(reporter, reader); + reader.rewind(); + assert_start(reporter, reader); + reader.read(buffer, sizeof(buffer)); + REPORTER_ASSERT(reporter, !memcmp(data, buffer, sizeof(buffer))); + + reader.setMemory(data2, sizeof(data2)); + for (i = 0; i < SK_ARRAY_COUNT(data2); ++i) { + REPORTER_ASSERT(reporter, sizeof(data2) == reader.size()); + REPORTER_ASSERT(reporter, i*4 == reader.offset()); + REPORTER_ASSERT(reporter, (const void*)data2 == reader.base()); + REPORTER_ASSERT(reporter, (const void*)&data2[i] == reader.peek()); + REPORTER_ASSERT(reporter, data2[i] == reader.readScalar()); + } + assert_eof(reporter, reader); + reader.rewind(); + assert_start(reporter, reader); + reader.read(buffer, sizeof(buffer)); + REPORTER_ASSERT(reporter, !memcmp(data2, buffer, sizeof(buffer))); + + reader.setMemory(NULL, 0); + assert_empty(reporter, reader); + REPORTER_ASSERT(reporter, NULL == reader.base()); + REPORTER_ASSERT(reporter, NULL == reader.peek()); +} + +#include "TestClassDef.h" +DEFINE_TESTCLASS("Reader32", Reader32Class, Tests) + diff --git a/tests/Writer32Test.cpp b/tests/Writer32Test.cpp new file mode 100644 index 0000000000..63b1209e98 --- /dev/null +++ b/tests/Writer32Test.cpp @@ -0,0 +1,90 @@ +/* + Copyright 2011 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +#include "SkReader32.h" +#include "SkWriter32.h" +#include "Test.h" + +static void test1(skiatest::Reporter* reporter, SkWriter32* writer) { + const uint32_t data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + for (size_t i = 0; i < SK_ARRAY_COUNT(data); ++i) { + REPORTER_ASSERT(reporter, i*4 == writer->size()); + writer->write32(data[i]); + uint32_t* addr = writer->peek32(i * 4); + REPORTER_ASSERT(reporter, data[i] == *addr); + } + + char buffer[sizeof(data)]; + REPORTER_ASSERT(reporter, sizeof(buffer) == writer->size()); + writer->flatten(buffer); + REPORTER_ASSERT(reporter, !memcmp(data, buffer, sizeof(buffer))); +} + +static void test2(skiatest::Reporter* reporter, SkWriter32* writer) { + static const char gStr[] = "abcdefghimjklmnopqrstuvwxyz"; + size_t i; + + size_t len = 0; + for (i = 0; i <= 26; ++i) { + len += SkWriter32::WriteStringSize(gStr, i); + writer->writeString(gStr, i); + } + REPORTER_ASSERT(reporter, writer->size() == len); + + SkAutoMalloc storage(len); + writer->flatten(storage.get()); + + SkReader32 reader; + reader.setMemory(storage.get(), len); + for (i = 0; i <= 26; ++i) { + REPORTER_ASSERT(reporter, !reader.eof()); + const char* str = reader.readString(&len); + REPORTER_ASSERT(reporter, i == len); + REPORTER_ASSERT(reporter, strlen(str) == len); + REPORTER_ASSERT(reporter, !memcmp(str, gStr, len)); + } + REPORTER_ASSERT(reporter, reader.eof()); +} + +static void Tests(skiatest::Reporter* reporter) { + // dynamic allocator + { + SkWriter32 writer(256 * 4); + REPORTER_ASSERT(reporter, NULL == writer.getSingleBlock()); + test1(reporter, &writer); + + writer.reset(); + test2(reporter, &writer); + } + + // single-block + { + SkWriter32 writer(0); + uint32_t storage[256]; + REPORTER_ASSERT(reporter, NULL == writer.getSingleBlock()); + writer.reset(storage, sizeof(storage)); + REPORTER_ASSERT(reporter, (void*)storage == writer.getSingleBlock()); + test1(reporter, &writer); + + writer.reset(storage, sizeof(storage)); + test2(reporter, &writer); + } +} + +#include "TestClassDef.h" +DEFINE_TESTCLASS("Writer32", Writer32Class, Tests) + diff --git a/tests/tests_files.mk b/tests/tests_files.mk index 28d5fe75f9..9b90179c7e 100644 --- a/tests/tests_files.mk +++ b/tests/tests_files.mk @@ -22,6 +22,7 @@ SOURCE := \ ParsePathTest.cpp \ PathMeasureTest.cpp \ PathTest.cpp \ + Reader32Test.cpp \ RefDictTest.cpp \ RegionTest.cpp \ Sk64Test.cpp \ @@ -33,4 +34,5 @@ SOURCE := \ Test.cpp \ TestSize.cpp \ UtilsTest.cpp \ + Writer32Test.cpp \ XfermodeTest.cpp |