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/SkImageInfo.h" 12 #include "include/core/SkRect.h" 13 #include "include/private/SkColorData.h" 14 #include "include/private/base/SkAssert.h" 15 #include "include/private/base/SkDebug.h" 16 #include "include/private/base/SkTemplates.h" 17 #include "include/private/base/SkTo.h" 18 #include "src/base/SkRectMemcpy.h" 19 #include "src/base/SkVx.h" 20 #include "src/core/SkConvertPixels.h" 21 22 #include <array> 23 #include <cstddef> 24 #include <cstdint> 25 #include <cstring> 26 #include <type_traits> 27 #include <utility> 28 29 namespace skgpu { 30 31 struct BufferWriter { 32 public: 33 // Marks a read-only position in the underlying buffer 34 struct Mark { 35 public: MarkBufferWriter::Mark36 Mark() : Mark(nullptr) {} 37 Mark(void* ptr, size_t offset = 0) 38 : fMark(reinterpret_cast<uintptr_t>(ptr) + offset) { 39 SkASSERT(ptr || offset == 0); 40 } 41 42 bool operator< (const Mark& o) const { return fMark < o.fMark; } 43 bool operator<=(const Mark& o) const { return fMark <= o.fMark; } 44 bool operator==(const Mark& o) const { return fMark == o.fMark; } 45 bool operator!=(const Mark& o) const { return fMark != o.fMark; } 46 bool operator>=(const Mark& o) const { return fMark >= o.fMark; } 47 bool operator> (const Mark& o) const { return fMark > o.fMark; } 48 49 ptrdiff_t operator-(const Mark& o) const { return fMark - o.fMark; } 50 51 explicit operator bool() const { return *this != Mark(); } 52 private: 53 uintptr_t fMark; 54 }; 55 56 explicit operator bool() const { return fPtr != nullptr; } 57 58 Mark mark(size_t offset=0) const { 59 this->validate(offset); 60 return Mark(fPtr, offset); 61 } 62 63 protected: 64 BufferWriter() = default; BufferWriterBufferWriter65 BufferWriter(void* ptr, size_t size) : fPtr(ptr) { 66 SkDEBUGCODE(fEnd = Mark(ptr, ptr ? size : 0);) 67 } fPtrBufferWriter68 BufferWriter(void* ptr, Mark end = {}) : fPtr(ptr) { 69 SkDEBUGCODE(fEnd = end;) 70 } 71 72 BufferWriter& operator=(const BufferWriter&) = delete; 73 BufferWriter& operator=(BufferWriter&& that) { 74 fPtr = that.fPtr; 75 that.fPtr = nullptr; 76 SkDEBUGCODE(fEnd = that.fEnd;) 77 SkDEBUGCODE(that.fEnd = Mark();) 78 return *this; 79 } 80 81 // makeOffset effectively splits the current writer from {fPtr, fEnd} into {fPtr, p} and 82 // a new writer {p, fEnd}. The same data range is accessible, but each byte can only be 83 // set by a single writer. Automatically validates that there is enough bytes remaining in this 84 // writer to do such a split. 85 // 86 // This splitting and validation means that providers of BufferWriters to callers can easily 87 // and correctly track everything in a single BufferWriter field and use 88 // return std::exchange(fCurrWriter, fCurrWriter.makeOffset(requestedBytes)); 89 // This exposes the current writer position to the caller and sets the provider's new current 90 // position to be just after the requested bytes. 91 // 92 // Templated so that it can create subclasses directly. 93 template<typename W> makeOffsetBufferWriter94 W makeOffset(size_t offsetInBytes) const { 95 this->validate(offsetInBytes); 96 void* p = SkTAddOffset<void>(fPtr, offsetInBytes); 97 Mark end{SkDEBUGCODE(fEnd)}; 98 SkDEBUGCODE(fEnd = Mark(p);) 99 return W{p, end}; 100 } 101 validateBufferWriter102 void validate(size_t bytesToWrite) const { 103 // If the buffer writer had an end marked, make sure we're not crossing it. 104 // Ideally, all creators of BufferWriters mark the end, but a lot of legacy code is not set 105 // up to easily do this. 106 SkASSERT(fPtr || bytesToWrite == 0); 107 SkASSERT(!fEnd || Mark(fPtr, bytesToWrite) <= fEnd); 108 } 109 110 protected: 111 void* fPtr = nullptr; 112 SkDEBUGCODE(mutable Mark fEnd = {};) 113 }; 114 115 /** 116 * Helper for writing vertex data to a buffer. Usage: 117 * VertexWriter vertices{target->makeVertexSpace(...)}; 118 * vertices << A0 << B0 << C0 << ...; 119 * vertices << A1 << B1 << C1 << ...; 120 * 121 * Each value must be POD (plain old data), or have a specialization of the "<<" operator. 122 */ 123 struct VertexWriter : public BufferWriter { 124 inline constexpr static uint32_t kIEEE_32_infinity = 0x7f800000; 125 126 VertexWriter() = default; 127 // DEPRECATED: Prefer specifying the size of the buffer being written to as well VertexWriterVertexWriter128 explicit VertexWriter(void* ptr) : BufferWriter(ptr, Mark()) {} 129 VertexWriterVertexWriter130 VertexWriter(void* ptr, size_t size) : BufferWriter(ptr, size) {} VertexWriterVertexWriter131 VertexWriter(void* ptr, Mark end) : BufferWriter(ptr, end) {} 132 133 VertexWriter(const VertexWriter&) = delete; VertexWriterVertexWriter134 VertexWriter(VertexWriter&& that) { *this = std::move(that); } 135 136 VertexWriter& operator=(const VertexWriter&) = delete; 137 VertexWriter& operator=(VertexWriter&& that) { 138 BufferWriter::operator=(std::move(that)); 139 return *this; 140 } 141 makeOffsetVertexWriter142 VertexWriter makeOffset(size_t offsetInBytes) const { 143 return this->BufferWriter::makeOffset<VertexWriter>(offsetInBytes); 144 } 145 146 template <typename T> 147 struct Conditional { 148 bool fCondition; 149 T fValue; 150 }; 151 152 template <typename T> IfVertexWriter153 static Conditional<T> If(bool condition, const T& value) { 154 return {condition, value}; 155 } 156 157 template <typename T> 158 struct Skip {}; 159 160 template<typename T> 161 struct ArrayDesc { 162 const T* fArray; 163 int fCount; 164 }; 165 166 template <typename T> ArrayVertexWriter167 static ArrayDesc<T> Array(const T* array, int count) { 168 return {array, count}; 169 } 170 171 template<int kCount, typename T> 172 struct RepeatDesc { 173 const T& fVal; 174 }; 175 176 template <int kCount, typename T> RepeatVertexWriter177 static RepeatDesc<kCount, T> Repeat(const T& val) { 178 return {val}; 179 } 180 181 /** 182 * Specialized utilities for writing a four-vertices, with some data being replicated at each 183 * vertex, and other data being the appropriate 2-components from an SkRect to construct a 184 * triangle strip. 185 * 186 * - Four sets of data will be written 187 * 188 * - For any arguments where is_quad<Type>::value is true, a unique point will be written at 189 * each vertex. To make a custom type be emitted as a quad, declare: 190 * 191 * template<> struct VertexWriter::is_quad<MyQuadClass> : std::true_type {}; 192 * 193 * and define: 194 * 195 * MyQuadClass::writeVertex(int cornerIdx, VertexWriter&) const { ... } 196 * 197 * - For any arguments where is_quad<Type>::value is false, its value will be replicated at each 198 * vertex. 199 */ 200 template <typename T> 201 struct is_quad : std::false_type {}; 202 203 template <typename T> 204 struct TriStrip { writeVertexVertexWriter::TriStrip205 void writeVertex(int cornerIdx, VertexWriter& w) const { 206 switch (cornerIdx) { 207 case 0: w << l << t; return; 208 case 1: w << l << b; return; 209 case 2: w << r << t; return; 210 case 3: w << r << b; return; 211 } 212 SkUNREACHABLE; 213 } 214 T l, t, r, b; 215 }; 216 TriStripFromRectVertexWriter217 static TriStrip<float> TriStripFromRect(const SkRect& r) { 218 return { r.fLeft, r.fTop, r.fRight, r.fBottom }; 219 } 220 TriStripFromUVsVertexWriter221 static TriStrip<uint16_t> TriStripFromUVs(const std::array<uint16_t, 4>& rect) { 222 return { rect[0], rect[1], rect[2], rect[3] }; 223 } 224 225 template <typename T> 226 struct TriFan { writeVertexVertexWriter::TriFan227 void writeVertex(int cornerIdx, VertexWriter& w) const { 228 switch (cornerIdx) { 229 case 0: w << l << t; return; 230 case 1: w << l << b; return; 231 case 2: w << r << b; return; 232 case 3: w << r << t; return; 233 } 234 SkUNREACHABLE; 235 } 236 T l, t, r, b; 237 }; 238 TriFanFromRectVertexWriter239 static TriFan<float> TriFanFromRect(const SkRect& r) { 240 return { r.fLeft, r.fTop, r.fRight, r.fBottom }; 241 } 242 243 template <typename... Args> writeQuadVertexWriter244 void writeQuad(const Args&... remainder) { 245 this->writeQuadVertex<0>(remainder...); 246 this->writeQuadVertex<1>(remainder...); 247 this->writeQuadVertex<2>(remainder...); 248 this->writeQuadVertex<3>(remainder...); 249 } 250 251 private: 252 template <int kCornerIdx, typename T, typename... Args> writeQuadVertexVertexWriter253 std::enable_if_t<!is_quad<T>::value, void> writeQuadVertex(const T& val, 254 const Args&... remainder) { 255 *this << val; // Non-quads duplicate their value. 256 this->writeQuadVertex<kCornerIdx>(remainder...); 257 } 258 259 template <int kCornerIdx, typename Q, typename... Args> writeQuadVertexVertexWriter260 std::enable_if_t<is_quad<Q>::value, void> writeQuadVertex(const Q& quad, 261 const Args&... remainder) { 262 quad.writeVertex(kCornerIdx, *this); // Quads emit a different corner each time. 263 this->writeQuadVertex<kCornerIdx>(remainder...); 264 } 265 266 template <int kCornerIdx> writeQuadVertexVertexWriter267 void writeQuadVertex() {} 268 269 template <typename T> 270 friend VertexWriter& operator<<(VertexWriter&, const T&); 271 272 template <typename T> 273 friend VertexWriter& operator<<(VertexWriter&, const ArrayDesc<T>&); 274 }; 275 276 template <typename T> 277 inline VertexWriter& operator<<(VertexWriter& w, const T& val) { 278 static_assert(std::is_trivially_copyable<T>::value, ""); 279 w.validate(sizeof(T)); 280 memcpy(w.fPtr, &val, sizeof(T)); 281 w = w.makeOffset(sizeof(T)); 282 return w; 283 } 284 285 template <typename T> 286 inline VertexWriter& operator<<(VertexWriter& w, const VertexWriter::Conditional<T>& val) { 287 static_assert(std::is_trivially_copyable<T>::value, ""); 288 if (val.fCondition) { 289 w << val.fValue; 290 } 291 return w; 292 } 293 294 template <typename T> 295 inline VertexWriter& operator<<(VertexWriter& w, const VertexWriter::Skip<T>& val) { 296 w = w.makeOffset(sizeof(T)); 297 return w; 298 } 299 300 template <typename T> 301 inline VertexWriter& operator<<(VertexWriter& w, const VertexWriter::ArrayDesc<T>& array) { 302 static_assert(std::is_trivially_copyable<T>::value, ""); 303 w.validate(array.fCount * sizeof(T)); 304 memcpy(w.fPtr, array.fArray, array.fCount * sizeof(T)); 305 w = w.makeOffset(sizeof(T) * array.fCount); 306 return w; 307 } 308 309 template <int kCount, typename T> 310 inline VertexWriter& operator<<(VertexWriter& w, const VertexWriter::RepeatDesc<kCount,T>& repeat) { 311 for (int i = 0; i < kCount; ++i) { 312 w << repeat.fVal; 313 } 314 return w; 315 } 316 317 template <> 318 [[maybe_unused]] inline VertexWriter& operator<<(VertexWriter& w, const skvx::float4& vector) { 319 w.validate(sizeof(vector)); 320 vector.store(w.fPtr); 321 w = w.makeOffset(sizeof(vector)); 322 return w; 323 } 324 325 // Allow r-value/temporary writers to be appended to 326 template <typename T> 327 inline VertexWriter& operator<<(VertexWriter&& w, const T& val) { return w << val; } 328 329 template <typename T> 330 struct VertexWriter::is_quad<VertexWriter::TriStrip<T>> : std::true_type {}; 331 332 template <typename T> 333 struct VertexWriter::is_quad<VertexWriter::TriFan<T>> : std::true_type {}; 334 335 /** 336 * VertexColor is a helper for writing colors to a vertex buffer. It outputs either four bytes or 337 * or four float32 channels, depending on the wideColor parameter. Note that the GP needs to have 338 * been constructed with the correct attribute type for colors, to match the usage here. 339 */ 340 class VertexColor { 341 public: 342 VertexColor() = default; 343 344 explicit VertexColor(const SkPMColor4f& color, bool wideColor) { 345 this->set(color, wideColor); 346 } 347 348 void set(const SkPMColor4f& color, bool wideColor) { 349 if (wideColor) { 350 memcpy(fColor, color.vec(), sizeof(fColor)); 351 } else { 352 fColor[0] = color.toBytes_RGBA(); 353 } 354 fWideColor = wideColor; 355 } 356 357 size_t size() const { return fWideColor ? 16 : 4; } 358 359 private: 360 template <typename T> 361 friend VertexWriter& operator<<(VertexWriter&, const T&); 362 363 uint32_t fColor[4]; 364 bool fWideColor; 365 }; 366 367 template <> 368 [[maybe_unused]] inline VertexWriter& operator<<(VertexWriter& w, const VertexColor& color) { 369 w << color.fColor[0]; 370 if (color.fWideColor) { 371 w << color.fColor[1] 372 << color.fColor[2] 373 << color.fColor[3]; 374 } 375 return w; 376 } 377 378 /////////////////////////////////////////////////////////////////////////////////////////////////// 379 380 struct IndexWriter : public BufferWriter { 381 IndexWriter() = default; 382 383 IndexWriter(void* ptr, size_t size) : BufferWriter(ptr, size) {} 384 IndexWriter(void* ptr, Mark end) : BufferWriter(ptr, end) {} 385 386 IndexWriter(const IndexWriter&) = delete; 387 IndexWriter(IndexWriter&& that) { *this = std::move(that); } 388 389 IndexWriter& operator=(const IndexWriter&) = delete; 390 IndexWriter& operator=(IndexWriter&& that) { 391 BufferWriter::operator=(std::move(that)); 392 return *this; 393 } 394 395 IndexWriter makeOffset(int numIndices) const { 396 return this->BufferWriter::makeOffset<IndexWriter>(numIndices * sizeof(uint16_t)); 397 } 398 399 void writeArray(const uint16_t* array, int count) { 400 size_t arraySize = count * sizeof(uint16_t); 401 this->validate(arraySize); 402 memcpy(fPtr, array, arraySize); 403 fPtr = SkTAddOffset<void>(fPtr, arraySize); 404 405 } 406 407 friend IndexWriter& operator<<(IndexWriter& w, uint16_t val); 408 }; 409 410 inline IndexWriter& operator<<(IndexWriter& w, uint16_t val) { 411 w.validate(sizeof(uint16_t)); 412 memcpy(w.fPtr, &val, sizeof(uint16_t)); 413 w = w.makeOffset(1); 414 return w; 415 } 416 417 inline IndexWriter& operator<<(IndexWriter& w, int val) { return (w << SkTo<uint16_t>(val)); } 418 419 template<typename T> 420 inline IndexWriter& operator<<(IndexWriter&& w, const T& val) { return w << val; } 421 422 /////////////////////////////////////////////////////////////////////////////////////////////////// 423 424 struct UniformWriter : public BufferWriter { 425 UniformWriter() = default; 426 427 UniformWriter(void* ptr, size_t size) : BufferWriter(ptr, size) {} 428 UniformWriter(void* ptr, Mark end) : BufferWriter(ptr, end) {} 429 430 UniformWriter(const UniformWriter&) = delete; 431 UniformWriter(UniformWriter&& that) { *this = std::move(that); } 432 433 UniformWriter& operator=(const UniformWriter&) = delete; 434 UniformWriter& operator=(UniformWriter&& that) { 435 BufferWriter::operator=(std::move(that)); 436 return *this; 437 } 438 439 void write(const void* src, size_t bytes) { 440 this->validate(bytes); 441 memcpy(fPtr, src, bytes); 442 fPtr = SkTAddOffset<void>(fPtr, bytes); 443 } 444 void skipBytes(size_t bytes) { 445 this->validate(bytes); 446 fPtr = SkTAddOffset<void>(fPtr, bytes); 447 } 448 }; 449 450 /////////////////////////////////////////////////////////////////////////////////////////////////// 451 452 struct TextureUploadWriter : public BufferWriter { 453 TextureUploadWriter() = default; 454 455 TextureUploadWriter(void* ptr, size_t size) : BufferWriter(ptr, size) {} 456 457 TextureUploadWriter(const TextureUploadWriter&) = delete; 458 TextureUploadWriter(TextureUploadWriter&& that) { *this = std::move(that); } 459 460 TextureUploadWriter& operator=(const TextureUploadWriter&) = delete; 461 TextureUploadWriter& operator=(TextureUploadWriter&& that) { 462 BufferWriter::operator=(std::move(that)); 463 return *this; 464 } 465 466 // Writes a block of image data to the upload buffer, starting at `offset`. The source image is 467 // `srcRowBytes` wide, and the written block is `dstRowBytes` wide and `rowCount` bytes tall. 468 void write(size_t offset, const void* src, size_t srcRowBytes, size_t dstRowBytes, 469 size_t trimRowBytes, int rowCount) { 470 this->validate(offset + dstRowBytes * rowCount); 471 void* dst = SkTAddOffset<void>(fPtr, offset); 472 SkRectMemcpy(dst, dstRowBytes, src, srcRowBytes, trimRowBytes, rowCount); 473 } 474 475 void convertAndWrite(size_t offset, 476 const SkImageInfo& srcInfo, const void* src, size_t srcRowBytes, 477 const SkImageInfo& dstInfo, size_t dstRowBytes) { 478 SkASSERT(srcInfo.width() == dstInfo.width() && srcInfo.height() == dstInfo.height()); 479 this->validate(offset + dstRowBytes * dstInfo.height()); 480 void* dst = SkTAddOffset<void>(fPtr, offset); 481 SkAssertResult(SkConvertPixels(dstInfo, dst, dstRowBytes, srcInfo, src, srcRowBytes)); 482 } 483 484 // Writes a block of image data to the upload buffer. It converts src data of RGB_888x 485 // colorType into a 3 channel RGB_888 format. 486 void writeRGBFromRGBx(size_t offset, const void* src, size_t srcRowBytes, size_t dstRowBytes, 487 int rowPixels, int rowCount) { 488 this->validate(offset + dstRowBytes * rowCount); 489 void* dst = SkTAddOffset<void>(fPtr, offset); 490 auto* sRow = reinterpret_cast<const char*>(src); 491 auto* dRow = reinterpret_cast<char*>(dst); 492 493 for (int y = 0; y < rowCount; ++y) { 494 for (int x = 0; x < rowPixels; ++x) { 495 memcpy(dRow + 3*x, sRow+4*x, 3); 496 } 497 sRow += srcRowBytes; 498 dRow += dstRowBytes; 499 } 500 } 501 }; 502 503 } // namespace skgpu 504 505 #endif // skgpu_BufferWriter_DEFINED 506