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