xref: /third_party/skia/src/gpu/BufferWriter.h (revision cb93a386)
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 BufferWriter_DEFINED
9#define BufferWriter_DEFINED
10
11#include "include/core/SkRect.h"
12#include "include/private/SkNx.h"
13#include "include/private/SkTemplates.h"
14#include <type_traits>
15
16namespace skgpu {
17
18struct BufferWriter {
19public:
20    operator bool() const { return fPtr != nullptr; }
21
22protected:
23    BufferWriter() = default;
24    BufferWriter(void* ptr) : fPtr(ptr) {}
25
26    BufferWriter& operator=(const BufferWriter&) = delete;
27    BufferWriter& operator=(BufferWriter&& that) {
28        fPtr = that.fPtr;
29        that.fPtr = nullptr;
30        return *this;
31    }
32
33protected:
34    void* fPtr;
35};
36
37/**
38 * Helper for writing vertex data to a buffer. Usage:
39 *  VertexWriter vertices{target->makeVertexSpace(...)};
40 *  vertices << A0 << B0 << C0 << ...;
41 *  vertices << A1 << B1 << C1 << ...;
42 *
43 * Each value must be POD (plain old data), or have a specialization of the "<<" operator.
44 */
45struct VertexWriter : public BufferWriter {
46    inline constexpr static uint32_t kIEEE_32_infinity = 0x7f800000;
47
48    VertexWriter() = default;
49    VertexWriter(void* ptr) : BufferWriter(ptr) {}
50    VertexWriter(const VertexWriter&) = delete;
51    VertexWriter(VertexWriter&& that) { *this = std::move(that); }
52
53    VertexWriter& operator=(const VertexWriter&) = delete;
54    VertexWriter& operator=(VertexWriter&& that) {
55        BufferWriter::operator=(std::move(that));
56        return *this;
57    }
58
59    bool operator==(const VertexWriter& that) const { return fPtr == that.fPtr; }
60
61    // TODO: Remove this call. We want all users of VertexWriter to have to go through the vertex
62    // writer functions to write data. We do not want them to directly access fPtr and copy their
63    // own data.
64    void* ptr() const { return fPtr; }
65
66    VertexWriter makeOffset(ptrdiff_t offsetInBytes) const {
67        return {SkTAddOffset<void>(fPtr, offsetInBytes)};
68    }
69
70    template <typename T>
71    struct Conditional {
72        bool fCondition;
73        T fValue;
74    };
75
76    template <typename T>
77    static Conditional<T> If(bool condition, const T& value) {
78        return {condition, value};
79    }
80
81    template <typename T>
82    struct Skip {};
83
84    template <typename T>
85    void writeArray(const T* array, int count) {
86        static_assert(std::is_pod<T>::value, "");
87        memcpy(fPtr, array, count * sizeof(T));
88        fPtr = SkTAddOffset<void>(fPtr, count * sizeof(T));
89    }
90
91    template <typename T>
92    void fill(const T& val, int repeatCount) {
93        for (int i = 0; i < repeatCount; ++i) {
94            *this << val;
95        }
96    }
97
98    /**
99     * Specialized utilities for writing a four-vertices, with some data being replicated at each
100     * vertex, and other data being the appropriate 2-components from an SkRect to construct a
101     * triangle strip.
102     *
103     * - Four sets of data will be written
104     *
105     * - For any arguments where is_quad<Type>::value is true, a unique point will be written at
106     *   each vertex. To make a custom type be emitted as a quad, declare:
107     *
108     *       template<> struct VertexWriter::is_quad<MyQuadClass> : std::true_type {};
109     *
110     *   and define:
111     *
112     *       MyQuadClass::writeVertex(int cornerIdx, VertexWriter&) const { ... }
113     *
114     * - For any arguments where is_quad<Type>::value is false, its value will be replicated at each
115     *   vertex.
116     */
117    template <typename T>
118    struct is_quad : std::false_type {};
119
120    template <typename T>
121    struct TriStrip {
122        void writeVertex(int cornerIdx, VertexWriter& w) const {
123            switch (cornerIdx) {
124                case 0: w << l << t; return;
125                case 1: w << l << b; return;
126                case 2: w << r << t; return;
127                case 3: w << r << b; return;
128            }
129            SkUNREACHABLE;
130        }
131        T l, t, r, b;
132    };
133
134    static TriStrip<float> TriStripFromRect(const SkRect& r) {
135        return { r.fLeft, r.fTop, r.fRight, r.fBottom };
136    }
137
138    static TriStrip<uint16_t> TriStripFromUVs(const std::array<uint16_t, 4>& rect) {
139        return { rect[0], rect[1], rect[2], rect[3] };
140    }
141
142    template <typename T>
143    struct TriFan {
144        void writeVertex(int cornerIdx, VertexWriter& w) const {
145            switch (cornerIdx) {
146                case 0: w << l << t; return;
147                case 1: w << l << b; return;
148                case 2: w << r << b; return;
149                case 3: w << r << t; return;
150            }
151            SkUNREACHABLE;
152        }
153        T l, t, r, b;
154    };
155
156    static TriFan<float> TriFanFromRect(const SkRect& r) {
157        return { r.fLeft, r.fTop, r.fRight, r.fBottom };
158    }
159
160    template <typename... Args>
161    void writeQuad(const Args&... remainder) {
162        this->writeQuadVertex<0>(remainder...);
163        this->writeQuadVertex<1>(remainder...);
164        this->writeQuadVertex<2>(remainder...);
165        this->writeQuadVertex<3>(remainder...);
166    }
167
168private:
169    template <int kCornerIdx, typename T, typename... Args>
170    std::enable_if_t<!is_quad<T>::value, void> writeQuadVertex(const T& val,
171                                                               const Args&... remainder) {
172        *this << val;  // Non-quads duplicate their value.
173        this->writeQuadVertex<kCornerIdx>(remainder...);
174    }
175
176    template <int kCornerIdx, typename Q, typename... Args>
177    std::enable_if_t<is_quad<Q>::value, void> writeQuadVertex(const Q& quad,
178                                                              const Args&... remainder) {
179        quad.writeVertex(kCornerIdx, *this);  // Quads emit a different corner each time.
180        this->writeQuadVertex<kCornerIdx>(remainder...);
181    }
182
183    template <int kCornerIdx>
184    void writeQuadVertex() {}
185
186    template <typename T> friend VertexWriter& operator<<(VertexWriter& w, const T& val);
187};
188
189template <typename T>
190inline VertexWriter& operator<<(VertexWriter& w, const T& val) {
191    static_assert(std::is_pod<T>::value, "");
192    memcpy(w.fPtr, &val, sizeof(T));
193    w = w.makeOffset(sizeof(T));
194    return w;
195}
196
197template <typename T>
198inline VertexWriter& operator<<(VertexWriter& w, const VertexWriter::Conditional<T>& val) {
199    static_assert(std::is_pod<T>::value, "");
200    if (val.fCondition) {
201        w << val.fValue;
202    }
203    return w;
204}
205
206template <typename T>
207inline VertexWriter& operator<<(VertexWriter& w, const VertexWriter::Skip<T>& val) {
208    w = w.makeOffset(sizeof(T));
209    return w;
210}
211
212template <>
213SK_MAYBE_UNUSED inline VertexWriter& operator<<(VertexWriter& w, const Sk4f& vector) {
214    vector.store(w.fPtr);
215    w = w.makeOffset(sizeof(vector));
216    return w;
217}
218
219template <typename T>
220struct VertexWriter::is_quad<VertexWriter::TriStrip<T>> : std::true_type {};
221
222template <typename T>
223struct VertexWriter::is_quad<VertexWriter::TriFan<T>> : std::true_type {};
224
225///////////////////////////////////////////////////////////////////////////////////////////////////
226
227struct IndexWriter : public BufferWriter {
228    IndexWriter() = default;
229    IndexWriter(void* ptr) : BufferWriter(ptr) {}
230    IndexWriter(const IndexWriter&) = delete;
231    IndexWriter(IndexWriter&& that) { *this = std::move(that); }
232
233    IndexWriter& operator=(const IndexWriter&) = delete;
234    IndexWriter& operator=(IndexWriter&& that) {
235        BufferWriter::operator=(std::move(that));
236        return *this;
237    }
238
239    IndexWriter makeAdvance(int numIndices) const {
240        return {SkTAddOffset<void>(fPtr, numIndices * sizeof(uint16_t))};
241    }
242
243    void writeArray(const uint16_t* array, int count) {
244        memcpy(fPtr, array, count * sizeof(uint16_t));
245        fPtr = SkTAddOffset<void>(fPtr, count * sizeof(uint16_t));
246    }
247
248    friend IndexWriter& operator<<(IndexWriter& w, uint16_t val);
249};
250
251inline IndexWriter& operator<<(IndexWriter& w, uint16_t val) {
252    memcpy(w.fPtr, &val, sizeof(uint16_t));
253    w = w.makeAdvance(1);
254    return w;
255}
256
257///////////////////////////////////////////////////////////////////////////////////////////////////
258
259struct UniformWriter : public BufferWriter {
260    UniformWriter() = default;
261    UniformWriter(void* ptr) : BufferWriter(ptr) {}
262    UniformWriter(const UniformWriter&) = delete;
263    UniformWriter(UniformWriter&& that) { *this = std::move(that); }
264
265    UniformWriter& operator=(const UniformWriter&) = delete;
266    UniformWriter& operator=(UniformWriter&& that) {
267        BufferWriter::operator=(std::move(that));
268        return *this;
269    }
270
271    void write(const void* src, size_t bytes) {
272        memcpy(fPtr, src, bytes);
273        fPtr = SkTAddOffset<void>(fPtr, bytes);
274    }
275};
276
277}  // namespace skgpu
278
279#endif // BufferWriter_DEFINED
280