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 "GrCpuBuffer.h" 10 #include "GrGLBuffer.h" 11 #include "GrGLGpu.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 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 } 78 SK_ABORT("Unknown vertex attrib type"); 79 return {false, 0, 0}; 80 }; 81 82 void GrGLAttribArrayState::set(GrGLGpu* gpu, 83 int index, 84 const GrBuffer* vertexBuffer, 85 GrVertexAttribType cpuType, 86 GrSLType gpuType, 87 GrGLsizei stride, 88 size_t offsetInBytes, 89 int divisor) { 90 SkASSERT(index >= 0 && index < fAttribArrayStates.count()); 91 SkASSERT(0 == divisor || gpu->caps()->instanceAttribSupport()); 92 AttribArrayState* array = &fAttribArrayStates[index]; 93 const char* offsetAsPtr; 94 bool bufferChanged = false; 95 if (vertexBuffer->isCpuBuffer()) { 96 if (!array->fUsingCpuBuffer) { 97 bufferChanged = true; 98 array->fUsingCpuBuffer = true; 99 } 100 offsetAsPtr = static_cast<const GrCpuBuffer*>(vertexBuffer)->data() + offsetInBytes; 101 } else { 102 auto gpuBuffer = static_cast<const GrGpuBuffer*>(vertexBuffer); 103 if (array->fUsingCpuBuffer || array->fVertexBufferUniqueID != gpuBuffer->uniqueID()) { 104 bufferChanged = true; 105 array->fVertexBufferUniqueID = gpuBuffer->uniqueID(); 106 } 107 offsetAsPtr = reinterpret_cast<const char*>(offsetInBytes); 108 } 109 if (bufferChanged || 110 array->fCPUType != cpuType || 111 array->fGPUType != gpuType || 112 array->fStride != stride || 113 array->fOffset != offsetAsPtr) { 114 // We always have to call this if we're going to change the array pointer. 'array' is 115 // tracking the last buffer used to setup attrib pointers, not the last buffer bound. 116 // GrGLGpu will avoid redundant binds. 117 gpu->bindBuffer(GrGpuBufferType::kVertex, vertexBuffer); 118 const AttribLayout& layout = attrib_layout(cpuType); 119 if (GrSLTypeIsFloatType(gpuType)) { 120 GR_GL_CALL(gpu->glInterface(), VertexAttribPointer(index, 121 layout.fCount, 122 layout.fType, 123 layout.fNormalized, 124 stride, 125 offsetAsPtr)); 126 } else { 127 SkASSERT(gpu->caps()->shaderCaps()->integerSupport()); 128 SkASSERT(!layout.fNormalized); 129 GR_GL_CALL(gpu->glInterface(), VertexAttribIPointer(index, 130 layout.fCount, 131 layout.fType, 132 stride, 133 offsetAsPtr)); 134 } 135 array->fCPUType = cpuType; 136 array->fGPUType = gpuType; 137 array->fStride = stride; 138 array->fOffset = offsetAsPtr; 139 } 140 if (gpu->caps()->instanceAttribSupport() && array->fDivisor != divisor) { 141 SkASSERT(0 == divisor || 1 == divisor); // not necessarily a requirement but what we expect. 142 GR_GL_CALL(gpu->glInterface(), VertexAttribDivisor(index, divisor)); 143 array->fDivisor = divisor; 144 } 145 } 146 147 void GrGLAttribArrayState::enableVertexArrays(const GrGLGpu* gpu, int enabledCount, 148 GrPrimitiveRestart enablePrimitiveRestart) { 149 SkASSERT(enabledCount <= fAttribArrayStates.count()); 150 151 if (!fEnableStateIsValid || enabledCount != fNumEnabledArrays) { 152 int firstIdxToEnable = fEnableStateIsValid ? fNumEnabledArrays : 0; 153 for (int i = firstIdxToEnable; i < enabledCount; ++i) { 154 GR_GL_CALL(gpu->glInterface(), EnableVertexAttribArray(i)); 155 } 156 157 int endIdxToDisable = fEnableStateIsValid ? fNumEnabledArrays : fAttribArrayStates.count(); 158 for (int i = enabledCount; i < endIdxToDisable; ++i) { 159 GR_GL_CALL(gpu->glInterface(), DisableVertexAttribArray(i)); 160 } 161 162 fNumEnabledArrays = enabledCount; 163 } 164 165 SkASSERT(GrPrimitiveRestart::kNo == enablePrimitiveRestart || 166 gpu->caps()->usePrimitiveRestart()); 167 168 if (gpu->caps()->usePrimitiveRestart() && 169 (!fEnableStateIsValid || enablePrimitiveRestart != fPrimitiveRestartEnabled)) { 170 if (GrPrimitiveRestart::kYes == enablePrimitiveRestart) { 171 GR_GL_CALL(gpu->glInterface(), Enable(GR_GL_PRIMITIVE_RESTART_FIXED_INDEX)); 172 } else { 173 GR_GL_CALL(gpu->glInterface(), Disable(GR_GL_PRIMITIVE_RESTART_FIXED_INDEX)); 174 } 175 176 fPrimitiveRestartEnabled = enablePrimitiveRestart; 177 } 178 179 fEnableStateIsValid = true; 180 } 181 182 /////////////////////////////////////////////////////////////////////////////////////////////////// 183 184 GrGLVertexArray::GrGLVertexArray(GrGLint id, int attribCount) 185 : fID(id) 186 , fAttribArrays(attribCount) 187 , fIndexBufferUniqueID(SK_InvalidUniqueID) { 188 } 189 190 GrGLAttribArrayState* GrGLVertexArray::bind(GrGLGpu* gpu) { 191 if (0 == fID) { 192 return nullptr; 193 } 194 gpu->bindVertexArray(fID); 195 return &fAttribArrays; 196 } 197 198 GrGLAttribArrayState* GrGLVertexArray::bindWithIndexBuffer(GrGLGpu* gpu, const GrBuffer* ibuff) { 199 GrGLAttribArrayState* state = this->bind(gpu); 200 if (!state) { 201 return nullptr; 202 } 203 if (ibuff->isCpuBuffer()) { 204 GR_GL_CALL(gpu->glInterface(), BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, 0)); 205 } else { 206 const GrGLBuffer* glBuffer = static_cast<const GrGLBuffer*>(ibuff); 207 if (fIndexBufferUniqueID != glBuffer->uniqueID()) { 208 const GrGLBuffer* glBuffer = static_cast<const GrGLBuffer*>(ibuff); 209 GR_GL_CALL(gpu->glInterface(), 210 BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, glBuffer->bufferID())); 211 fIndexBufferUniqueID = glBuffer->uniqueID(); 212 } 213 } 214 return state; 215 } 216 217 void GrGLVertexArray::invalidateCachedState() { 218 fAttribArrays.invalidate(); 219 fIndexBufferUniqueID.makeInvalid(); 220 } 221