blob: 192b86224219eea6938f85d8b8f06fb9cf4c5b04 [file] [log] [blame]
Brian Osmanf9aabff2018-11-13 16:11:38 -05001/*
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 GrVertexWriter_DEFINED
9#define GrVertexWriter_DEFINED
10
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/private/SkTemplates.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040012#include "src/gpu/GrColor.h"
Michael Ludwigfd4f4df2019-05-29 09:51:09 -040013#include "src/gpu/geometry/GrQuad.h"
Brian Osmanf9aabff2018-11-13 16:11:38 -050014#include <type_traits>
15
16/**
17 * Helper for writing vertex data to a buffer. Usage:
18 * GrVertexWriter vertices{target->makeVertexSpace(...)};
19 * vertices.write(A0, B0, C0, ...);
20 * vertices.write(A1, B1, C1, ...);
21 *
22 * Supports any number of arguments. Each argument must be POD (plain old data), or an array
23 * thereof.
24 */
25struct GrVertexWriter {
Brian Osman4486d982018-11-15 15:56:04 -050026 void* fPtr;
27
Chris Daltona43d5832021-02-07 21:10:32 -070028 GrVertexWriter() = default;
29 GrVertexWriter(void* ptr) : fPtr(ptr) {}
30 GrVertexWriter(const GrVertexWriter&) = delete;
31 GrVertexWriter(GrVertexWriter&& that) { *this = std::move(that); }
32
33 GrVertexWriter& operator=(const GrVertexWriter&) = delete;
34 GrVertexWriter& operator=(GrVertexWriter&& that) {
35 fPtr = that.fPtr;
36 that.fPtr = nullptr;
37 return *this;
38 }
39
Chris Dalton8ed7a8d2021-03-31 10:40:29 -060040 bool operator==(const GrVertexWriter& that) const { return fPtr == that.fPtr; }
41 operator bool() const { return fPtr != nullptr; }
Chris Daltona43d5832021-02-07 21:10:32 -070042
43 GrVertexWriter makeOffset(size_t offsetInBytes) const {
44 return {SkTAddOffset<void>(fPtr, offsetInBytes)};
45 }
46
Brian Osmancfec9d52018-11-20 11:39:15 -050047 template <typename T>
48 class Conditional {
49 public:
50 explicit Conditional(bool condition, const T& value)
51 : fCondition(condition), fValue(value) {}
52 private:
53 friend struct GrVertexWriter;
54
55 bool fCondition;
56 T fValue;
57 };
58
59 template <typename T>
60 static Conditional<T> If(bool condition, const T& value) {
61 return Conditional<T>(condition, value);
62 }
63
Brian Osmand2fa2eb2018-12-26 16:48:40 -050064 template <typename T>
65 struct Skip {};
66
Brian Osmanf9aabff2018-11-13 16:11:38 -050067 template <typename T, typename... Args>
68 void write(const T& val, const Args&... remainder) {
69 static_assert(std::is_pod<T>::value, "");
Brian Osman0dd43022018-11-16 15:53:26 -050070 // This assert is barely related to what we're trying to check - that our vertex data
71 // matches our attribute layouts, where each attribute is aligned to four bytes. If this
72 // becomes a problem, just remove it.
73 static_assert(alignof(T) <= 4, "");
Brian Osmanf9aabff2018-11-13 16:11:38 -050074 memcpy(fPtr, &val, sizeof(T));
75 fPtr = SkTAddOffset<void>(fPtr, sizeof(T));
76 this->write(remainder...);
77 }
78
79 template <typename T, size_t N, typename... Args>
80 void write(const T(&val)[N], const Args&... remainder) {
81 static_assert(std::is_pod<T>::value, "");
Brian Osman0dd43022018-11-16 15:53:26 -050082 static_assert(alignof(T) <= 4, "");
Brian Osmanf9aabff2018-11-13 16:11:38 -050083 memcpy(fPtr, val, N * sizeof(T));
84 fPtr = SkTAddOffset<void>(fPtr, N * sizeof(T));
85 this->write(remainder...);
86 }
87
Brian Osman5c8a6b32018-11-19 11:56:57 -050088 template <typename... Args>
89 void write(const GrVertexColor& color, const Args&... remainder) {
90 this->write(color.fColor[0]);
91 if (color.fWideColor) {
92 this->write(color.fColor[1]);
Brian Osman2715bf52019-12-06 14:38:47 -050093 this->write(color.fColor[2]);
94 this->write(color.fColor[3]);
Brian Osman5c8a6b32018-11-19 11:56:57 -050095 }
96 this->write(remainder...);
97 }
98
Brian Osmancfec9d52018-11-20 11:39:15 -050099 template <typename T, typename... Args>
100 void write(const Conditional<T>& val, const Args&... remainder) {
101 if (val.fCondition) {
102 this->write(val.fValue);
103 }
104 this->write(remainder...);
105 }
106
Brian Osmand2fa2eb2018-12-26 16:48:40 -0500107 template <typename T, typename... Args>
108 void write(const Skip<T>& val, const Args&... remainder) {
109 fPtr = SkTAddOffset<void>(fPtr, sizeof(T));
110 this->write(remainder...);
111 }
112
Michael Ludwigf995c052018-11-26 15:24:29 -0500113 template <typename... Args>
114 void write(const Sk4f& vector, const Args&... remainder) {
115 float buffer[4];
116 vector.store(buffer);
117 this->write<float, 4>(buffer);
118 this->write(remainder...);
119 }
120
Chris Daltona43d5832021-02-07 21:10:32 -0700121 template <typename T>
122 void writeArray(const T* array, int count) {
123 static_assert(std::is_pod<T>::value, "");
124 static_assert(alignof(T) <= 4, "");
125 memcpy(fPtr, array, count * sizeof(T));
126 fPtr = SkTAddOffset<void>(fPtr, count * sizeof(T));
127 }
128
129 template <typename T>
130 void fill(const T& val, int repeatCount) {
131 for (int i = 0; i < repeatCount; ++i) {
132 this->write(val);
133 }
134 }
135
Brian Osmanffd11f4a2020-03-30 09:57:53 -0400136 void writeRaw(const void* data, size_t size) {
137 memcpy(fPtr, data, size);
138 fPtr = SkTAddOffset<void>(fPtr, size);
139 }
140
Brian Osmanf9aabff2018-11-13 16:11:38 -0500141 void write() {}
142
Brian Osman4486d982018-11-15 15:56:04 -0500143 /**
144 * Specialized utility for writing a four-vertices, with some data being replicated at each
145 * vertex, and other data being the appropriate 2-components from an SkRect to construct a
146 * triangle strip.
147 *
148 * writeQuad(A, B, C, ...) is similar to write(A, B, C, ...), except that:
149 *
150 * - Four sets of data will be written
151 * - For any arguments of type TriStrip, a unique SkPoint will be written at each vertex,
152 * in this order: left-top, left-bottom, right-top, right-bottom.
153 */
Brian Osman0dd43022018-11-16 15:53:26 -0500154 template <typename T>
155 struct TriStrip { T l, t, r, b; };
156
157 static TriStrip<float> TriStripFromRect(const SkRect& r) {
158 return { r.fLeft, r.fTop, r.fRight, r.fBottom };
159 }
Brian Osman4486d982018-11-15 15:56:04 -0500160
Robert Phillips6d3bc292020-04-06 10:29:28 -0400161 static TriStrip<uint16_t> TriStripFromUVs(const std::array<uint16_t, 4>& rect) {
162 return { rect[0], rect[1], rect[2], rect[3] };
163 }
164
Brian Osmancfec9d52018-11-20 11:39:15 -0500165 template <typename T>
166 struct TriFan { T l, t, r, b; };
167
168 static TriFan<float> TriFanFromRect(const SkRect& r) {
169 return { r.fLeft, r.fTop, r.fRight, r.fBottom };
170 }
171
Brian Osman4486d982018-11-15 15:56:04 -0500172 template <typename... Args>
173 void writeQuad(const Args&... remainder) {
174 this->writeQuadVert<0>(remainder...);
175 this->writeQuadVert<1>(remainder...);
176 this->writeQuadVert<2>(remainder...);
177 this->writeQuadVert<3>(remainder...);
178 }
179
180private:
181 template <int corner, typename T, typename... Args>
182 void writeQuadVert(const T& val, const Args&... remainder) {
183 this->writeQuadValue<corner>(val);
184 this->writeQuadVert<corner>(remainder...);
185 }
186
187 template <int corner>
188 void writeQuadVert() {}
189
190 template <int corner, typename T>
191 void writeQuadValue(const T& val) {
192 this->write(val);
193 }
194
Brian Osman0dd43022018-11-16 15:53:26 -0500195 template <int corner, typename T>
196 void writeQuadValue(const TriStrip<T>& r) {
Brian Osman4486d982018-11-15 15:56:04 -0500197 switch (corner) {
Brian Osman0dd43022018-11-16 15:53:26 -0500198 case 0: this->write(r.l, r.t); break;
199 case 1: this->write(r.l, r.b); break;
200 case 2: this->write(r.r, r.t); break;
201 case 3: this->write(r.r, r.b); break;
Brian Osman4486d982018-11-15 15:56:04 -0500202 }
203 }
Brian Osman0dd43022018-11-16 15:53:26 -0500204
Brian Osmancfec9d52018-11-20 11:39:15 -0500205 template <int corner, typename T>
206 void writeQuadValue(const TriFan<T>& r) {
207 switch (corner) {
208 case 0: this->write(r.l, r.t); break;
209 case 1: this->write(r.l, r.b); break;
210 case 2: this->write(r.r, r.b); break;
211 case 3: this->write(r.r, r.t); break;
212 }
213 }
214
Brian Osman0dd43022018-11-16 15:53:26 -0500215 template <int corner>
216 void writeQuadValue(const GrQuad& q) {
217 this->write(q.point(corner));
218 }
Brian Osmanf9aabff2018-11-13 16:11:38 -0500219};
220
221#endif