1 /*
2  * Copyright 2013 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 #include "GrGLVertexArray.h"
9 #include "GrGLBuffer.h"
10 #include "GrGLGpu.h"
11 
12 struct AttribLayout {
13     bool        fNormalized;  // Only used by floating point types.
14     uint8_t     fCount;
15     uint16_t    fType;
16 };
17 
18 GR_STATIC_ASSERT(4 == sizeof(AttribLayout));
19 
attrib_layout(GrVertexAttribType type)20 static AttribLayout attrib_layout(GrVertexAttribType type) {
21     switch (type) {
22         case kFloat_GrVertexAttribType:
23             return {false, 1, GR_GL_FLOAT};
24         case kFloat2_GrVertexAttribType:
25             return {false, 2, GR_GL_FLOAT};
26         case kFloat3_GrVertexAttribType:
27             return {false, 3, GR_GL_FLOAT};
28         case kFloat4_GrVertexAttribType:
29             return {false, 4, GR_GL_FLOAT};
30         case kHalf_GrVertexAttribType:
31             return {false, 1, GR_GL_FLOAT};
32         case kHalf2_GrVertexAttribType:
33             return {false, 2, GR_GL_FLOAT};
34         case kHalf3_GrVertexAttribType:
35             return {false, 3, GR_GL_FLOAT};
36         case kHalf4_GrVertexAttribType:
37             return {false, 4, GR_GL_FLOAT};
38         case kInt2_GrVertexAttribType:
39             return {false, 2, GR_GL_INT};
40         case kInt3_GrVertexAttribType:
41             return {false, 3, GR_GL_INT};
42         case kInt4_GrVertexAttribType:
43             return {false, 4, GR_GL_INT};
44         case kUByte_norm_GrVertexAttribType:
45             return {true, 1, GR_GL_UNSIGNED_BYTE};
46         case kUByte4_norm_GrVertexAttribType:
47             return {true, 4, GR_GL_UNSIGNED_BYTE};
48         case kShort2_GrVertexAttribType:
49             return {false, 2, GR_GL_SHORT};
50         case kUShort2_GrVertexAttribType:
51             return {false, 2, GR_GL_UNSIGNED_SHORT};
52         case kUShort2_norm_GrVertexAttribType:
53             return {true, 2, GR_GL_UNSIGNED_SHORT};
54         case kInt_GrVertexAttribType:
55             return {false, 1, GR_GL_INT};
56         case kUint_GrVertexAttribType:
57             return {false, 1, GR_GL_UNSIGNED_INT};
58     }
59     SK_ABORT("Unknown vertex attrib type");
60     return {false, 0, 0};
61 };
62 
GrVertexAttribTypeIsIntType(const GrShaderCaps * shaderCaps,GrVertexAttribType type)63 static bool GrVertexAttribTypeIsIntType(const GrShaderCaps* shaderCaps,
64                                         GrVertexAttribType type) {
65     switch (type) {
66         case kFloat_GrVertexAttribType:
67             return false;
68         case kFloat2_GrVertexAttribType:
69             return false;
70         case kFloat3_GrVertexAttribType:
71             return false;
72         case kFloat4_GrVertexAttribType:
73             return false;
74         case kHalf_GrVertexAttribType:
75             return false;
76         case kHalf2_GrVertexAttribType:
77             return false;
78         case kHalf3_GrVertexAttribType:
79             return false;
80         case kHalf4_GrVertexAttribType:
81             return false;
82         case kInt2_GrVertexAttribType:
83             return true;
84         case kInt3_GrVertexAttribType:
85             return true;
86         case kInt4_GrVertexAttribType:
87             return true;
88         case kUByte_norm_GrVertexAttribType:
89             return false;
90         case kUByte4_norm_GrVertexAttribType:
91             return false;
92         case kShort2_GrVertexAttribType:
93             return true;
94         case kUShort2_GrVertexAttribType:
95             return shaderCaps->integerSupport(); // FIXME: caller should handle this.
96         case kUShort2_norm_GrVertexAttribType:
97             return false;
98         case kInt_GrVertexAttribType:
99             return true;
100         case kUint_GrVertexAttribType:
101             return true;
102     }
103     SK_ABORT("Unexpected attribute type");
104     return false;
105 }
106 
set(GrGLGpu * gpu,int index,const GrBuffer * vertexBuffer,GrVertexAttribType type,GrGLsizei stride,size_t offsetInBytes,int divisor)107 void GrGLAttribArrayState::set(GrGLGpu* gpu,
108                                int index,
109                                const GrBuffer* vertexBuffer,
110                                GrVertexAttribType type,
111                                GrGLsizei stride,
112                                size_t offsetInBytes,
113                                int divisor) {
114     SkASSERT(index >= 0 && index < fAttribArrayStates.count());
115     SkASSERT(0 == divisor || gpu->caps()->instanceAttribSupport());
116     AttribArrayState* array = &fAttribArrayStates[index];
117     if (array->fVertexBufferUniqueID != vertexBuffer->uniqueID() ||
118         array->fType != type ||
119         array->fStride != stride ||
120         array->fOffset != offsetInBytes) {
121         gpu->bindBuffer(kVertex_GrBufferType, vertexBuffer);
122         const AttribLayout& layout = attrib_layout(type);
123         const GrGLvoid* offsetAsPtr = reinterpret_cast<const GrGLvoid*>(offsetInBytes);
124         if (!GrVertexAttribTypeIsIntType(gpu->caps()->shaderCaps(), type)) {
125             GR_GL_CALL(gpu->glInterface(), VertexAttribPointer(index,
126                                                                layout.fCount,
127                                                                layout.fType,
128                                                                layout.fNormalized,
129                                                                stride,
130                                                                offsetAsPtr));
131         } else {
132             SkASSERT(gpu->caps()->shaderCaps()->integerSupport());
133             SkASSERT(!layout.fNormalized);
134             GR_GL_CALL(gpu->glInterface(), VertexAttribIPointer(index,
135                                                                 layout.fCount,
136                                                                 layout.fType,
137                                                                 stride,
138                                                                 offsetAsPtr));
139         }
140         array->fVertexBufferUniqueID = vertexBuffer->uniqueID();
141         array->fType = type;
142         array->fStride = stride;
143         array->fOffset = offsetInBytes;
144     }
145     if (gpu->caps()->instanceAttribSupport() && array->fDivisor != divisor) {
146         SkASSERT(0 == divisor || 1 == divisor); // not necessarily a requirement but what we expect.
147         GR_GL_CALL(gpu->glInterface(), VertexAttribDivisor(index, divisor));
148         array->fDivisor = divisor;
149     }
150 }
151 
enableVertexArrays(const GrGLGpu * gpu,int enabledCount,EnablePrimitiveRestart enablePrimitiveRestart)152 void GrGLAttribArrayState::enableVertexArrays(const GrGLGpu* gpu, int enabledCount,
153                                               EnablePrimitiveRestart enablePrimitiveRestart) {
154     SkASSERT(enabledCount <= fAttribArrayStates.count());
155 
156     if (!fEnableStateIsValid || enabledCount != fNumEnabledArrays) {
157         int firstIdxToEnable = fEnableStateIsValid ? fNumEnabledArrays : 0;
158         for (int i = firstIdxToEnable; i < enabledCount; ++i) {
159             GR_GL_CALL(gpu->glInterface(), EnableVertexAttribArray(i));
160         }
161 
162         int endIdxToDisable = fEnableStateIsValid ? fNumEnabledArrays : fAttribArrayStates.count();
163         for (int i = enabledCount; i < endIdxToDisable; ++i) {
164             GR_GL_CALL(gpu->glInterface(), DisableVertexAttribArray(i));
165         }
166 
167         fNumEnabledArrays = enabledCount;
168     }
169 
170     SkASSERT(EnablePrimitiveRestart::kNo == enablePrimitiveRestart ||
171              gpu->caps()->usePrimitiveRestart());
172 
173     if (gpu->caps()->usePrimitiveRestart() &&
174         (!fEnableStateIsValid || enablePrimitiveRestart != fPrimitiveRestartEnabled)) {
175         if (EnablePrimitiveRestart::kYes == enablePrimitiveRestart) {
176             GR_GL_CALL(gpu->glInterface(), Enable(GR_GL_PRIMITIVE_RESTART_FIXED_INDEX));
177         } else {
178             GR_GL_CALL(gpu->glInterface(), Disable(GR_GL_PRIMITIVE_RESTART_FIXED_INDEX));
179         }
180 
181         fPrimitiveRestartEnabled = enablePrimitiveRestart;
182     }
183 
184     fEnableStateIsValid = true;
185 }
186 
187 ///////////////////////////////////////////////////////////////////////////////////////////////////
188 
GrGLVertexArray(GrGLint id,int attribCount)189 GrGLVertexArray::GrGLVertexArray(GrGLint id, int attribCount)
190     : fID(id)
191     , fAttribArrays(attribCount)
192     , fIndexBufferUniqueID(SK_InvalidUniqueID) {
193 }
194 
bind(GrGLGpu * gpu)195 GrGLAttribArrayState* GrGLVertexArray::bind(GrGLGpu* gpu) {
196     if (0 == fID) {
197         return nullptr;
198     }
199     gpu->bindVertexArray(fID);
200     return &fAttribArrays;
201 }
202 
bindWithIndexBuffer(GrGLGpu * gpu,const GrBuffer * ibuff)203 GrGLAttribArrayState* GrGLVertexArray::bindWithIndexBuffer(GrGLGpu* gpu, const GrBuffer* ibuff) {
204     GrGLAttribArrayState* state = this->bind(gpu);
205     if (state && fIndexBufferUniqueID != ibuff->uniqueID()) {
206         if (ibuff->isCPUBacked()) {
207             GR_GL_CALL(gpu->glInterface(), BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, 0));
208         } else {
209             const GrGLBuffer* glBuffer = static_cast<const GrGLBuffer*>(ibuff);
210             GR_GL_CALL(gpu->glInterface(), BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER,
211                                                       glBuffer->bufferID()));
212         }
213         fIndexBufferUniqueID = ibuff->uniqueID();
214     }
215     return state;
216 }
217 
invalidateCachedState()218 void GrGLVertexArray::invalidateCachedState() {
219     fAttribArrays.invalidate();
220     fIndexBufferUniqueID.makeInvalid();
221 }
222