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