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