• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2010 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef skgpu_BufferWriter_DEFINED
9 #define skgpu_BufferWriter_DEFINED
10 
11 #include <type_traits>
12 #include "include/core/SkRect.h"
13 #include "include/private/SkColorData.h"
14 #include "include/private/base/SkTemplates.h"
15 #include "src/base/SkVx.h"
16 #include "src/core/SkConvertPixels.h"
17 
18 namespace skgpu {
19 
20 struct BufferWriter {
21 public:
22     // Marks a read-only position in the underlying buffer
23     struct Mark {
24     public:
MarkBufferWriter::Mark25         Mark() : Mark(nullptr) {}
26         Mark(void* ptr, size_t offset = 0)
27                 : fMark(reinterpret_cast<uintptr_t>(ptr) + offset) {
28             SkASSERT(ptr || offset == 0);
29         }
30 
31         bool operator< (const Mark& o) const { return fMark <  o.fMark; }
32         bool operator<=(const Mark& o) const { return fMark <= o.fMark; }
33         bool operator==(const Mark& o) const { return fMark == o.fMark; }
34         bool operator!=(const Mark& o) const { return fMark != o.fMark; }
35         bool operator>=(const Mark& o) const { return fMark >= o.fMark; }
36         bool operator> (const Mark& o) const { return fMark >  o.fMark; }
37 
38         ptrdiff_t operator-(const Mark& o) const { return fMark - o.fMark; }
39 
40         explicit operator bool() const { return *this != Mark(); }
41     private:
42         uintptr_t fMark;
43     };
44 
45     explicit operator bool() const { return fPtr != nullptr; }
46 
47     Mark mark(size_t offset=0) const {
48         this->validate(offset);
49         return Mark(fPtr, offset);
50     }
51 
52 protected:
53     BufferWriter() = default;
BufferWriterBufferWriter54     BufferWriter(void* ptr, size_t size) : fPtr(ptr) {
55         SkDEBUGCODE(fEnd = Mark(ptr, ptr ? size : 0);)
56     }
fPtrBufferWriter57     BufferWriter(void* ptr, Mark end = {}) : fPtr(ptr) {
58         SkDEBUGCODE(fEnd = end;)
59     }
60 
61     BufferWriter& operator=(const BufferWriter&) = delete;
62     BufferWriter& operator=(BufferWriter&& that) {
63         fPtr = that.fPtr;
64         that.fPtr = nullptr;
65         SkDEBUGCODE(fEnd = that.fEnd;)
66         SkDEBUGCODE(that.fEnd = Mark();)
67         return *this;
68     }
69 
70     // makeOffset effectively splits the current writer from {fPtr, fEnd} into {fPtr, p} and
71     // a new writer {p, fEnd}. The same data range is accessible, but each byte can only be
72     // set by a single writer. Automatically validates that there is enough bytes remaining in this
73     // writer to do such a split.
74     //
75     // This splitting and validation means that providers of BufferWriters to callers can easily
76     // and correctly track everything in a single BufferWriter field and use
77     //    return std::exchange(fCurrWriter, fCurrWriter.makeOffset(requestedBytes));
78     // This exposes the current writer position to the caller and sets the provider's new current
79     // position to be just after the requested bytes.
80     //
81     // Templated so that it can create subclasses directly.
82     template<typename W>
makeOffsetBufferWriter83     W makeOffset(size_t offsetInBytes) const {
84         this->validate(offsetInBytes);
85         void* p = SkTAddOffset<void>(fPtr, offsetInBytes);
86         Mark end{SkDEBUGCODE(fEnd)};
87         SkDEBUGCODE(fEnd = Mark(p);)
88         return W{p, end};
89     }
90 
validateBufferWriter91     void validate(size_t bytesToWrite) const {
92         // If the buffer writer had an end marked, make sure we're not crossing it.
93         // Ideally, all creators of BufferWriters mark the end, but a lot of legacy code is not set
94         // up to easily do this.
95         SkASSERT(fPtr || bytesToWrite == 0);
96         SkASSERT(!fEnd || Mark(fPtr, bytesToWrite) <= fEnd);
97     }
98 
99 protected:
100     void* fPtr = nullptr;
101     SkDEBUGCODE(mutable Mark fEnd = {};)
102 };
103 
104 /**
105  * Helper for writing vertex data to a buffer. Usage:
106  *  VertexWriter vertices{target->makeVertexSpace(...)};
107  *  vertices << A0 << B0 << C0 << ...;
108  *  vertices << A1 << B1 << C1 << ...;
109  *
110  * Each value must be POD (plain old data), or have a specialization of the "<<" operator.
111  */
112 struct VertexWriter : public BufferWriter {
113     inline constexpr static uint32_t kIEEE_32_infinity = 0x7f800000;
114 
115     VertexWriter() = default;
116     // DEPRECATED: Prefer specifying the size of the buffer being written to as well
VertexWriterVertexWriter117     explicit VertexWriter(void* ptr) : BufferWriter(ptr, Mark()) {}
118 
VertexWriterVertexWriter119     VertexWriter(void* ptr, size_t size) : BufferWriter(ptr, size) {}
VertexWriterVertexWriter120     VertexWriter(void* ptr, Mark end) : BufferWriter(ptr, end) {}
121 
122     VertexWriter(const VertexWriter&) = delete;
VertexWriterVertexWriter123     VertexWriter(VertexWriter&& that) { *this = std::move(that); }
124 
125     VertexWriter& operator=(const VertexWriter&) = delete;
126     VertexWriter& operator=(VertexWriter&& that) {
127         BufferWriter::operator=(std::move(that));
128         return *this;
129     }
130 
makeOffsetVertexWriter131     VertexWriter makeOffset(size_t offsetInBytes) const {
132         return this->BufferWriter::makeOffset<VertexWriter>(offsetInBytes);
133     }
134 
135     template <typename T>
136     struct Conditional {
137         bool fCondition;
138         T fValue;
139     };
140 
141     template <typename T>
IfVertexWriter142     static Conditional<T> If(bool condition, const T& value) {
143         return {condition, value};
144     }
145 
146     template <typename T>
147     struct Skip {};
148 
149     template<typename T>
150     struct ArrayDesc {
151         const T* fArray;
152         int fCount;
153     };
154 
155     template <typename T>
ArrayVertexWriter156     static ArrayDesc<T> Array(const T* array, int count) {
157         return {array, count};
158     }
159 
160     template<int kCount, typename T>
161     struct RepeatDesc {
162         const T& fVal;
163     };
164 
165     template <int kCount, typename T>
RepeatVertexWriter166     static RepeatDesc<kCount, T> Repeat(const T& val) {
167         return {val};
168     }
169 
170     /**
171      * Specialized utilities for writing a four-vertices, with some data being replicated at each
172      * vertex, and other data being the appropriate 2-components from an SkRect to construct a
173      * triangle strip.
174      *
175      * - Four sets of data will be written
176      *
177      * - For any arguments where is_quad<Type>::value is true, a unique point will be written at
178      *   each vertex. To make a custom type be emitted as a quad, declare:
179      *
180      *       template<> struct VertexWriter::is_quad<MyQuadClass> : std::true_type {};
181      *
182      *   and define:
183      *
184      *       MyQuadClass::writeVertex(int cornerIdx, VertexWriter&) const { ... }
185      *
186      * - For any arguments where is_quad<Type>::value is false, its value will be replicated at each
187      *   vertex.
188      */
189     template <typename T>
190     struct is_quad : std::false_type {};
191 
192     template <typename T>
193     struct TriStrip {
writeVertexVertexWriter::TriStrip194         void writeVertex(int cornerIdx, VertexWriter& w) const {
195             switch (cornerIdx) {
196                 case 0: w << l << t; return;
197                 case 1: w << l << b; return;
198                 case 2: w << r << t; return;
199                 case 3: w << r << b; return;
200             }
201             SkUNREACHABLE;
202         }
203         T l, t, r, b;
204     };
205 
TriStripFromRectVertexWriter206     static TriStrip<float> TriStripFromRect(const SkRect& r) {
207         return { r.fLeft, r.fTop, r.fRight, r.fBottom };
208     }
209 
TriStripFromUVsVertexWriter210     static TriStrip<uint16_t> TriStripFromUVs(const std::array<uint16_t, 4>& rect) {
211         return { rect[0], rect[1], rect[2], rect[3] };
212     }
213 
214     template <typename T>
215     struct TriFan {
writeVertexVertexWriter::TriFan216         void writeVertex(int cornerIdx, VertexWriter& w) const {
217             switch (cornerIdx) {
218                 case 0: w << l << t; return;
219                 case 1: w << l << b; return;
220                 case 2: w << r << b; return;
221                 case 3: w << r << t; return;
222             }
223             SkUNREACHABLE;
224         }
225         T l, t, r, b;
226     };
227 
TriFanFromRectVertexWriter228     static TriFan<float> TriFanFromRect(const SkRect& r) {
229         return { r.fLeft, r.fTop, r.fRight, r.fBottom };
230     }
231 
232     template <typename... Args>
writeQuadVertexWriter233     void writeQuad(const Args&... remainder) {
234         this->writeQuadVertex<0>(remainder...);
235         this->writeQuadVertex<1>(remainder...);
236         this->writeQuadVertex<2>(remainder...);
237         this->writeQuadVertex<3>(remainder...);
238     }
239 
240 private:
241     template <int kCornerIdx, typename T, typename... Args>
writeQuadVertexVertexWriter242     std::enable_if_t<!is_quad<T>::value, void> writeQuadVertex(const T& val,
243                                                                const Args&... remainder) {
244         *this << val;  // Non-quads duplicate their value.
245         this->writeQuadVertex<kCornerIdx>(remainder...);
246     }
247 
248     template <int kCornerIdx, typename Q, typename... Args>
writeQuadVertexVertexWriter249     std::enable_if_t<is_quad<Q>::value, void> writeQuadVertex(const Q& quad,
250                                                               const Args&... remainder) {
251         quad.writeVertex(kCornerIdx, *this);  // Quads emit a different corner each time.
252         this->writeQuadVertex<kCornerIdx>(remainder...);
253     }
254 
255     template <int kCornerIdx>
writeQuadVertexVertexWriter256     void writeQuadVertex() {}
257 
258     template <typename T>
259     friend VertexWriter& operator<<(VertexWriter&, const T&);
260 
261     template <typename T>
262     friend VertexWriter& operator<<(VertexWriter&, const ArrayDesc<T>&);
263 };
264 
265 template <typename T>
266 inline VertexWriter& operator<<(VertexWriter& w, const T& val) {
267     static_assert(std::is_pod<T>::value, "");
268     w.validate(sizeof(T));
269     memcpy(w.fPtr, &val, sizeof(T));
270     w = w.makeOffset(sizeof(T));
271     return w;
272 }
273 
274 template <typename T>
275 inline VertexWriter& operator<<(VertexWriter& w, const VertexWriter::Conditional<T>& val) {
276     static_assert(std::is_pod<T>::value, "");
277     if (val.fCondition) {
278         w << val.fValue;
279     }
280     return w;
281 }
282 
283 template <typename T>
284 inline VertexWriter& operator<<(VertexWriter& w, const VertexWriter::Skip<T>& val) {
285     w = w.makeOffset(sizeof(T));
286     return w;
287 }
288 
289 template <typename T>
290 inline VertexWriter& operator<<(VertexWriter& w, const VertexWriter::ArrayDesc<T>& array) {
291     static_assert(std::is_pod<T>::value, "");
292     w.validate(array.fCount * sizeof(T));
293     memcpy(w.fPtr, array.fArray, array.fCount * sizeof(T));
294     w = w.makeOffset(sizeof(T) * array.fCount);
295     return w;
296 }
297 
298 template <int kCount, typename T>
299 inline VertexWriter& operator<<(VertexWriter& w, const VertexWriter::RepeatDesc<kCount,T>& repeat) {
300     for (int i = 0; i < kCount; ++i) {
301         w << repeat.fVal;
302     }
303     return w;
304 }
305 
306 template <>
307 [[maybe_unused]] inline VertexWriter& operator<<(VertexWriter& w, const skvx::float4& vector) {
308     w.validate(sizeof(vector));
309     vector.store(w.fPtr);
310     w = w.makeOffset(sizeof(vector));
311     return w;
312 }
313 
314 // Allow r-value/temporary writers to be appended to
315 template <typename T>
316 inline VertexWriter& operator<<(VertexWriter&& w, const T& val) { return w << val; }
317 
318 template <typename T>
319 struct VertexWriter::is_quad<VertexWriter::TriStrip<T>> : std::true_type {};
320 
321 template <typename T>
322 struct VertexWriter::is_quad<VertexWriter::TriFan<T>> : std::true_type {};
323 
324 /**
325  * VertexColor is a helper for writing colors to a vertex buffer. It outputs either four bytes or
326  * or four float32 channels, depending on the wideColor parameter. Note that the GP needs to have
327  * been constructed with the correct attribute type for colors, to match the usage here.
328  */
329 class VertexColor {
330 public:
331     VertexColor() = default;
332 
333     explicit VertexColor(const SkPMColor4f& color, bool wideColor) {
334         this->set(color, wideColor);
335     }
336 
337     void set(const SkPMColor4f& color, bool wideColor) {
338         if (wideColor) {
339             memcpy(fColor, color.vec(), sizeof(fColor));
340         } else {
341             fColor[0] = color.toBytes_RGBA();
342         }
343         fWideColor = wideColor;
344     }
345 
346     size_t size() const { return fWideColor ? 16 : 4; }
347 
348 private:
349     template <typename T>
350     friend VertexWriter& operator<<(VertexWriter&, const T&);
351 
352     uint32_t fColor[4];
353     bool     fWideColor;
354 };
355 
356 template <>
357 [[maybe_unused]] inline VertexWriter& operator<<(VertexWriter& w, const VertexColor& color) {
358     w << color.fColor[0];
359     if (color.fWideColor) {
360         w << color.fColor[1]
361           << color.fColor[2]
362           << color.fColor[3];
363     }
364     return w;
365 }
366 
367 ///////////////////////////////////////////////////////////////////////////////////////////////////
368 
369 struct IndexWriter : public BufferWriter {
370     IndexWriter() = default;
371 
372     IndexWriter(void* ptr, size_t size) : BufferWriter(ptr, size) {}
373     IndexWriter(void* ptr, Mark end) : BufferWriter(ptr, end) {}
374 
375     IndexWriter(const IndexWriter&) = delete;
376     IndexWriter(IndexWriter&& that) { *this = std::move(that); }
377 
378     IndexWriter& operator=(const IndexWriter&) = delete;
379     IndexWriter& operator=(IndexWriter&& that) {
380         BufferWriter::operator=(std::move(that));
381         return *this;
382     }
383 
384     IndexWriter makeOffset(int numIndices) const {
385         return this->BufferWriter::makeOffset<IndexWriter>(numIndices * sizeof(uint16_t));
386     }
387 
388     void writeArray(const uint16_t* array, int count) {
389         size_t arraySize = count * sizeof(uint16_t);
390         this->validate(arraySize);
391         memcpy(fPtr, array, arraySize);
392         fPtr = SkTAddOffset<void>(fPtr, arraySize);
393     }
394 
395     friend IndexWriter& operator<<(IndexWriter& w, uint16_t val);
396 };
397 
398 inline IndexWriter& operator<<(IndexWriter& w, uint16_t val) {
399     w.validate(sizeof(uint16_t));
400     memcpy(w.fPtr, &val, sizeof(uint16_t));
401     w = w.makeOffset(1);
402     return w;
403 }
404 
405 inline IndexWriter& operator<<(IndexWriter& w, int val) { return (w << SkTo<uint16_t>(val)); }
406 
407 template<typename T>
408 inline IndexWriter& operator<<(IndexWriter&& w, const T& val) { return w << val; }
409 
410 ///////////////////////////////////////////////////////////////////////////////////////////////////
411 
412 struct UniformWriter : public BufferWriter {
413     UniformWriter() = default;
414 
415     UniformWriter(void* ptr, size_t size) : BufferWriter(ptr, size) {}
416     UniformWriter(void* ptr, Mark end) : BufferWriter(ptr, end) {}
417 
418     UniformWriter(const UniformWriter&) = delete;
419     UniformWriter(UniformWriter&& that) { *this = std::move(that); }
420 
421     UniformWriter& operator=(const UniformWriter&) = delete;
422     UniformWriter& operator=(UniformWriter&& that) {
423         BufferWriter::operator=(std::move(that));
424         return *this;
425     }
426 
427     void write(const void* src, size_t bytes) {
428         this->validate(bytes);
429         memcpy(fPtr, src, bytes);
430         fPtr = SkTAddOffset<void>(fPtr, bytes);
431     }
432     void skipBytes(size_t bytes) {
433         this->validate(bytes);
434         fPtr = SkTAddOffset<void>(fPtr, bytes);
435     }
436 };
437 
438 ///////////////////////////////////////////////////////////////////////////////////////////////////
439 
440 struct UploadWriter : public BufferWriter {
441     UploadWriter() = default;
442 
443     UploadWriter(void* ptr, size_t size) : BufferWriter(ptr, size) {}
444 
445     UploadWriter(const UploadWriter&) = delete;
446     UploadWriter(UploadWriter&& that) { *this = std::move(that); }
447 
448     UploadWriter& operator=(const UploadWriter&) = delete;
449     UploadWriter& operator=(UploadWriter&& that) {
450         BufferWriter::operator=(std::move(that));
451         return *this;
452     }
453 
454     // Writes a block of image data to the upload buffer, starting at `offset`. The source image is
455     // `srcRowBytes` wide, and the written block is `dstRowBytes` wide and `rowCount` bytes tall.
456     void write(size_t offset, const void* src, size_t srcRowBytes, size_t dstRowBytes,
457                size_t trimRowBytes, int rowCount) {
458         this->validate(dstRowBytes * rowCount);
459         void* dst = SkTAddOffset<void>(fPtr, offset);
460         SkRectMemcpy(dst, dstRowBytes, src, srcRowBytes, trimRowBytes, rowCount);
461     }
462 
463     void convertAndWrite(size_t offset,
464                          const SkImageInfo& srcInfo, const void* src, size_t srcRowBytes,
465                          const SkImageInfo& dstInfo, size_t dstRowBytes) {
466         SkASSERT(srcInfo.width() == dstInfo.width() && srcInfo.height() == dstInfo.height());
467         this->validate(dstRowBytes * dstInfo.height());
468         void* dst = SkTAddOffset<void>(fPtr, offset);
469         SkAssertResult(SkConvertPixels(dstInfo, dst, dstRowBytes, srcInfo, src, srcRowBytes));
470     }
471 };
472 
473 }  // namespace skgpu
474 
475 #endif // skgpu_BufferWriter_DEFINED
476