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