• 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 "include/core/SkRect.h"
12 #include "include/private/SkColorData.h"
13 #include "include/private/SkNx.h"
14 #include "include/private/SkTemplates.h"
15 #include <type_traits>
16 
17 namespace skgpu {
18 
19 struct BufferWriter {
20 public:
21     // Marks a read-only position in the underlying buffer
22     struct Mark {
23     public:
MarkBufferWriter::Mark24         Mark() : Mark(nullptr) {}
25         Mark(void* ptr, size_t offset = 0)
26                 : fMark(reinterpret_cast<uintptr_t>(ptr) + offset) {
27             SkASSERT(ptr || offset == 0);
28         }
29 
30         bool operator< (const Mark& o) const { return fMark <  o.fMark; }
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 
37         ptrdiff_t operator-(const Mark& o) const { return fMark - o.fMark; }
38 
39         explicit operator bool() const { return *this != Mark(); }
40     private:
41         uintptr_t fMark;
42     };
43 
44     explicit operator bool() const { return fPtr != nullptr; }
45 
46     Mark mark(size_t offset=0) const {
47         this->validate(offset);
48         return Mark(fPtr, offset);
49     }
50 
51 protected:
52     BufferWriter() = default;
BufferWriterBufferWriter53     BufferWriter(void* ptr, size_t size) : fPtr(ptr) {
54         SkDEBUGCODE(fEnd = Mark(ptr, ptr ? size : 0);)
55     }
fPtrBufferWriter56     BufferWriter(void* ptr, Mark end = {}) : fPtr(ptr) {
57         SkDEBUGCODE(fEnd = end;)
58     }
59 
60     BufferWriter& operator=(const BufferWriter&) = delete;
61     BufferWriter& operator=(BufferWriter&& that) {
62         fPtr = that.fPtr;
63         that.fPtr = nullptr;
64         SkDEBUGCODE(fEnd = that.fEnd;)
65         SkDEBUGCODE(that.fEnd = Mark();)
66         return *this;
67     }
68 
69     // makeOffset effectively splits the current writer from {fPtr, fEnd} into {fPtr, p} and
70     // a new writer {p, fEnd}. The same data range is accessible, but each byte can only be
71     // set by a single writer. Automatically validates that there is enough bytes remaining in this
72     // writer to do such a split.
73     //
74     // This splitting and validation means that providers of BufferWriters to callers can easily
75     // and correctly track everything in a single BufferWriter field and use
76     //    return std::exchange(fCurrWriter, fCurrWriter.makeOffset(requestedBytes));
77     // This exposes the current writer position to the caller and sets the provider's new current
78     // position to be just after the requested bytes.
79     //
80     // Templated so that it can create subclasses directly.
81     template<typename W>
makeOffsetBufferWriter82     W makeOffset(size_t offsetInBytes) const {
83         this->validate(offsetInBytes);
84         void* p = SkTAddOffset<void>(fPtr, offsetInBytes);
85         Mark end{SkDEBUGCODE(fEnd)};
86         SkDEBUGCODE(fEnd = Mark(p);)
87         return W{p, end};
88     }
89 
validateBufferWriter90     void validate(size_t bytesToWrite) const {
91         // If the buffer writer had an end marked, make sure we're not crossing it.
92         // Ideally, all creators of BufferWriters mark the end, but a lot of legacy code is not set
93         // up to easily do this.
94         SkASSERT(fPtr || bytesToWrite == 0);
95         SkASSERT(!fEnd || Mark(fPtr, bytesToWrite) <= fEnd);
96     }
97 
98 protected:
99     void* fPtr = nullptr;
100     SkDEBUGCODE(mutable Mark fEnd = {};)
101 };
102 
103 /**
104  * Helper for writing vertex data to a buffer. Usage:
105  *  VertexWriter vertices{target->makeVertexSpace(...)};
106  *  vertices << A0 << B0 << C0 << ...;
107  *  vertices << A1 << B1 << C1 << ...;
108  *
109  * Each value must be POD (plain old data), or have a specialization of the "<<" operator.
110  */
111 struct VertexWriter : public BufferWriter {
112     inline constexpr static uint32_t kIEEE_32_infinity = 0x7f800000;
113 
114     VertexWriter() = default;
115     // DEPRECATED: Prefer specifying the size of the buffer being written to as well
VertexWriterVertexWriter116     explicit VertexWriter(void* ptr) : BufferWriter(ptr, Mark()) {}
117 
VertexWriterVertexWriter118     VertexWriter(void* ptr, size_t size) : BufferWriter(ptr, size) {}
VertexWriterVertexWriter119     VertexWriter(void* ptr, Mark end) : BufferWriter(ptr, end) {}
120 
121     VertexWriter(const VertexWriter&) = delete;
VertexWriterVertexWriter122     VertexWriter(VertexWriter&& that) { *this = std::move(that); }
123 
124     VertexWriter& operator=(const VertexWriter&) = delete;
125     VertexWriter& operator=(VertexWriter&& that) {
126         BufferWriter::operator=(std::move(that));
127         return *this;
128     }
129 
makeOffsetVertexWriter130     VertexWriter makeOffset(size_t offsetInBytes) const {
131         return this->BufferWriter::makeOffset<VertexWriter>(offsetInBytes);
132     }
133 
134     template <typename T>
135     struct Conditional {
136         bool fCondition;
137         T fValue;
138     };
139 
140     template <typename T>
IfVertexWriter141     static Conditional<T> If(bool condition, const T& value) {
142         return {condition, value};
143     }
144 
145     template <typename T>
146     struct Skip {};
147 
148     template<typename T>
149     struct ArrayDesc {
150         const T* fArray;
151         int fCount;
152     };
153 
154     template <typename T>
ArrayVertexWriter155     static ArrayDesc<T> Array(const T* array, int count) {
156         return {array, count};
157     }
158 
159     template<int kCount, typename T>
160     struct RepeatDesc {
161         const T& fVal;
162     };
163 
164     template <int kCount, typename T>
RepeatVertexWriter165     static RepeatDesc<kCount, T> Repeat(const T& val) {
166         return {val};
167     }
168 
169     /**
170      * Specialized utilities for writing a four-vertices, with some data being replicated at each
171      * vertex, and other data being the appropriate 2-components from an SkRect to construct a
172      * triangle strip.
173      *
174      * - Four sets of data will be written
175      *
176      * - For any arguments where is_quad<Type>::value is true, a unique point will be written at
177      *   each vertex. To make a custom type be emitted as a quad, declare:
178      *
179      *       template<> struct VertexWriter::is_quad<MyQuadClass> : std::true_type {};
180      *
181      *   and define:
182      *
183      *       MyQuadClass::writeVertex(int cornerIdx, VertexWriter&) const { ... }
184      *
185      * - For any arguments where is_quad<Type>::value is false, its value will be replicated at each
186      *   vertex.
187      */
188     template <typename T>
189     struct is_quad : std::false_type {};
190 
191     template <typename T>
192     struct TriStrip {
writeVertexVertexWriter::TriStrip193         void writeVertex(int cornerIdx, VertexWriter& w) const {
194             switch (cornerIdx) {
195                 case 0: w << l << t; return;
196                 case 1: w << l << b; return;
197                 case 2: w << r << t; return;
198                 case 3: w << r << b; return;
199             }
200             SkUNREACHABLE;
201         }
202         T l, t, r, b;
203     };
204 
TriStripFromRectVertexWriter205     static TriStrip<float> TriStripFromRect(const SkRect& r) {
206         return { r.fLeft, r.fTop, r.fRight, r.fBottom };
207     }
208 
TriStripFromUVsVertexWriter209     static TriStrip<uint16_t> TriStripFromUVs(const std::array<uint16_t, 4>& rect) {
210         return { rect[0], rect[1], rect[2], rect[3] };
211     }
212 
213     template <typename T>
214     struct TriFan {
writeVertexVertexWriter::TriFan215         void writeVertex(int cornerIdx, VertexWriter& w) const {
216             switch (cornerIdx) {
217                 case 0: w << l << t; return;
218                 case 1: w << l << b; return;
219                 case 2: w << r << b; return;
220                 case 3: w << r << t; return;
221             }
222             SkUNREACHABLE;
223         }
224         T l, t, r, b;
225     };
226 
TriFanFromRectVertexWriter227     static TriFan<float> TriFanFromRect(const SkRect& r) {
228         return { r.fLeft, r.fTop, r.fRight, r.fBottom };
229     }
230 
231     template <typename... Args>
writeQuadVertexWriter232     void writeQuad(const Args&... remainder) {
233         this->writeQuadVertex<0>(remainder...);
234         this->writeQuadVertex<1>(remainder...);
235         this->writeQuadVertex<2>(remainder...);
236         this->writeQuadVertex<3>(remainder...);
237     }
238 
239 private:
240     template <int kCornerIdx, typename T, typename... Args>
writeQuadVertexVertexWriter241     std::enable_if_t<!is_quad<T>::value, void> writeQuadVertex(const T& val,
242                                                                const Args&... remainder) {
243         *this << val;  // Non-quads duplicate their value.
244         this->writeQuadVertex<kCornerIdx>(remainder...);
245     }
246 
247     template <int kCornerIdx, typename Q, typename... Args>
writeQuadVertexVertexWriter248     std::enable_if_t<is_quad<Q>::value, void> writeQuadVertex(const Q& quad,
249                                                               const Args&... remainder) {
250         quad.writeVertex(kCornerIdx, *this);  // Quads emit a different corner each time.
251         this->writeQuadVertex<kCornerIdx>(remainder...);
252     }
253 
254     template <int kCornerIdx>
writeQuadVertexVertexWriter255     void writeQuadVertex() {}
256 
257     template <typename T>
258     friend VertexWriter& operator<<(VertexWriter&, const T&);
259 
260     template <typename T>
261     friend VertexWriter& operator<<(VertexWriter&, const ArrayDesc<T>&);
262 };
263 
264 template <typename T>
265 inline VertexWriter& operator<<(VertexWriter& w, const T& val) {
266     static_assert(std::is_pod<T>::value, "");
267     w.validate(sizeof(T));
268     memcpy(w.fPtr, &val, sizeof(T));
269     w = w.makeOffset(sizeof(T));
270     return w;
271 }
272 
273 template <typename T>
274 inline VertexWriter& operator<<(VertexWriter& w, const VertexWriter::Conditional<T>& val) {
275     static_assert(std::is_pod<T>::value, "");
276     if (val.fCondition) {
277         w << val.fValue;
278     }
279     return w;
280 }
281 
282 template <typename T>
283 inline VertexWriter& operator<<(VertexWriter& w, const VertexWriter::Skip<T>& val) {
284     w = w.makeOffset(sizeof(T));
285     return w;
286 }
287 
288 template <typename T>
289 inline VertexWriter& operator<<(VertexWriter& w, const VertexWriter::ArrayDesc<T>& array) {
290     static_assert(std::is_pod<T>::value, "");
291     w.validate(array.fCount * sizeof(T));
292     memcpy(w.fPtr, array.fArray, array.fCount * sizeof(T));
293     w = w.makeOffset(sizeof(T) * array.fCount);
294     return w;
295 }
296 
297 template <int kCount, typename T>
298 inline VertexWriter& operator<<(VertexWriter& w, const VertexWriter::RepeatDesc<kCount,T>& repeat) {
299     for (int i = 0; i < kCount; ++i) {
300         w << repeat.fVal;
301     }
302     return w;
303 }
304 
305 template <>
306 SK_MAYBE_UNUSED inline VertexWriter& operator<<(VertexWriter& w, const Sk4f& vector) {
307     w.validate(sizeof(vector));
308     vector.store(w.fPtr);
309     w = w.makeOffset(sizeof(vector));
310     return w;
311 }
312 
313 // Allow r-value/temporary writers to be appended to
314 template <typename T>
315 inline VertexWriter& operator<<(VertexWriter&& w, const T& val) { return w << val; }
316 
317 template <typename T>
318 struct VertexWriter::is_quad<VertexWriter::TriStrip<T>> : std::true_type {};
319 
320 template <typename T>
321 struct VertexWriter::is_quad<VertexWriter::TriFan<T>> : std::true_type {};
322 
323 /**
324  * VertexColor is a helper for writing colors to a vertex buffer. It outputs either four bytes or
325  * or four float32 channels, depending on the wideColor parameter. Note that the GP needs to have
326  * been constructed with the correct attribute type for colors, to match the usage here.
327  */
328 class VertexColor {
329 public:
330     VertexColor() = default;
331 
332     explicit VertexColor(const SkPMColor4f& color, bool wideColor) {
333         this->set(color, wideColor);
334     }
335 
336     void set(const SkPMColor4f& color, bool wideColor) {
337         if (wideColor) {
338             memcpy(fColor, color.vec(), sizeof(fColor));
339         } else {
340             fColor[0] = color.toBytes_RGBA();
341         }
342         fWideColor = wideColor;
343     }
344 
345     size_t size() const { return fWideColor ? 16 : 4; }
346 
347 private:
348     template <typename T>
349     friend VertexWriter& operator<<(VertexWriter&, const T&);
350 
351     uint32_t fColor[4];
352     bool     fWideColor;
353 };
354 
355 template <>
356 SK_MAYBE_UNUSED inline VertexWriter& operator<<(VertexWriter& w, const VertexColor& color) {
357     w << color.fColor[0];
358     if (color.fWideColor) {
359         w << color.fColor[1]
360           << color.fColor[2]
361           << color.fColor[3];
362     }
363     return w;
364 }
365 
366 ///////////////////////////////////////////////////////////////////////////////////////////////////
367 
368 struct IndexWriter : public BufferWriter {
369     IndexWriter() = default;
370 
371     IndexWriter(void* ptr, size_t size) : BufferWriter(ptr, size) {}
372     IndexWriter(void* ptr, Mark end) : BufferWriter(ptr, end) {}
373 
374     IndexWriter(const IndexWriter&) = delete;
375     IndexWriter(IndexWriter&& that) { *this = std::move(that); }
376 
377     IndexWriter& operator=(const IndexWriter&) = delete;
378     IndexWriter& operator=(IndexWriter&& that) {
379         BufferWriter::operator=(std::move(that));
380         return *this;
381     }
382 
383     IndexWriter makeOffset(int numIndices) const {
384         return this->BufferWriter::makeOffset<IndexWriter>(numIndices * sizeof(uint16_t));
385     }
386 
387     void writeArray(const uint16_t* array, int count) {
388         size_t arraySize = count * sizeof(uint16_t);
389         this->validate(arraySize);
390         memcpy(fPtr, array, arraySize);
391         fPtr = SkTAddOffset<void>(fPtr, arraySize);
392     }
393 
394     friend IndexWriter& operator<<(IndexWriter& w, uint16_t val);
395 };
396 
397 inline IndexWriter& operator<<(IndexWriter& w, uint16_t val) {
398     w.validate(sizeof(uint16_t));
399     memcpy(w.fPtr, &val, sizeof(uint16_t));
400     w = w.makeOffset(1);
401     return w;
402 }
403 
404 inline IndexWriter& operator<<(IndexWriter& w, int val) { return (w << SkTo<uint16_t>(val)); }
405 
406 template<typename T>
407 inline IndexWriter& operator<<(IndexWriter&& w, const T& val) { return w << val; }
408 
409 ///////////////////////////////////////////////////////////////////////////////////////////////////
410 
411 struct UniformWriter : public BufferWriter {
412     UniformWriter() = default;
413 
414     UniformWriter(void* ptr, size_t size) : BufferWriter(ptr, size) {}
415     UniformWriter(void* ptr, Mark end) : BufferWriter(ptr, end) {}
416 
417     UniformWriter(const UniformWriter&) = delete;
418     UniformWriter(UniformWriter&& that) { *this = std::move(that); }
419 
420     UniformWriter& operator=(const UniformWriter&) = delete;
421     UniformWriter& operator=(UniformWriter&& that) {
422         BufferWriter::operator=(std::move(that));
423         return *this;
424     }
425 
426     void write(const void* src, size_t bytes) {
427         this->validate(bytes);
428         memcpy(fPtr, src, bytes);
429         fPtr = SkTAddOffset<void>(fPtr, bytes);
430     }
431 };
432 
433 }  // namespace skgpu
434 
435 #endif // skgpu_BufferWriter_DEFINED
436