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 GrVertices_DEFINED
9#define GrVertices_DEFINED
10
11#include "GrIndexBuffer.h"
12#include "GrVertexBuffer.h"
13
14class GrNonInstancedVertices {
15public:
16    GrPrimitiveType primitiveType() const { return fPrimitiveType; }
17    int startVertex() const { return fStartVertex; }
18    int startIndex() const { return fStartIndex; }
19    int vertexCount() const { return fVertexCount; }
20    int indexCount() const { return fIndexCount; }
21    bool isIndexed() const { return fIndexCount > 0; }
22
23    const GrVertexBuffer* vertexBuffer() const { return fVertexBuffer.get(); }
24    const GrIndexBuffer* indexBuffer() const { return fIndexBuffer.get(); }
25
26protected:
27    GrPrimitiveType         fPrimitiveType;
28    int                     fStartVertex;
29    int                     fStartIndex;
30    int                     fVertexCount;
31    int                     fIndexCount;
32    GrPendingIOResource<const GrVertexBuffer, kRead_GrIOType> fVertexBuffer;
33    GrPendingIOResource<const GrIndexBuffer, kRead_GrIOType>  fIndexBuffer;
34    friend class GrVertices;
35};
36
37/**
38 * Used to communicate index and vertex buffers, counts, and offsets for a draw from GrBatch to
39 * GrGpu. It also holds the primitive type for the draw. TODO: Consider moving ownership of this
40 * and draw-issuing responsibility to GrPrimitiveProcessor. The rest of the vertex info lives there
41 * already (stride, attribute mappings).
42 */
43class GrVertices : public GrNonInstancedVertices {
44public:
45    GrVertices() {}
46    GrVertices(const GrVertices& di) { (*this) = di; }
47    GrVertices& operator =(const GrVertices& di);
48
49    void init(GrPrimitiveType primType, const GrVertexBuffer* vertexBuffer, int startVertex,
50                int vertexCount) {
51        SkASSERT(vertexBuffer);
52        SkASSERT(vertexCount);
53        SkASSERT(startVertex >= 0);
54        fPrimitiveType = primType;
55        fVertexBuffer.reset(vertexBuffer);
56        fIndexBuffer.reset(nullptr);
57        fStartVertex = startVertex;
58        fStartIndex = 0;
59        fVertexCount = vertexCount;
60        fIndexCount = 0;
61        fInstanceCount = 0;
62        fVerticesPerInstance = 0;
63        fIndicesPerInstance = 0;
64        fMaxInstancesPerDraw = 0;
65    }
66
67    void initIndexed(GrPrimitiveType primType,
68                        const GrVertexBuffer* vertexBuffer,
69                        const GrIndexBuffer* indexBuffer,
70                        int startVertex,
71                        int startIndex,
72                        int vertexCount,
73                        int indexCount) {
74        SkASSERT(indexBuffer);
75        SkASSERT(vertexBuffer);
76        SkASSERT(indexCount);
77        SkASSERT(vertexCount);
78        SkASSERT(startIndex >= 0);
79        SkASSERT(startVertex >= 0);
80        fPrimitiveType = primType;
81        fVertexBuffer.reset(vertexBuffer);
82        fIndexBuffer.reset(indexBuffer);
83        fStartVertex = startVertex;
84        fStartIndex = startIndex;
85        fVertexCount = vertexCount;
86        fIndexCount = indexCount;
87        fInstanceCount = 0;
88        fVerticesPerInstance = 0;
89        fIndicesPerInstance = 0;
90        fMaxInstancesPerDraw = 0;
91    }
92
93
94    /** Variation of the above that may be used when the total number of instances may exceed
95        the number of instances supported by the index buffer. To be used with
96        nextInstances() to draw in max-sized batches.*/
97    void initInstanced(GrPrimitiveType primType,
98                        const GrVertexBuffer* vertexBuffer,
99                        const GrIndexBuffer* indexBuffer,
100                        int startVertex,
101                        int verticesPerInstance,
102                        int indicesPerInstance,
103                        int instanceCount,
104                        int maxInstancesPerDraw) {
105        SkASSERT(vertexBuffer);
106        SkASSERT(indexBuffer);
107        SkASSERT(instanceCount);
108        SkASSERT(verticesPerInstance);
109        SkASSERT(indicesPerInstance);
110        SkASSERT(startVertex >= 0);
111        fPrimitiveType = primType;
112        fVertexBuffer.reset(vertexBuffer);
113        fIndexBuffer.reset(indexBuffer);
114        fStartVertex = startVertex;
115        fStartIndex = 0;
116        fVerticesPerInstance = verticesPerInstance;
117        fIndicesPerInstance = indicesPerInstance;
118        fInstanceCount = instanceCount;
119        fVertexCount = instanceCount * fVerticesPerInstance;
120        fIndexCount = instanceCount * fIndicesPerInstance;
121        fMaxInstancesPerDraw = maxInstancesPerDraw;
122    }
123
124
125    /** These return 0 if initInstanced was not used to initialize the GrVertices. */
126    int verticesPerInstance() const { return fVerticesPerInstance; }
127    int indicesPerInstance() const { return fIndicesPerInstance; }
128    int instanceCount() const { return fInstanceCount; }
129
130    bool isInstanced() const { return fInstanceCount > 0; }
131
132    class Iterator {
133    public:
134        const GrNonInstancedVertices* init(const GrVertices& vertices) {
135            fVertices = &vertices;
136            if (vertices.fInstanceCount <= vertices.fMaxInstancesPerDraw) {
137                fInstancesRemaining = 0;
138                // Note, this also covers the non-instanced case!
139                return &vertices;
140            }
141            SkASSERT(vertices.isInstanced());
142            fInstanceBatch.fIndexBuffer.reset(vertices.fIndexBuffer.get());
143            fInstanceBatch.fVertexBuffer.reset(vertices.fVertexBuffer.get());
144            fInstanceBatch.fIndexCount = vertices.fMaxInstancesPerDraw *
145                                         vertices.fIndicesPerInstance;
146            fInstanceBatch.fVertexCount = vertices.fMaxInstancesPerDraw *
147                                          vertices.fVerticesPerInstance;
148            fInstanceBatch.fPrimitiveType = vertices.fPrimitiveType;
149            fInstanceBatch.fStartIndex = vertices.fStartIndex;
150            fInstanceBatch.fStartVertex = vertices.fStartVertex;
151            fInstancesRemaining = vertices.fInstanceCount - vertices.fMaxInstancesPerDraw;
152            return &fInstanceBatch;
153        }
154
155        const GrNonInstancedVertices* next() {
156            if (!fInstancesRemaining) {
157                return nullptr;
158            }
159            fInstanceBatch.fStartVertex += fInstanceBatch.fVertexCount;
160            int instances = SkTMin(fInstancesRemaining, fVertices->fMaxInstancesPerDraw);
161            fInstanceBatch.fIndexCount = instances * fVertices->fIndicesPerInstance;
162            fInstanceBatch.fVertexCount = instances * fVertices->fVerticesPerInstance;
163            fInstancesRemaining -= instances;
164            return &fInstanceBatch;
165        }
166    private:
167        GrNonInstancedVertices fInstanceBatch;
168        const GrVertices* fVertices;
169        int fInstancesRemaining;
170    };
171
172private:
173    int                     fInstanceCount;
174    int                     fVerticesPerInstance;
175    int                     fIndicesPerInstance;
176    int                     fMaxInstancesPerDraw;
177};
178
179#endif
180