xref: /aosp_15_r20/external/skia/src/gpu/BufferWriter.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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