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 "GrBuffer.h"
12 #include "GrGpuResourceRef.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(GrPrimitiveType primitiveType)24 GrMesh(GrPrimitiveType primitiveType)
25 : fPrimitiveType(primitiveType)
26 , fBaseVertex(0) {
27 SkDEBUGCODE(fNonIndexNonInstanceData.fVertexCount = -1;)
28 }
29
primitiveType()30 GrPrimitiveType primitiveType() const { return fPrimitiveType; }
isIndexed()31 bool isIndexed() const { return SkToBool(fIndexBuffer.get()); }
isInstanced()32 bool isInstanced() const { return SkToBool(fInstanceBuffer.get()); }
hasVertexData()33 bool hasVertexData() const { return SkToBool(fVertexBuffer.get()); }
34
35 void setNonIndexedNonInstanced(int vertexCount);
36
37 void setIndexed(const GrBuffer* indexBuffer, int indexCount, int baseIndex,
38 uint16_t minIndexValue, uint16_t maxIndexValue);
39 void setIndexedPatterned(const GrBuffer* indexBuffer, int indexCount, int vertexCount,
40 int patternRepeatCount, int maxPatternRepetitionsInIndexBuffer);
41
42 void setInstanced(const GrBuffer* instanceBuffer, int instanceCount, int baseInstance,
43 int vertexCount);
44 void setIndexedInstanced(const GrBuffer* indexBuffer, int indexCount,
45 const GrBuffer* instanceBuffer, int instanceCount, int baseInstance=0);
46
47 void setVertexData(const GrBuffer* vertexBuffer, int baseVertex = 0);
48
49 class SendToGpuImpl {
50 public:
51 virtual void sendMeshToGpu(const GrPrimitiveProcessor&, GrPrimitiveType,
52 const GrBuffer* vertexBuffer, int vertexCount,
53 int baseVertex) = 0;
54
55 virtual void sendIndexedMeshToGpu(const GrPrimitiveProcessor&, GrPrimitiveType,
56 const GrBuffer* indexBuffer, int indexCount,
57 int baseIndex, uint16_t minIndexValue,
58 uint16_t maxIndexValue, const GrBuffer* vertexBuffer,
59 int baseVertex) = 0;
60
61 virtual void sendInstancedMeshToGpu(const GrPrimitiveProcessor&, GrPrimitiveType,
62 const GrBuffer* vertexBuffer, int vertexCount,
63 int baseVertex, const GrBuffer* instanceBuffer,
64 int instanceCount, int baseInstance) = 0;
65
66 virtual void sendIndexedInstancedMeshToGpu(const GrPrimitiveProcessor&, GrPrimitiveType,
67 const GrBuffer* indexBuffer, int indexCount,
68 int baseIndex, const GrBuffer* vertexBuffer,
69 int baseVertex, const GrBuffer* instanceBuffer,
70 int instanceCount, int baseInstance) = 0;
71
~SendToGpuImpl()72 virtual ~SendToGpuImpl() {}
73 };
74
75 void sendToGpu(const GrPrimitiveProcessor&, SendToGpuImpl*) const;
76
77 struct PatternBatch;
78
79 private:
80 using PendingBuffer = GrPendingIOResource<const GrBuffer, kRead_GrIOType>;
81
82 GrPrimitiveType fPrimitiveType;
83 PendingBuffer fIndexBuffer;
84 PendingBuffer fInstanceBuffer;
85 PendingBuffer fVertexBuffer;
86 int fBaseVertex;
87
88 union {
89 struct { // When fIndexBuffer == nullptr and fInstanceBuffer == nullptr.
90 int fVertexCount;
91 } fNonIndexNonInstanceData;
92
93 struct { // When fIndexBuffer != nullptr and fInstanceBuffer == nullptr.
94 struct {
95 int fIndexCount;
96 int fPatternRepeatCount;
97 } fIndexData;
98
99 union {
100 struct { // When fPatternRepeatCount == 0.
101 int fBaseIndex;
102 uint16_t fMinIndexValue;
103 uint16_t fMaxIndexValue;
104 } fNonPatternIndexData;
105
106 struct { // When fPatternRepeatCount != 0.
107 int fVertexCount;
108 int fMaxPatternRepetitionsInIndexBuffer;
109 } fPatternData;
110 };
111 };
112
113 struct { // When fInstanceBuffer != nullptr.
114 struct {
115 int fInstanceCount;
116 int fBaseInstance;
117 } fInstanceData;
118
119 union { // When fIndexBuffer == nullptr.
120 struct {
121 int fVertexCount;
122 } fInstanceNonIndexData;
123
124 struct { // When fIndexBuffer != nullptr.
125 int fIndexCount;
126 } fInstanceIndexData;
127 };
128 };
129 };
130 };
131
setNonIndexedNonInstanced(int vertexCount)132 inline void GrMesh::setNonIndexedNonInstanced(int vertexCount) {
133 fIndexBuffer.reset(nullptr);
134 fInstanceBuffer.reset(nullptr);
135 fNonIndexNonInstanceData.fVertexCount = vertexCount;
136 }
137
setIndexed(const GrBuffer * indexBuffer,int indexCount,int baseIndex,uint16_t minIndexValue,uint16_t maxIndexValue)138 inline void GrMesh::setIndexed(const GrBuffer* indexBuffer, int indexCount, int baseIndex,
139 uint16_t minIndexValue, uint16_t maxIndexValue) {
140 SkASSERT(indexBuffer);
141 SkASSERT(indexCount >= 1);
142 SkASSERT(baseIndex >= 0);
143 SkASSERT(maxIndexValue >= minIndexValue);
144 fIndexBuffer.reset(indexBuffer);
145 fInstanceBuffer.reset(nullptr);
146 fIndexData.fIndexCount = indexCount;
147 fIndexData.fPatternRepeatCount = 0;
148 fNonPatternIndexData.fBaseIndex = baseIndex;
149 fNonPatternIndexData.fMinIndexValue = minIndexValue;
150 fNonPatternIndexData.fMaxIndexValue = maxIndexValue;
151 }
152
setIndexedPatterned(const GrBuffer * indexBuffer,int indexCount,int vertexCount,int patternRepeatCount,int maxPatternRepetitionsInIndexBuffer)153 inline void GrMesh::setIndexedPatterned(const GrBuffer* indexBuffer, int indexCount,
154 int vertexCount, int patternRepeatCount,
155 int maxPatternRepetitionsInIndexBuffer) {
156 SkASSERT(indexBuffer);
157 SkASSERT(indexCount >= 1);
158 SkASSERT(vertexCount >= 1);
159 SkASSERT(patternRepeatCount >= 1);
160 SkASSERT(maxPatternRepetitionsInIndexBuffer >= 1);
161 fIndexBuffer.reset(indexBuffer);
162 fInstanceBuffer.reset(nullptr);
163 fIndexData.fIndexCount = indexCount;
164 fIndexData.fPatternRepeatCount = patternRepeatCount;
165 fPatternData.fVertexCount = vertexCount;
166 fPatternData.fMaxPatternRepetitionsInIndexBuffer = maxPatternRepetitionsInIndexBuffer;
167 }
168
setInstanced(const GrBuffer * instanceBuffer,int instanceCount,int baseInstance,int vertexCount)169 inline void GrMesh::setInstanced(const GrBuffer* instanceBuffer, int instanceCount,
170 int baseInstance, int vertexCount) {
171 SkASSERT(instanceBuffer);
172 SkASSERT(instanceCount >= 1);
173 SkASSERT(baseInstance >= 0);
174 fIndexBuffer.reset(nullptr);
175 fInstanceBuffer.reset(instanceBuffer);
176 fInstanceData.fInstanceCount = instanceCount;
177 fInstanceData.fBaseInstance = baseInstance;
178 fInstanceNonIndexData.fVertexCount = vertexCount;
179 }
180
setIndexedInstanced(const GrBuffer * indexBuffer,int indexCount,const GrBuffer * instanceBuffer,int instanceCount,int baseInstance)181 inline void GrMesh::setIndexedInstanced(const GrBuffer* indexBuffer, int indexCount,
182 const GrBuffer* instanceBuffer, int instanceCount,
183 int baseInstance) {
184 SkASSERT(indexBuffer);
185 SkASSERT(indexCount >= 1);
186 SkASSERT(instanceBuffer);
187 SkASSERT(instanceCount >= 1);
188 SkASSERT(baseInstance >= 0);
189 fIndexBuffer.reset(indexBuffer);
190 fInstanceBuffer.reset(instanceBuffer);
191 fInstanceData.fInstanceCount = instanceCount;
192 fInstanceData.fBaseInstance = baseInstance;
193 fInstanceIndexData.fIndexCount = indexCount;
194 }
195
setVertexData(const GrBuffer * vertexBuffer,int baseVertex)196 inline void GrMesh::setVertexData(const GrBuffer* vertexBuffer, int baseVertex) {
197 SkASSERT(baseVertex >= 0);
198 fVertexBuffer.reset(vertexBuffer);
199 fBaseVertex = baseVertex;
200 }
201
sendToGpu(const GrPrimitiveProcessor & primProc,SendToGpuImpl * impl)202 inline void GrMesh::sendToGpu(const GrPrimitiveProcessor& primProc, SendToGpuImpl* impl) const {
203 if (this->isInstanced()) {
204 if (!this->isIndexed()) {
205 impl->sendInstancedMeshToGpu(primProc, fPrimitiveType, fVertexBuffer.get(),
206 fInstanceNonIndexData.fVertexCount, fBaseVertex,
207 fInstanceBuffer.get(), fInstanceData.fInstanceCount,
208 fInstanceData.fBaseInstance);
209 } else {
210 impl->sendIndexedInstancedMeshToGpu(primProc, fPrimitiveType, fIndexBuffer.get(),
211 fInstanceIndexData.fIndexCount, 0,
212 fVertexBuffer.get(), fBaseVertex,
213 fInstanceBuffer.get(), fInstanceData.fInstanceCount,
214 fInstanceData.fBaseInstance);
215 }
216 return;
217 }
218
219 if (!this->isIndexed()) {
220 SkASSERT(fNonIndexNonInstanceData.fVertexCount > 0);
221 impl->sendMeshToGpu(primProc, fPrimitiveType, fVertexBuffer.get(),
222 fNonIndexNonInstanceData.fVertexCount, fBaseVertex);
223 return;
224 }
225
226 if (0 == fIndexData.fPatternRepeatCount) {
227 impl->sendIndexedMeshToGpu(primProc, fPrimitiveType, fIndexBuffer.get(),
228 fIndexData.fIndexCount, fNonPatternIndexData.fBaseIndex,
229 fNonPatternIndexData.fMinIndexValue,
230 fNonPatternIndexData.fMaxIndexValue, fVertexBuffer.get(),
231 fBaseVertex);
232 return;
233 }
234
235 SkASSERT(fIndexData.fPatternRepeatCount > 0);
236 int baseRepetition = 0;
237 do {
238 int repeatCount = SkTMin(fPatternData.fMaxPatternRepetitionsInIndexBuffer,
239 fIndexData.fPatternRepeatCount - baseRepetition);
240 // A patterned index buffer must contain indices in the range [0..vertexCount].
241 int minIndexValue = 0;
242 int maxIndexValue = fPatternData.fVertexCount * repeatCount - 1;
243 impl->sendIndexedMeshToGpu(primProc, fPrimitiveType, fIndexBuffer.get(),
244 fIndexData.fIndexCount * repeatCount, 0, minIndexValue,
245 maxIndexValue, fVertexBuffer.get(),
246 fBaseVertex + fPatternData.fVertexCount * baseRepetition);
247 baseRepetition += repeatCount;
248 } while (baseRepetition < fIndexData.fPatternRepeatCount);
249 }
250
251 #endif
252