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