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