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