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

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

Issue 156683004: Cleaner external buffer handling in SkWriter32 (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Review fixes (spaced and comments) Created 6 years, 10 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
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
(...skipping 12 matching lines...) Expand all
23 23
24 class SkWriter32 : SkNoncopyable { 24 class SkWriter32 : SkNoncopyable {
25 public: 25 public:
26 /** 26 /**
27 * 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.
28 * 28 *
29 * SkWriter32 will try to back reserve and write calls with this external s torage until the 29 * SkWriter32 will try to back reserve and write calls with this external s torage until the
30 * first time an allocation doesn't fit. From then it will use dynamically allocated storage. 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. 31 * This used to be optional behavior, but pipe now relies on it.
32 */ 32 */
33 SkWriter32(void* external = NULL, size_t externalBytes = 0) { 33 SkWriter32(void* external = NULL, size_t externalBytes = 0)
34 this->reset(external, externalBytes); 34 : fData((uint8_t*)external)
reed1 2014/02/06 21:41:34 Seems a tiny shame that the constructor and reset(
mtklein 2014/02/06 22:01:24 Agreed. It's equivalent to write this, right? Sk
iancottrell 2014/02/07 12:20:41 It's functionally equivalent, but I have always th
35 , fCapacity(externalBytes)
36 , fUsed(0)
37 , fExternal(external)
38 {
39 SkASSERT(SkIsAlign4((uintptr_t)external));
40 SkASSERT(SkIsAlign4(externalBytes));
35 } 41 }
36 42
37 // return the current offset (will always be a multiple of 4) 43 // return the current offset (will always be a multiple of 4)
38 size_t bytesWritten() const { return fCount * 4; } 44 size_t bytesWritten() const { return fUsed; }
39 45
40 SK_ATTR_DEPRECATED("use bytesWritten") 46 SK_ATTR_DEPRECATED("use bytesWritten")
41 size_t size() const { return this->bytesWritten(); } 47 size_t size() const { return this->bytesWritten(); }
42 48
43 void reset(void* external = NULL, size_t externalBytes = 0) { 49 void reset(void* external = NULL, size_t externalBytes = 0) {
44 SkASSERT(SkIsAlign4((uintptr_t)external)); 50 SkASSERT(SkIsAlign4((uintptr_t)external));
45 SkASSERT(SkIsAlign4(externalBytes)); 51 SkASSERT(SkIsAlign4(externalBytes));
46 fExternal = (uint32_t*)external; 52
47 fExternalLimit = SkToInt(externalBytes/4); 53 fData = (uint8_t*)external;
48 fCount = 0; 54 fCapacity = externalBytes;
49 fInternal.rewind(); 55 fUsed = 0;
56 fExternal = external;
50 } 57 }
51 58
52 // If all data written is contiguous, then this returns a pointer to it, oth erwise NULL. 59 // Returns the current buffer.
53 // This will work if we've only written to the externally supplied block of storage, or if we've 60 // The pointer may be invalidated by any future write calls.
54 // only written to our internal dynamic storage, but will fail if we have wr itten into both.
55 const uint32_t* contiguousArray() const { 61 const uint32_t* contiguousArray() const {
56 if (this->externalCount() == 0) { 62 return (uint32_t*)fData;
57 return fInternal.begin();
58 } else if (fInternal.isEmpty()) {
59 return fExternal;
60 }
61 return NULL;
62 } 63 }
63 64
64 // size MUST be multiple of 4 65 // size MUST be multiple of 4
65 uint32_t* reserve(size_t size) { 66 uint32_t* reserve(size_t size) {
66 SkASSERT(SkAlign4(size) == size); 67 SkASSERT(SkAlign4(size) == size);
67 const int count = SkToInt(size/4); 68 size_t offset = fUsed;
68 69 size_t used = fUsed + size;
mtklein 2014/02/06 22:01:24 This might make more sense if you rename used to r
iancottrell 2014/02/07 12:20:41 Done.
69 uint32_t* p; 70 if (used > fCapacity) {
70 // Once we start writing to fInternal, we never write to fExternal again . 71 grow(used);
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);
76 } 72 }
77 73 fUsed = used;
78 fCount += count; 74 return (uint32_t*)(fData + offset);
79 return p;
80 } 75 }
81 76
82 // Read or write 4 bytes at offset, which must be a multiple of 4 <= size(). 77 // Read or write 4 bytes at offset, which must be a multiple of 4 <= size().
83 uint32_t read32At(size_t offset) { return this->atOffset(offset); } 78 uint32_t read32At(size_t offset) {
84 void write32At(size_t offset, uint32_t val) { this->atOffset(offset) = val; } 79 SkASSERT(SkAlign4(offset) == offset);
80 SkASSERT(offset < fUsed);
81 return *(uint32_t*)(fData + offset);
82 }
83
84 void write32At(size_t offset, uint32_t val) {
85 SkASSERT(SkAlign4(offset) == offset);
86 SkASSERT(offset < fUsed);
87 *(uint32_t*)(fData + offset) = val;
88 }
85 89
86 bool writeBool(bool value) { 90 bool writeBool(bool value) {
87 this->write32(value); 91 this->write32(value);
88 return value; 92 return value;
89 } 93 }
90 94
91 void writeInt(int32_t value) { 95 void writeInt(int32_t value) {
92 this->write32(value); 96 this->write32(value);
93 } 97 }
94 98
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
150 void writeMul4(const void* values, size_t size) { 154 void writeMul4(const void* values, size_t size) {
151 this->write(values, size); 155 this->write(values, size);
152 } 156 }
153 157
154 /** 158 /**
155 * Write size bytes from values. size must be a multiple of 4, though 159 * Write size bytes from values. size must be a multiple of 4, though
156 * values need not be 4-byte aligned. 160 * values need not be 4-byte aligned.
157 */ 161 */
158 void write(const void* values, size_t size) { 162 void write(const void* values, size_t size) {
159 SkASSERT(SkAlign4(size) == size); 163 SkASSERT(SkAlign4(size) == size);
160 // TODO: If we're going to spill from fExternal to fInternal, we might w ant to fill
161 // fExternal as much as possible before writing to fInternal.
162 memcpy(this->reserve(size), values, size); 164 memcpy(this->reserve(size), values, size);
163 } 165 }
164 166
165 /** 167 /**
166 * Reserve size bytes. Does not need to be 4 byte aligned. The remaining sp ace (if any) will be 168 * Reserve size bytes. Does not need to be 4 byte aligned. The remaining sp ace (if any) will be
167 * filled in with zeroes. 169 * filled in with zeroes.
168 */ 170 */
169 uint32_t* reservePad(size_t size) { 171 uint32_t* reservePad(size_t size) {
170 uint32_t* p = this->reserve(SkAlign4(size)); 172 uint32_t* p = this->reserve(SkAlign4(size));
171 uint8_t* tail = (uint8_t*)p + size; 173 uint8_t* tail = (uint8_t*)p + size;
(...skipping 30 matching lines...) Expand all
202 * computed by calling strlen(). 204 * computed by calling strlen().
203 */ 205 */
204 static size_t WriteStringSize(const char* str, size_t len = (size_t)-1); 206 static size_t WriteStringSize(const char* str, size_t len = (size_t)-1);
205 207
206 /** 208 /**
207 * Move the cursor back to offset bytes from the beginning. 209 * Move the cursor back to offset bytes from the beginning.
208 * offset must be a multiple of 4 no greater than size(). 210 * offset must be a multiple of 4 no greater than size().
209 */ 211 */
210 void rewindToOffset(size_t offset) { 212 void rewindToOffset(size_t offset) {
211 SkASSERT(SkAlign4(offset) == offset); 213 SkASSERT(SkAlign4(offset) == offset);
212 const int count = SkToInt(offset/4); 214 SkASSERT(offset <= bytesWritten());
213 if (count < this->externalCount()) { 215 fUsed = offset;
214 fInternal.setCount(0);
215 } else {
216 fInternal.setCount(count - this->externalCount());
217 }
218 fCount = count;
219 } 216 }
220 217
221 // copy into a single buffer (allocated by caller). Must be at least size() 218 // copy into a single buffer (allocated by caller). Must be at least size()
222 void flatten(void* dst) const { 219 void flatten(void* dst) const {
reed1 2014/02/06 21:41:34 A future iteration of the API might deprecate this
mtklein 2014/02/06 22:01:24 Ack. With a .release() and a .writeToStream(), we
iancottrell 2014/02/07 12:20:41 Yes, the stuff to release the buffer is coming in
223 const size_t externalBytes = this->externalCount()*4; 220 memcpy(dst, fData, fUsed);
224 memcpy(dst, fExternal, externalBytes);
225 dst = (uint8_t*)dst + externalBytes;
226 memcpy(dst, fInternal.begin(), fInternal.bytes());
227 } 221 }
228 222
229 bool writeToStream(SkWStream* stream) const { 223 bool writeToStream(SkWStream* stream) const {
230 return stream->write(fExternal, this->externalCount()*4) 224 return stream->write(fData, fUsed);
231 && stream->write(fInternal.begin(), fInternal.bytes());
232 } 225 }
233 226
234 // read from the stream, and write up to length bytes. Return the actual 227 // read from the stream, and write up to length bytes. Return the actual
235 // number of bytes written. 228 // number of bytes written.
236 size_t readFromStream(SkStream* stream, size_t length) { 229 size_t readFromStream(SkStream* stream, size_t length) {
237 return stream->read(this->reservePad(length), length); 230 return stream->read(this->reservePad(length), length);
238 } 231 }
239 232
240 private: 233 private:
241 uint32_t& atOffset(size_t offset) { 234 void grow(size_t size);
242 SkASSERT(SkAlign4(offset) == offset);
243 const int count = SkToInt(offset/4);
244 SkASSERT(count < fCount);
245 235
246 if (count < this->externalCount()) { 236 uint8_t* fData; // Points to either fInternal or fExternal.
247 return fExternal[count]; 237 size_t fCapacity; // Number of bytes we can write to fData.
248 } 238 size_t fUsed; // Number of bytes written.
249 return fInternal[count - this->externalCount()]; 239 void* fExternal; // Unmanaged memory block.
250 } 240 SkTDArray<uint8_t> fInternal; // Managed memory block.
251
252
253 // Number of uint32_t written into fExternal. <= fExternalLimit.
254 int externalCount() const { return fCount - fInternal.count(); }
255
256 int fCount; // Total number of uint32_t written.
257 int fExternalLimit; // Number of uint32_t we can write to fExter nal.
258 uint32_t* fExternal; // Unmanaged memory block.
259 SkTDArray<uint32_t> fInternal; // Managed memory block.
260 }; 241 };
261 242
262 /** 243 /**
263 * Helper class to allocated SIZE bytes as part of the writer, and to provide 244 * Helper class to allocated SIZE bytes as part of the writer, and to provide
264 * that storage to the constructor as its initial storage buffer. 245 * that storage to the constructor as its initial storage buffer.
265 * 246 *
266 * This wrapper ensures proper alignment rules are met for the storage. 247 * This wrapper ensures proper alignment rules are met for the storage.
267 */ 248 */
268 template <size_t SIZE> class SkSWriter32 : public SkWriter32 { 249 template <size_t SIZE> class SkSWriter32 : public SkWriter32 {
269 public: 250 public:
270 SkSWriter32() : SkWriter32(fData.fStorage, SIZE) {} 251 SkSWriter32() : SkWriter32(fData.fStorage, SIZE) {}
271 252
272 private: 253 private:
273 union { 254 union {
274 void* fPtrAlignment; 255 void* fPtrAlignment;
275 double fDoubleAlignment; 256 double fDoubleAlignment;
276 char fStorage[SIZE]; 257 char fStorage[SIZE];
277 } fData; 258 } fData;
278 }; 259 };
279 260
280 #endif 261 #endif
OLDNEW
« no previous file with comments | « include/core/SkTDArray.h ('k') | src/core/SkWriter32.cpp » ('j') | src/core/SkWriter32.cpp » ('J')

Powered by Google App Engine
This is Rietveld 408576698