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