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
14class 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 */
22class GrMesh {
23public:
24    GrMesh(GrPrimitiveType primitiveType)
25        : fPrimitiveType(primitiveType)
26        , fBaseVertex(0) {
27        SkDEBUGCODE(fNonIndexNonInstanceData.fVertexCount = -1;)
28    }
29
30    GrPrimitiveType primitiveType() const { return fPrimitiveType; }
31    bool isIndexed() const { return SkToBool(fIndexBuffer.get()); }
32    bool isInstanced() const { return SkToBool(fInstanceBuffer.get()); }
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
72        virtual ~SendToGpuImpl() {}
73    };
74
75    void sendToGpu(const GrPrimitiveProcessor&, SendToGpuImpl*) const;
76
77    struct PatternBatch;
78
79private:
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
132inline void GrMesh::setNonIndexedNonInstanced(int vertexCount) {
133    fIndexBuffer.reset(nullptr);
134    fInstanceBuffer.reset(nullptr);
135    fNonIndexNonInstanceData.fVertexCount = vertexCount;
136}
137
138inline 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
153inline 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
169inline 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
181inline 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
196inline void GrMesh::setVertexData(const GrBuffer* vertexBuffer, int baseVertex) {
197    SkASSERT(baseVertex >= 0);
198    fVertexBuffer.reset(vertexBuffer);
199    fBaseVertex = baseVertex;
200}
201
202inline 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