1 /*
2 * Copyright 2015 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 GrMesh_DEFINED
9 #define GrMesh_DEFINED
10
11 #include "src/gpu/GrBuffer.h"
12 #include "src/gpu/GrGpuBuffer.h"
13
14 class GrPrimitiveProcessor;
15
16 /**
17 * Used to communicate index and vertex buffers, counts, and offsets for a draw from GrOp to
18 * GrGpu. It also holds the primitive type for the draw. TODO: Consider moving ownership of this
19 * and draw-issuing responsibility to GrPrimitiveProcessor. The rest of the vertex info lives there
20 * already (stride, attribute mappings).
21 */
22 class GrMesh {
23 public:
GrMesh()24 GrMesh() {
25 SkDEBUGCODE(fNonIndexNonInstanceData.fVertexCount = -1;)
26 }
27
isIndexed()28 bool isIndexed() const { return SkToBool(fIndexBuffer.get()); }
indexBuffer()29 const GrBuffer* indexBuffer() const {
30 SkASSERT(this->isIndexed());
31 return fIndexBuffer.get();
32 }
primitiveRestart()33 GrPrimitiveRestart primitiveRestart() const {
34 return GrPrimitiveRestart(fFlags & Flags::kUsePrimitiveRestart);
35 }
36
isInstanced()37 bool isInstanced() const { return fFlags & Flags::kIsInstanced; }
instanceBuffer()38 const GrBuffer* instanceBuffer() const {
39 SkASSERT(this->isInstanced() || !fInstanceBuffer);
40 return fInstanceBuffer.get();
41 }
42
vertexBuffer()43 const GrBuffer* vertexBuffer() const { return fVertexBuffer.get(); }
44
45 void setNonIndexedNonInstanced(int vertexCount);
46
47 void setIndexed(sk_sp<const GrBuffer> indexBuffer, int indexCount, int baseIndex,
48 uint16_t minIndexValue, uint16_t maxIndexValue, GrPrimitiveRestart);
49 void setIndexedPatterned(sk_sp<const GrBuffer> indexBuffer, int indexCount, int vertexCount,
50 int patternRepeatCount, int maxPatternRepetitionsInIndexBuffer);
51
52 void setInstanced(sk_sp<const GrBuffer> instanceBuffer, int instanceCount, int baseInstance,
53 int vertexCount);
54 void setIndexedInstanced(sk_sp<const GrBuffer> indexBuffer, int indexCount,
55 sk_sp<const GrBuffer> instanceBuffer, int instanceCount,
56 int baseInstance, GrPrimitiveRestart);
57
58 void setVertexData(sk_sp<const GrBuffer> vertexBuffer, int baseVertex = 0);
59
60 class SendToGpuImpl {
61 public:
62 virtual void sendArrayMeshToGpu(GrPrimitiveType, const GrMesh&, int vertexCount,
63 int baseVertex) = 0;
64 virtual void sendIndexedMeshToGpu(GrPrimitiveType, const GrMesh&, int indexCount,
65 int baseIndex, uint16_t minIndexValue,
66 uint16_t maxIndexValue, int baseVertex) = 0;
67 virtual void sendInstancedMeshToGpu(GrPrimitiveType, const GrMesh&, int vertexCount,
68 int baseVertex, int instanceCount,
69 int baseInstance) = 0;
70 virtual void sendIndexedInstancedMeshToGpu(GrPrimitiveType, const GrMesh&, int indexCount,
71 int baseIndex, int baseVertex, int instanceCount,
72 int baseInstance) = 0;
~SendToGpuImpl()73 virtual ~SendToGpuImpl() {}
74 };
75
76 void sendToGpu(GrPrimitiveType, SendToGpuImpl*) const;
77
78 private:
79 enum class Flags : uint8_t {
80 kNone = 0,
81 kUsePrimitiveRestart = 1 << 0,
82 kIsInstanced = 1 << 1,
83 };
84
85 GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(Flags);
86 static_assert(Flags(GrPrimitiveRestart::kNo) == Flags::kNone);
87 static_assert(Flags(GrPrimitiveRestart::kYes) == Flags::kUsePrimitiveRestart);
88
89 sk_sp<const GrBuffer> fIndexBuffer;
90 sk_sp<const GrBuffer> fInstanceBuffer;
91 sk_sp<const GrBuffer> fVertexBuffer;
92 int fBaseVertex = 0;
93 Flags fFlags = Flags::kNone;
94
95 union {
96 struct { // When fIndexBuffer == nullptr and isInstanced() == false.
97 int fVertexCount;
98 } fNonIndexNonInstanceData;
99
100 struct { // When fIndexBuffer != nullptr and isInstanced() == false.
101 struct {
102 int fIndexCount;
103 int fPatternRepeatCount;
104 } fIndexData;
105
106 union {
107 struct { // When fPatternRepeatCount == 0.
108 int fBaseIndex;
109 uint16_t fMinIndexValue;
110 uint16_t fMaxIndexValue;
111 } fNonPatternIndexData;
112
113 struct { // When fPatternRepeatCount != 0.
114 int fVertexCount;
115 int fMaxPatternRepetitionsInIndexBuffer;
116 } fPatternData;
117 };
118 };
119
120 struct { // When isInstanced() != false.
121 struct {
122 int fInstanceCount;
123 int fBaseInstance;
124 } fInstanceData;
125
126 union { // When fIndexBuffer == nullptr.
127 struct {
128 int fVertexCount;
129 } fInstanceNonIndexData;
130
131 struct { // When fIndexBuffer != nullptr.
132 int fIndexCount;
133 } fInstanceIndexData;
134 };
135 };
136 };
137 };
138
139 GR_MAKE_BITFIELD_CLASS_OPS(GrMesh::Flags);
140
setNonIndexedNonInstanced(int vertexCount)141 inline void GrMesh::setNonIndexedNonInstanced(int vertexCount) {
142 fIndexBuffer.reset();
143 fInstanceBuffer.reset();
144 fNonIndexNonInstanceData.fVertexCount = vertexCount;
145 fFlags = Flags::kNone;
146 }
147
setIndexed(sk_sp<const GrBuffer> indexBuffer,int indexCount,int baseIndex,uint16_t minIndexValue,uint16_t maxIndexValue,GrPrimitiveRestart primitiveRestart)148 inline void GrMesh::setIndexed(sk_sp<const GrBuffer> indexBuffer, int indexCount, int baseIndex,
149 uint16_t minIndexValue, uint16_t maxIndexValue,
150 GrPrimitiveRestart primitiveRestart) {
151 SkASSERT(indexBuffer);
152 SkASSERT(indexCount >= 1);
153 SkASSERT(baseIndex >= 0);
154 SkASSERT(maxIndexValue >= minIndexValue);
155 fIndexBuffer = std::move(indexBuffer);
156 fInstanceBuffer.reset();
157 fIndexData.fIndexCount = indexCount;
158 fIndexData.fPatternRepeatCount = 0;
159 fNonPatternIndexData.fBaseIndex = baseIndex;
160 fNonPatternIndexData.fMinIndexValue = minIndexValue;
161 fNonPatternIndexData.fMaxIndexValue = maxIndexValue;
162 fFlags = Flags(primitiveRestart);
163 }
164
setIndexedPatterned(sk_sp<const GrBuffer> indexBuffer,int indexCount,int vertexCount,int patternRepeatCount,int maxPatternRepetitionsInIndexBuffer)165 inline void GrMesh::setIndexedPatterned(sk_sp<const GrBuffer> indexBuffer, int indexCount,
166 int vertexCount, int patternRepeatCount,
167 int maxPatternRepetitionsInIndexBuffer) {
168 SkASSERT(indexBuffer);
169 SkASSERT(indexCount >= 1);
170 SkASSERT(vertexCount >= 1);
171 SkASSERT(patternRepeatCount >= 1);
172 SkASSERT(maxPatternRepetitionsInIndexBuffer >= 1);
173 fIndexBuffer = std::move(indexBuffer);
174 fInstanceBuffer.reset();
175 fIndexData.fIndexCount = indexCount;
176 fIndexData.fPatternRepeatCount = patternRepeatCount;
177 fPatternData.fVertexCount = vertexCount;
178 fPatternData.fMaxPatternRepetitionsInIndexBuffer = maxPatternRepetitionsInIndexBuffer;
179 fFlags = Flags::kNone;
180 }
181
setInstanced(sk_sp<const GrBuffer> instanceBuffer,int instanceCount,int baseInstance,int vertexCount)182 inline void GrMesh::setInstanced(sk_sp<const GrBuffer> instanceBuffer, int instanceCount,
183 int baseInstance, int vertexCount) {
184 SkASSERT(instanceCount >= 1);
185 SkASSERT(baseInstance >= 0);
186 fIndexBuffer.reset();
187 fInstanceBuffer = std::move(instanceBuffer);
188 fInstanceData.fInstanceCount = instanceCount;
189 fInstanceData.fBaseInstance = baseInstance;
190 fInstanceNonIndexData.fVertexCount = vertexCount;
191 fFlags = Flags::kIsInstanced;
192 }
193
setIndexedInstanced(sk_sp<const GrBuffer> indexBuffer,int indexCount,sk_sp<const GrBuffer> instanceBuffer,int instanceCount,int baseInstance,GrPrimitiveRestart primitiveRestart)194 inline void GrMesh::setIndexedInstanced(sk_sp<const GrBuffer> indexBuffer, int indexCount,
195 sk_sp<const GrBuffer> instanceBuffer, int instanceCount,
196 int baseInstance, GrPrimitiveRestart primitiveRestart) {
197 SkASSERT(indexBuffer);
198 SkASSERT(indexCount >= 1);
199 SkASSERT(instanceCount >= 1);
200 SkASSERT(baseInstance >= 0);
201 fIndexBuffer = std::move(indexBuffer);
202 fInstanceBuffer = std::move(instanceBuffer);
203 fInstanceData.fInstanceCount = instanceCount;
204 fInstanceData.fBaseInstance = baseInstance;
205 fInstanceIndexData.fIndexCount = indexCount;
206 fFlags = Flags::kIsInstanced | Flags(primitiveRestart);
207 }
208
setVertexData(sk_sp<const GrBuffer> vertexBuffer,int baseVertex)209 inline void GrMesh::setVertexData(sk_sp<const GrBuffer> vertexBuffer, int baseVertex) {
210 SkASSERT(baseVertex >= 0);
211 fVertexBuffer = std::move(vertexBuffer);
212 fBaseVertex = baseVertex;
213 }
214
sendToGpu(GrPrimitiveType primitiveType,SendToGpuImpl * impl)215 inline void GrMesh::sendToGpu(GrPrimitiveType primitiveType, SendToGpuImpl* impl) const {
216 if (this->isInstanced()) {
217 if (!this->isIndexed()) {
218 impl->sendInstancedMeshToGpu(primitiveType, *this, fInstanceNonIndexData.fVertexCount,
219 fBaseVertex, fInstanceData.fInstanceCount,
220 fInstanceData.fBaseInstance);
221 } else {
222 impl->sendIndexedInstancedMeshToGpu(
223 primitiveType, *this, fInstanceIndexData.fIndexCount, 0, fBaseVertex,
224 fInstanceData.fInstanceCount, fInstanceData.fBaseInstance);
225 }
226 return;
227 }
228
229 if (!this->isIndexed()) {
230 SkASSERT(fNonIndexNonInstanceData.fVertexCount > 0);
231 impl->sendArrayMeshToGpu(primitiveType, *this, fNonIndexNonInstanceData.fVertexCount,
232 fBaseVertex);
233 return;
234 }
235
236 if (0 == fIndexData.fPatternRepeatCount) {
237 impl->sendIndexedMeshToGpu(primitiveType, *this, fIndexData.fIndexCount,
238 fNonPatternIndexData.fBaseIndex,
239 fNonPatternIndexData.fMinIndexValue,
240 fNonPatternIndexData.fMaxIndexValue, fBaseVertex);
241 return;
242 }
243
244 SkASSERT(fIndexData.fPatternRepeatCount > 0);
245 int baseRepetition = 0;
246 do {
247 int repeatCount = std::min(fPatternData.fMaxPatternRepetitionsInIndexBuffer,
248 fIndexData.fPatternRepeatCount - baseRepetition);
249 int indexCount = fIndexData.fIndexCount * repeatCount;
250 // A patterned index buffer must contain indices in the range [0..vertexCount].
251 int minIndexValue = 0;
252 int maxIndexValue = fPatternData.fVertexCount * repeatCount - 1;
253 SkASSERT(!(fFlags & Flags::kUsePrimitiveRestart));
254 impl->sendIndexedMeshToGpu(primitiveType, *this, indexCount, 0, minIndexValue,
255 maxIndexValue,
256 fBaseVertex + fPatternData.fVertexCount * baseRepetition);
257 baseRepetition += repeatCount;
258 } while (baseRepetition < fIndexData.fPatternRepeatCount);
259 }
260
261 #endif
262