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