Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(19)

Side by Side Diff: include/core/SkWriter32.h

Issue 137433003: Convert SkWriter32 to use an SkTDArray for its internal storage. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: update android-guarded write buffers Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « bench/WriterBench.cpp ('k') | src/core/SkFlattenableSerialization.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 1
2 /* 2 /*
3 * Copyright 2008 The Android Open Source Project 3 * Copyright 2008 The Android Open Source Project
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 */ 7 */
8 8
9 9
10 #ifndef SkWriter32_DEFINED 10 #ifndef SkWriter32_DEFINED
11 #define SkWriter32_DEFINED 11 #define SkWriter32_DEFINED
12 12
13 #include "SkMatrix.h"
14 #include "SkPath.h"
15 #include "SkPoint.h"
16 #include "SkRRect.h"
17 #include "SkRect.h"
18 #include "SkRegion.h"
19 #include "SkScalar.h"
20 #include "SkStream.h"
21 #include "SkTDArray.h"
13 #include "SkTypes.h" 22 #include "SkTypes.h"
14 23
15 #include "SkScalar.h"
16 #include "SkPath.h"
17 #include "SkPoint.h"
18 #include "SkRect.h"
19 #include "SkRRect.h"
20 #include "SkMatrix.h"
21 #include "SkRegion.h"
22
23 class SkStream;
24 class SkWStream;
25
26 class SkWriter32 : SkNoncopyable { 24 class SkWriter32 : SkNoncopyable {
27 struct BlockHeader;
28 public: 25 public:
29 /** 26 /**
30 * The caller can specify an initial block of storage, which the caller man ages. 27 * The caller can specify an initial block of storage, which the caller man ages.
31 * SkWriter32 will not attempt to free this in its destructor. It is up to the 28 *
32 * implementation to decide if, and how much, of the storage to utilize, an d it 29 * SkWriter32 will try to back reserve and write calls with this external s torage until the
33 * is possible that it may be ignored entirely. 30 * first time an allocation doesn't fit. From then it will use dynamically allocated storage.
31 * This used to be optional behavior, but pipe now relies on it.
34 */ 32 */
35 SkWriter32(size_t minSize, void* initialStorage, size_t storageSize); 33 SkWriter32(void* external = NULL, size_t externalBytes = 0) {
36 34 this->reset(external, externalBytes);
37 SkWriter32(size_t minSize) 35 }
38 : fHead(NULL)
39 , fTail(NULL)
40 , fMinSize(minSize)
41 , fSize(0)
42 , fWrittenBeforeLastBlock(0)
43 {}
44
45 ~SkWriter32();
46 36
47 // return the current offset (will always be a multiple of 4) 37 // return the current offset (will always be a multiple of 4)
48 size_t bytesWritten() const { return fSize; } 38 size_t bytesWritten() const { return fCount * 4; }
49 39
50 SK_ATTR_DEPRECATED("use bytesWritten") 40 SK_ATTR_DEPRECATED("use bytesWritten")
51 size_t size() const { return this->bytesWritten(); } 41 size_t size() const { return this->bytesWritten(); }
52 42
53 // Returns true if we've written only into the storage passed into construct or or reset. 43 void reset(void* external = NULL, size_t externalBytes = 0) {
54 // (You may be able to use this to avoid a call to flatten.) 44 SkASSERT(SkIsAlign4((uintptr_t)external));
55 bool wroteOnlyToStorage() const { 45 SkASSERT(SkIsAlign4(externalBytes));
56 return fHead == &fExternalBlock && this->bytesWritten() <= fExternalBloc k.fSizeOfBlock; 46 fExternal = (uint32_t*)external;
47 fExternalLimit = externalBytes/4;
48 fCount = 0;
49 fInternal.rewind();
57 } 50 }
58 51
59 void reset(); 52 // If all data written is contiguous, then this returns a pointer to it, oth erwise NULL.
60 void reset(void* storage, size_t size); 53 // This will work if we've only written to the externally supplied block of storage, or if we've
54 // only written to our internal dynamic storage, but will fail if we have wr itten into both.
55 const uint32_t* contiguousArray() const {
56 if (this->externalCount() == 0) {
57 return fInternal.begin();
58 } else if (fInternal.isEmpty()) {
59 return fExternal;
60 }
61 return NULL;
62 }
61 63
62 // size MUST be multiple of 4 64 // size MUST be multiple of 4
63 uint32_t* reserve(size_t size) { 65 uint32_t* reserve(size_t size) {
64 SkASSERT(SkAlign4(size) == size); 66 SkASSERT(SkAlign4(size) == size);
67 const int count = size/4;
65 68
66 Block* block = fTail; 69 uint32_t* p;
67 if (NULL == block || block->available() < size) { 70 // Once we start writing to fInternal, we never write to fExternal again .
68 block = this->doReserve(size); 71 // This simplifies tracking what data is where.
72 if (fInternal.isEmpty() && this->externalCount() + count <= fExternalLim it) {
73 p = fExternal + fCount;
74 } else {
75 p = fInternal.append(count);
69 } 76 }
70 fSize += size; 77
71 return block->alloc(size); 78 fCount += count;
79 return p;
80 }
81
82 // return the address of the 4byte int at the specified offset (which must
83 // be a multiple of 4. This does not allocate any new space, so the returned
84 // address is only valid for 1 int.
85 uint32_t* peek32(size_t offset) {
86 SkASSERT(SkAlign4(offset) == offset);
87 const int count = offset/4;
88 SkASSERT(count < fCount);
89
90 if (count < this->externalCount()) {
91 return fExternal + count;
92 }
93 return &fInternal[count - this->externalCount()];
72 } 94 }
73 95
74 bool writeBool(bool value) { 96 bool writeBool(bool value) {
75 this->writeInt(value); 97 this->write32(value);
76 return value; 98 return value;
77 } 99 }
78 100
79 void writeInt(int32_t value) { 101 void writeInt(int32_t value) {
80 *(int32_t*)this->reserve(sizeof(value)) = value; 102 this->write32(value);
81 } 103 }
82 104
83 void write8(int32_t value) { 105 void write8(int32_t value) {
84 *(int32_t*)this->reserve(sizeof(value)) = value & 0xFF; 106 *(int32_t*)this->reserve(sizeof(value)) = value & 0xFF;
85 } 107 }
86 108
87 void write16(int32_t value) { 109 void write16(int32_t value) {
88 *(int32_t*)this->reserve(sizeof(value)) = value & 0xFFFF; 110 *(int32_t*)this->reserve(sizeof(value)) = value & 0xFFFF;
89 } 111 }
90 112
91 void write32(int32_t value) { 113 void write32(int32_t value) {
92 *(int32_t*)this->reserve(sizeof(value)) = value; 114 *(int32_t*)this->reserve(sizeof(value)) = value;
93 } 115 }
94 116
95 void writePtr(void* ptr) { 117 void writePtr(void* value) {
96 // Since we "know" that we're always 4-byte aligned, we can tell the 118 *(void**)this->reserve(sizeof(value)) = value;
97 // compiler that here, by assigning to an int32 ptr.
98 int32_t* addr = (int32_t*)this->reserve(sizeof(void*));
99 if (4 == sizeof(void*)) {
100 *(void**)addr = ptr;
101 } else {
102 memcpy(addr, &ptr, sizeof(void*));
103 }
104 } 119 }
105 120
106 void writeScalar(SkScalar value) { 121 void writeScalar(SkScalar value) {
107 *(SkScalar*)this->reserve(sizeof(value)) = value; 122 *(SkScalar*)this->reserve(sizeof(value)) = value;
108 } 123 }
109 124
110 void writePoint(const SkPoint& pt) { 125 void writePoint(const SkPoint& pt) {
111 *(SkPoint*)this->reserve(sizeof(pt)) = pt; 126 *(SkPoint*)this->reserve(sizeof(pt)) = pt;
112 } 127 }
113 128
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
145 void writeMul4(const void* values, size_t size) { 160 void writeMul4(const void* values, size_t size) {
146 this->write(values, size); 161 this->write(values, size);
147 } 162 }
148 163
149 /** 164 /**
150 * Write size bytes from values. size must be a multiple of 4, though 165 * Write size bytes from values. size must be a multiple of 4, though
151 * values need not be 4-byte aligned. 166 * values need not be 4-byte aligned.
152 */ 167 */
153 void write(const void* values, size_t size) { 168 void write(const void* values, size_t size) {
154 SkASSERT(SkAlign4(size) == size); 169 SkASSERT(SkAlign4(size) == size);
155 // if we could query how much is avail in the current block, we might 170 // TODO: If we're going to spill from fExternal to fInternal, we might w ant to fill
156 // copy that much, and then alloc the rest. That would reduce the waste 171 // fExternal as much as possible before writing to fInternal.
157 // in the current block
158 memcpy(this->reserve(size), values, size); 172 memcpy(this->reserve(size), values, size);
159 } 173 }
160 174
161 /** 175 /**
162 * Reserve size bytes. Does not need to be 4 byte aligned. The remaining sp ace (if any) will be 176 * Reserve size bytes. Does not need to be 4 byte aligned. The remaining sp ace (if any) will be
163 * filled in with zeroes. 177 * filled in with zeroes.
164 */ 178 */
165 uint32_t* reservePad(size_t size); 179 uint32_t* reservePad(size_t size) {
180 uint32_t* p = this->reserve(SkAlign4(size));
181 uint8_t* tail = (uint8_t*)p + size;
182 switch (SkAlign4(size) - size) {
183 case 3: *tail++ = 0x00;
184 case 2: *tail++ = 0x00;
185 case 1: *tail++ = 0x00;
reed1 2014/01/14 18:59:37 will we get a 'missing default:' warning here?
mtklein 2014/01/14 19:52:02 I am curious to find out. Kicking off our most an
mtklein 2014/01/14 20:38:16 All the buildbots were totally cool as-is with no
186 }
187 return p;
188 }
166 189
167 /** 190 /**
168 * Write size bytes from src, and pad to 4 byte alignment with zeroes. 191 * Write size bytes from src, and pad to 4 byte alignment with zeroes.
169 */ 192 */
170 void writePad(const void* src, size_t size); 193 void writePad(const void* src, size_t size) {
194 memcpy(this->reservePad(size), src, size);
195 }
171 196
172 /** 197 /**
173 * Writes a string to the writer, which can be retrieved with 198 * Writes a string to the writer, which can be retrieved with
174 * SkReader32::readString(). 199 * SkReader32::readString().
175 * The length can be specified, or if -1 is passed, it will be computed by 200 * The length can be specified, or if -1 is passed, it will be computed by
176 * calling strlen(). The length must be < max size_t. 201 * calling strlen(). The length must be < max size_t.
177 * 202 *
178 * If you write NULL, it will be read as "". 203 * If you write NULL, it will be read as "".
179 */ 204 */
180 void writeString(const char* str, size_t len = (size_t)-1); 205 void writeString(const char* str, size_t len = (size_t)-1);
181 206
182 /** 207 /**
183 * Computes the size (aligned to multiple of 4) need to write the string 208 * Computes the size (aligned to multiple of 4) need to write the string
184 * in a call to writeString(). If the length is not specified, it will be 209 * in a call to writeString(). If the length is not specified, it will be
185 * computed by calling strlen(). 210 * computed by calling strlen().
186 */ 211 */
187 static size_t WriteStringSize(const char* str, size_t len = (size_t)-1); 212 static size_t WriteStringSize(const char* str, size_t len = (size_t)-1);
188 213
189 // return the address of the 4byte int at the specified offset (which must
190 // be a multiple of 4. This does not allocate any new space, so the returned
191 // address is only valid for 1 int.
192 uint32_t* peek32(size_t offset);
193
194 /** 214 /**
195 * Move the cursor back to offset bytes from the beginning. 215 * Move the cursor back to offset bytes from the beginning.
196 * This has the same restrictions as peek32: offset must be <= size() and 216 * This has the same restrictions as peek32: offset must be <= size() and
197 * offset must be a multiple of 4. 217 * offset must be a multiple of 4.
198 */ 218 */
199 void rewindToOffset(size_t offset); 219 void rewindToOffset(size_t offset) {
220 SkASSERT(SkAlign4(offset) == offset);
221 const int count = offset/4;
222 if (count < this->externalCount()) {
223 fInternal.setCount(0);
224 } else {
225 fInternal.setCount(count - this->externalCount());
226 }
227 fCount = count;
228 }
200 229
201 // copy into a single buffer (allocated by caller). Must be at least size() 230 // copy into a single buffer (allocated by caller). Must be at least size()
202 void flatten(void* dst) const; 231 void flatten(void* dst) const {
232 const size_t externalBytes = this->externalCount()*4;
233 memcpy(dst, fExternal, externalBytes);
234 dst = (uint8_t*)dst + externalBytes;
235 memcpy(dst, fInternal.begin(), fInternal.bytes());
236 }
237
238 bool writeToStream(SkWStream* stream) const {
239 return stream->write(fExternal, this->externalCount()*4)
240 && stream->write(fInternal.begin(), fInternal.bytes());
241 }
203 242
204 // read from the stream, and write up to length bytes. Return the actual 243 // read from the stream, and write up to length bytes. Return the actual
205 // number of bytes written. 244 // number of bytes written.
206 size_t readFromStream(SkStream*, size_t length); 245 size_t readFromStream(SkStream* stream, size_t length) {
207 246 return stream->read(this->reservePad(length), length);
208 bool writeToStream(SkWStream*); 247 }
209 248
210 private: 249 private:
211 struct Block { 250 // Number of uint32_t written into fExternal. <= fExternalLimit.
212 Block* fNext; 251 int externalCount() const { return fCount - fInternal.count(); }
213 char* fBasePtr;
214 size_t fSizeOfBlock; // total space allocated (after this)
215 size_t fAllocatedSoFar; // space used so far
216 252
217 size_t available() const { return fSizeOfBlock - fAllocatedSoFar; } 253 int fCount; // Total number of uint32_t written.
218 char* base() { return fBasePtr; } 254 int fExternalLimit; // Number of uint32_t we can write to fExter nal.
219 const char* base() const { return fBasePtr; } 255 uint32_t* fExternal; // Unmanaged memory block.
220 256 SkTDArray<uint32_t> fInternal; // Managed memory block.
221 uint32_t* alloc(size_t size) {
222 SkASSERT(SkAlign4(size) == size);
223 SkASSERT(this->available() >= size);
224 void* ptr = this->base() + fAllocatedSoFar;
225 fAllocatedSoFar += size;
226 SkASSERT(fAllocatedSoFar <= fSizeOfBlock);
227 return (uint32_t*)ptr;
228 }
229
230 uint32_t* peek32(size_t offset) {
231 SkASSERT(offset <= fAllocatedSoFar + 4);
232 void* ptr = this->base() + offset;
233 return (uint32_t*)ptr;
234 }
235
236 void rewind() {
237 fNext = NULL;
238 fAllocatedSoFar = 0;
239 // keep fSizeOfBlock as is
240 }
241
242 static Block* Create(size_t size) {
243 SkASSERT(SkIsAlign4(size));
244 Block* block = (Block*)sk_malloc_throw(sizeof(Block) + size);
245 block->fNext = NULL;
246 block->fBasePtr = (char*)(block + 1);
247 block->fSizeOfBlock = size;
248 block->fAllocatedSoFar = 0;
249 return block;
250 }
251
252 Block* initFromStorage(void* storage, size_t size) {
253 SkASSERT(SkIsAlign4((intptr_t)storage));
254 SkASSERT(SkIsAlign4(size));
255 Block* block = this;
256 block->fNext = NULL;
257 block->fBasePtr = (char*)storage;
258 block->fSizeOfBlock = size;
259 block->fAllocatedSoFar = 0;
260 return block;
261 }
262 };
263
264 enum {
265 MIN_BLOCKSIZE = sizeof(SkWriter32::Block) + sizeof(intptr_t)
266 };
267
268 Block fExternalBlock;
269 Block* fHead;
270 Block* fTail;
271 size_t fMinSize;
272 size_t fSize;
273 // sum of bytes written in all blocks *before* fTail
274 size_t fWrittenBeforeLastBlock;
275
276 bool isHeadExternallyAllocated() const {
277 return fHead == &fExternalBlock;
278 }
279
280 Block* newBlock(size_t bytes);
281
282 // only call from reserve()
283 Block* doReserve(size_t bytes);
284
285 SkDEBUGCODE(void validate() const;)
286 }; 257 };
287 258
288 /** 259 /**
289 * Helper class to allocated SIZE bytes as part of the writer, and to provide 260 * Helper class to allocated SIZE bytes as part of the writer, and to provide
290 * that storage to the constructor as its initial storage buffer. 261 * that storage to the constructor as its initial storage buffer.
291 * 262 *
292 * This wrapper ensures proper alignment rules are met for the storage. 263 * This wrapper ensures proper alignment rules are met for the storage.
293 */ 264 */
294 template <size_t SIZE> class SkSWriter32 : public SkWriter32 { 265 template <size_t SIZE> class SkSWriter32 : public SkWriter32 {
295 public: 266 public:
296 SkSWriter32(size_t minSize) : SkWriter32(minSize, fData.fStorage, SIZE) {} 267 SkSWriter32() : SkWriter32(fData.fStorage, SIZE) {}
297 268
298 private: 269 private:
299 union { 270 union {
300 void* fPtrAlignment; 271 void* fPtrAlignment;
301 double fDoubleAlignment; 272 double fDoubleAlignment;
302 char fStorage[SIZE]; 273 char fStorage[SIZE];
303 } fData; 274 } fData;
304 }; 275 };
305 276
306 #endif 277 #endif
OLDNEW
« no previous file with comments | « bench/WriterBench.cpp ('k') | src/core/SkFlattenableSerialization.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698