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