• 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 GrVertexWriter_DEFINED
9 #define GrVertexWriter_DEFINED
10 
11 #include "include/private/SkTemplates.h"
12 #include "src/gpu/GrColor.h"
13 #include "src/gpu/geometry/GrQuad.h"
14 #include <type_traits>
15 
16 /**
17  * Helper for writing vertex data to a buffer. Usage:
18  *  GrVertexWriter vertices{target->makeVertexSpace(...)};
19  *  vertices.write(A0, B0, C0, ...);
20  *  vertices.write(A1, B1, C1, ...);
21  *
22  * Supports any number of arguments. Each argument must be POD (plain old data), or an array
23  * thereof.
24  */
25 struct GrVertexWriter {
26     void* fPtr;
27 
28     GrVertexWriter() = default;
GrVertexWriterGrVertexWriter29     GrVertexWriter(void* ptr) : fPtr(ptr) {}
30     GrVertexWriter(const GrVertexWriter&) = delete;
GrVertexWriterGrVertexWriter31     GrVertexWriter(GrVertexWriter&& that) { *this = std::move(that); }
32 
33     GrVertexWriter& operator=(const GrVertexWriter&) = delete;
34     GrVertexWriter& operator=(GrVertexWriter&& that) {
35         fPtr = that.fPtr;
36         that.fPtr = nullptr;
37         return *this;
38     }
39 
40     bool operator==(const GrVertexWriter& that) const { return fPtr == that.fPtr; }
41     operator bool() const { return fPtr != nullptr; }
42 
makeOffsetGrVertexWriter43     GrVertexWriter makeOffset(size_t offsetInBytes) const {
44         return {SkTAddOffset<void>(fPtr, offsetInBytes)};
45     }
46 
47     template <typename T>
48     class Conditional {
49     public:
ConditionalGrVertexWriter50         explicit Conditional(bool condition, const T& value)
51             : fCondition(condition), fValue(value) {}
52     private:
53         friend struct GrVertexWriter;
54 
55         bool fCondition;
56         T fValue;
57     };
58 
59     template <typename T>
IfGrVertexWriter60     static Conditional<T> If(bool condition, const T& value) {
61         return Conditional<T>(condition, value);
62     }
63 
64     template <typename T>
65     struct Skip {};
66 
67     template <typename T, typename... Args>
writeGrVertexWriter68     void write(const T& val, const Args&... remainder) {
69         static_assert(std::is_pod<T>::value, "");
70         // This assert is barely related to what we're trying to check - that our vertex data
71         // matches our attribute layouts, where each attribute is aligned to four bytes. If this
72         // becomes a problem, just remove it.
73         static_assert(alignof(T) <= 4, "");
74         memcpy(fPtr, &val, sizeof(T));
75         fPtr = SkTAddOffset<void>(fPtr, sizeof(T));
76         this->write(remainder...);
77     }
78 
79     template <typename T, size_t N, typename... Args>
writeGrVertexWriter80     void write(const T(&val)[N], const Args&... remainder) {
81         static_assert(std::is_pod<T>::value, "");
82         static_assert(alignof(T) <= 4, "");
83         memcpy(fPtr, val, N * sizeof(T));
84         fPtr = SkTAddOffset<void>(fPtr, N * sizeof(T));
85         this->write(remainder...);
86     }
87 
88     template <typename... Args>
writeGrVertexWriter89     void write(const GrVertexColor& color, const Args&... remainder) {
90         this->write(color.fColor[0]);
91         if (color.fWideColor) {
92             this->write(color.fColor[1]);
93             this->write(color.fColor[2]);
94             this->write(color.fColor[3]);
95         }
96         this->write(remainder...);
97     }
98 
99     template <typename T, typename... Args>
writeGrVertexWriter100     void write(const Conditional<T>& val, const Args&... remainder) {
101         if (val.fCondition) {
102             this->write(val.fValue);
103         }
104         this->write(remainder...);
105     }
106 
107     template <typename T, typename... Args>
writeGrVertexWriter108     void write(const Skip<T>& val, const Args&... remainder) {
109         fPtr = SkTAddOffset<void>(fPtr, sizeof(T));
110         this->write(remainder...);
111     }
112 
113     template <typename... Args>
writeGrVertexWriter114     void write(const Sk4f& vector, const Args&... remainder) {
115         float buffer[4];
116         vector.store(buffer);
117         this->write<float, 4>(buffer);
118         this->write(remainder...);
119     }
120 
121     template <typename T>
writeArrayGrVertexWriter122     void writeArray(const T* array, int count) {
123         static_assert(std::is_pod<T>::value, "");
124         static_assert(alignof(T) <= 4, "");
125         memcpy(fPtr, array, count * sizeof(T));
126         fPtr = SkTAddOffset<void>(fPtr, count * sizeof(T));
127     }
128 
129     template <typename T>
fillGrVertexWriter130     void fill(const T& val, int repeatCount) {
131         for (int i = 0; i < repeatCount; ++i) {
132             this->write(val);
133         }
134     }
135 
writeRawGrVertexWriter136     void writeRaw(const void* data, size_t size) {
137         memcpy(fPtr, data, size);
138         fPtr = SkTAddOffset<void>(fPtr, size);
139     }
140 
writeGrVertexWriter141     void write() {}
142 
143     /**
144      * Specialized utility for writing a four-vertices, with some data being replicated at each
145      * vertex, and other data being the appropriate 2-components from an SkRect to construct a
146      * triangle strip.
147      *
148      * writeQuad(A, B, C, ...) is similar to write(A, B, C, ...), except that:
149      *
150      * - Four sets of data will be written
151      * - For any arguments of type TriStrip, a unique SkPoint will be written at each vertex,
152      *   in this order: left-top, left-bottom, right-top, right-bottom.
153      */
154     template <typename T>
155     struct TriStrip { T l, t, r, b; };
156 
TriStripFromRectGrVertexWriter157     static TriStrip<float> TriStripFromRect(const SkRect& r) {
158         return { r.fLeft, r.fTop, r.fRight, r.fBottom };
159     }
160 
TriStripFromUVsGrVertexWriter161     static TriStrip<uint16_t> TriStripFromUVs(const std::array<uint16_t, 4>& rect) {
162         return { rect[0], rect[1], rect[2], rect[3] };
163     }
164 
165     template <typename T>
166     struct TriFan { T l, t, r, b; };
167 
TriFanFromRectGrVertexWriter168     static TriFan<float> TriFanFromRect(const SkRect& r) {
169         return { r.fLeft, r.fTop, r.fRight, r.fBottom };
170     }
171 
172     template <typename... Args>
writeQuadGrVertexWriter173     void writeQuad(const Args&... remainder) {
174         this->writeQuadVert<0>(remainder...);
175         this->writeQuadVert<1>(remainder...);
176         this->writeQuadVert<2>(remainder...);
177         this->writeQuadVert<3>(remainder...);
178     }
179 
180 private:
181     template <int corner, typename T, typename... Args>
writeQuadVertGrVertexWriter182     void writeQuadVert(const T& val, const Args&... remainder) {
183         this->writeQuadValue<corner>(val);
184         this->writeQuadVert<corner>(remainder...);
185     }
186 
187     template <int corner>
writeQuadVertGrVertexWriter188     void writeQuadVert() {}
189 
190     template <int corner, typename T>
writeQuadValueGrVertexWriter191     void writeQuadValue(const T& val) {
192         this->write(val);
193     }
194 
195     template <int corner, typename T>
writeQuadValueGrVertexWriter196     void writeQuadValue(const TriStrip<T>& r) {
197         switch (corner) {
198             case 0: this->write(r.l, r.t); break;
199             case 1: this->write(r.l, r.b); break;
200             case 2: this->write(r.r, r.t); break;
201             case 3: this->write(r.r, r.b); break;
202         }
203     }
204 
205     template <int corner, typename T>
writeQuadValueGrVertexWriter206     void writeQuadValue(const TriFan<T>& r) {
207         switch (corner) {
208         case 0: this->write(r.l, r.t); break;
209         case 1: this->write(r.l, r.b); break;
210         case 2: this->write(r.r, r.b); break;
211         case 3: this->write(r.r, r.t); break;
212         }
213     }
214 
215     template <int corner>
writeQuadValueGrVertexWriter216     void writeQuadValue(const GrQuad& q) {
217         this->write(q.point(corner));
218     }
219 };
220 
221 #endif
222