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 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_HALF_FLOAT}; 32 case kHalf2_GrVertexAttribType: 33 return {false, 2, GR_GL_HALF_FLOAT}; 34 case kHalf3_GrVertexAttribType: 35 return {false, 3, GR_GL_HALF_FLOAT}; 36 case kHalf4_GrVertexAttribType: 37 return {false, 4, GR_GL_HALF_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 kByte_GrVertexAttribType: 45 return {false, 1, GR_GL_BYTE}; 46 case kByte2_GrVertexAttribType: 47 return {false, 2, GR_GL_BYTE}; 48 case kByte3_GrVertexAttribType: 49 return {false, 3, GR_GL_BYTE}; 50 case kByte4_GrVertexAttribType: 51 return {false, 4, GR_GL_BYTE}; 52 case kUByte_GrVertexAttribType: 53 return {false, 1, GR_GL_UNSIGNED_BYTE}; 54 case kUByte2_GrVertexAttribType: 55 return {false, 2, GR_GL_UNSIGNED_BYTE}; 56 case kUByte3_GrVertexAttribType: 57 return {false, 3, GR_GL_UNSIGNED_BYTE}; 58 case kUByte4_GrVertexAttribType: 59 return {false, 4, GR_GL_UNSIGNED_BYTE}; 60 case kUByte_norm_GrVertexAttribType: 61 return {true, 1, GR_GL_UNSIGNED_BYTE}; 62 case kUByte4_norm_GrVertexAttribType: 63 return {true, 4, GR_GL_UNSIGNED_BYTE}; 64 case kShort2_GrVertexAttribType: 65 return {false, 2, GR_GL_SHORT}; 66 case kShort4_GrVertexAttribType: 67 return {false, 4, GR_GL_SHORT}; 68 case kUShort2_GrVertexAttribType: 69 return {false, 2, GR_GL_UNSIGNED_SHORT}; 70 case kUShort2_norm_GrVertexAttribType: 71 return {true, 2, GR_GL_UNSIGNED_SHORT}; 72 case kInt_GrVertexAttribType: 73 return {false, 1, GR_GL_INT}; 74 case kUint_GrVertexAttribType: 75 return {false, 1, GR_GL_UNSIGNED_INT}; 76 } 77 SK_ABORT("Unknown vertex attrib type"); 78 return {false, 0, 0}; 79 }; 80 81 void GrGLAttribArrayState::set(GrGLGpu* gpu, 82 int index, 83 const GrBuffer* vertexBuffer, 84 GrVertexAttribType cpuType, 85 GrSLType gpuType, 86 GrGLsizei stride, 87 size_t offsetInBytes, 88 int divisor) { 89 SkASSERT(index >= 0 && index < fAttribArrayStates.count()); 90 SkASSERT(0 == divisor || gpu->caps()->instanceAttribSupport()); 91 AttribArrayState* array = &fAttribArrayStates[index]; 92 if (array->fVertexBufferUniqueID != vertexBuffer->uniqueID() || 93 array->fCPUType != cpuType || 94 array->fGPUType != gpuType || 95 array->fStride != stride || 96 array->fOffset != offsetInBytes) { 97 gpu->bindBuffer(kVertex_GrBufferType, vertexBuffer); 98 const AttribLayout& layout = attrib_layout(cpuType); 99 const GrGLvoid* offsetAsPtr = reinterpret_cast<const GrGLvoid*>(offsetInBytes); 100 if (GrSLTypeIsFloatType(gpuType)) { 101 GR_GL_CALL(gpu->glInterface(), VertexAttribPointer(index, 102 layout.fCount, 103 layout.fType, 104 layout.fNormalized, 105 stride, 106 offsetAsPtr)); 107 } else { 108 SkASSERT(gpu->caps()->shaderCaps()->integerSupport()); 109 SkASSERT(!layout.fNormalized); 110 GR_GL_CALL(gpu->glInterface(), VertexAttribIPointer(index, 111 layout.fCount, 112 layout.fType, 113 stride, 114 offsetAsPtr)); 115 } 116 array->fVertexBufferUniqueID = vertexBuffer->uniqueID(); 117 array->fCPUType = cpuType; 118 array->fGPUType = gpuType; 119 array->fStride = stride; 120 array->fOffset = offsetInBytes; 121 } 122 if (gpu->caps()->instanceAttribSupport() && array->fDivisor != divisor) { 123 SkASSERT(0 == divisor || 1 == divisor); // not necessarily a requirement but what we expect. 124 GR_GL_CALL(gpu->glInterface(), VertexAttribDivisor(index, divisor)); 125 array->fDivisor = divisor; 126 } 127 } 128 129 void GrGLAttribArrayState::enableVertexArrays(const GrGLGpu* gpu, int enabledCount, 130 GrPrimitiveRestart enablePrimitiveRestart) { 131 SkASSERT(enabledCount <= fAttribArrayStates.count()); 132 133 if (!fEnableStateIsValid || enabledCount != fNumEnabledArrays) { 134 int firstIdxToEnable = fEnableStateIsValid ? fNumEnabledArrays : 0; 135 for (int i = firstIdxToEnable; i < enabledCount; ++i) { 136 GR_GL_CALL(gpu->glInterface(), EnableVertexAttribArray(i)); 137 } 138 139 int endIdxToDisable = fEnableStateIsValid ? fNumEnabledArrays : fAttribArrayStates.count(); 140 for (int i = enabledCount; i < endIdxToDisable; ++i) { 141 GR_GL_CALL(gpu->glInterface(), DisableVertexAttribArray(i)); 142 } 143 144 fNumEnabledArrays = enabledCount; 145 } 146 147 SkASSERT(GrPrimitiveRestart::kNo == enablePrimitiveRestart || 148 gpu->caps()->usePrimitiveRestart()); 149 150 if (gpu->caps()->usePrimitiveRestart() && 151 (!fEnableStateIsValid || enablePrimitiveRestart != fPrimitiveRestartEnabled)) { 152 if (GrPrimitiveRestart::kYes == enablePrimitiveRestart) { 153 GR_GL_CALL(gpu->glInterface(), Enable(GR_GL_PRIMITIVE_RESTART_FIXED_INDEX)); 154 } else { 155 GR_GL_CALL(gpu->glInterface(), Disable(GR_GL_PRIMITIVE_RESTART_FIXED_INDEX)); 156 } 157 158 fPrimitiveRestartEnabled = enablePrimitiveRestart; 159 } 160 161 fEnableStateIsValid = true; 162 } 163 164 /////////////////////////////////////////////////////////////////////////////////////////////////// 165 166 GrGLVertexArray::GrGLVertexArray(GrGLint id, int attribCount) 167 : fID(id) 168 , fAttribArrays(attribCount) 169 , fIndexBufferUniqueID(SK_InvalidUniqueID) { 170 } 171 172 GrGLAttribArrayState* GrGLVertexArray::bind(GrGLGpu* gpu) { 173 if (0 == fID) { 174 return nullptr; 175 } 176 gpu->bindVertexArray(fID); 177 return &fAttribArrays; 178 } 179 180 GrGLAttribArrayState* GrGLVertexArray::bindWithIndexBuffer(GrGLGpu* gpu, const GrBuffer* ibuff) { 181 GrGLAttribArrayState* state = this->bind(gpu); 182 if (state && fIndexBufferUniqueID != ibuff->uniqueID()) { 183 if (ibuff->isCPUBacked()) { 184 GR_GL_CALL(gpu->glInterface(), BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, 0)); 185 } else { 186 const GrGLBuffer* glBuffer = static_cast<const GrGLBuffer*>(ibuff); 187 GR_GL_CALL(gpu->glInterface(), BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, 188 glBuffer->bufferID())); 189 } 190 fIndexBufferUniqueID = ibuff->uniqueID(); 191 } 192 return state; 193 } 194 195 void GrGLVertexArray::invalidateCachedState() { 196 fAttribArrays.invalidate(); 197 fIndexBufferUniqueID.makeInvalid(); 198 } 199