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