WebGLContextVertices.cpp (8652B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "GLContext.h" 7 #include "WebGLBuffer.h" 8 #include "WebGLContext.h" 9 #include "WebGLFramebuffer.h" 10 #include "WebGLProgram.h" 11 #include "WebGLRenderbuffer.h" 12 #include "WebGLShader.h" 13 #include "WebGLTexture.h" 14 #include "WebGLTypes.h" 15 #include "WebGLVertexArray.h" 16 #include "mozilla/ResultVariant.h" 17 18 namespace mozilla { 19 20 static bool ValidateAttribIndex(WebGLContext& webgl, GLuint index) { 21 bool valid = (index < webgl.MaxVertexAttribs()); 22 23 if (!valid) { 24 if (index == GLuint(-1)) { 25 webgl.ErrorInvalidValue( 26 "-1 is not a valid `index`. This value" 27 " probably comes from a getAttribLocation()" 28 " call, where this return value -1 means" 29 " that the passed name didn't correspond to" 30 " an active attribute in the specified" 31 " program."); 32 } else { 33 webgl.ErrorInvalidValue( 34 "`index` must be less than" 35 " MAX_VERTEX_ATTRIBS."); 36 } 37 } 38 39 return valid; 40 } 41 42 //////////////////////////////////////// 43 44 void WebGLContext::VertexAttrib4T(GLuint index, const webgl::TypedQuad& src) { 45 const FuncScope funcScope(*this, "vertexAttrib[1234]u?[fi]v?"); 46 if (IsContextLost()) return; 47 48 if (!ValidateAttribIndex(*this, index)) return; 49 50 //// 51 52 if (index || !gl->IsCompatibilityProfile()) { 53 switch (src.type) { 54 case webgl::AttribBaseType::Boolean: 55 case webgl::AttribBaseType::Float: 56 gl->fVertexAttrib4fv(index, 57 reinterpret_cast<const float*>(src.data.data())); 58 break; 59 case webgl::AttribBaseType::Int: 60 gl->fVertexAttribI4iv( 61 index, reinterpret_cast<const int32_t*>(src.data.data())); 62 break; 63 case webgl::AttribBaseType::Uint: 64 gl->fVertexAttribI4uiv( 65 index, reinterpret_cast<const uint32_t*>(src.data.data())); 66 break; 67 } 68 } 69 70 //// 71 72 mGenericVertexAttribTypes[index] = src.type; 73 mGenericVertexAttribTypeInvalidator.InvalidateCaches(); 74 75 if (!index) { 76 memcpy(mGenericVertexAttrib0Data, src.data.data(), 77 sizeof(mGenericVertexAttrib0Data)); 78 } 79 } 80 81 //////////////////////////////////////// 82 83 void WebGLContext::EnableVertexAttribArray(GLuint index) { 84 const FuncScope funcScope(*this, "enableVertexAttribArray"); 85 if (IsContextLost()) return; 86 87 if (!ValidateAttribIndex(*this, index)) return; 88 89 gl->fEnableVertexAttribArray(index); 90 91 MOZ_ASSERT(mBoundVertexArray); 92 mBoundVertexArray->SetAttribIsArray(index, true); 93 } 94 95 void WebGLContext::DisableVertexAttribArray(GLuint index) { 96 const FuncScope funcScope(*this, "disableVertexAttribArray"); 97 if (IsContextLost()) return; 98 99 if (!ValidateAttribIndex(*this, index)) return; 100 101 if (index || !gl->IsCompatibilityProfile()) { 102 gl->fDisableVertexAttribArray(index); 103 } 104 105 MOZ_ASSERT(mBoundVertexArray); 106 mBoundVertexArray->SetAttribIsArray(index, false); 107 } 108 109 Maybe<double> WebGLContext::GetVertexAttrib(GLuint index, GLenum pname) { 110 const FuncScope funcScope(*this, "getVertexAttrib"); 111 if (IsContextLost()) return Nothing(); 112 113 if (!ValidateAttribIndex(*this, index)) return Nothing(); 114 115 MOZ_ASSERT(mBoundVertexArray); 116 auto ret = mBoundVertexArray->GetVertexAttrib(index, pname); 117 118 switch (pname) { 119 case LOCAL_GL_VERTEX_ATTRIB_ARRAY_INTEGER: 120 if (!IsWebGL2()) { 121 ret = Nothing(); 122 } 123 break; 124 125 case LOCAL_GL_VERTEX_ATTRIB_ARRAY_DIVISOR: 126 if (!IsWebGL2() && 127 !IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays)) { 128 ret = Nothing(); 129 } 130 break; 131 } 132 133 if (!ret) { 134 ErrorInvalidEnumInfo("pname", pname); 135 } 136 return ret; 137 } 138 139 //////////////////////////////////////// 140 141 Result<webgl::VertAttribPointerCalculated, webgl::ErrorInfo> 142 CheckVertexAttribPointer(const bool isWebgl2, 143 const webgl::VertAttribPointerDesc& desc) { 144 if (desc.channels < 1 || desc.channels > 4) { 145 return Err(webgl::ErrorInfo{LOCAL_GL_INVALID_VALUE, 146 "Channel count `size` must be within [1,4]."}); 147 } 148 149 //// 150 151 webgl::VertAttribPointerCalculated calc; 152 153 bool isTypeValid = true; 154 bool isPackedType = false; 155 uint8_t bytesPerType = 0; 156 switch (desc.type) { 157 // WebGL 1: 158 case LOCAL_GL_BYTE: 159 bytesPerType = 1; 160 calc.baseType = webgl::AttribBaseType::Int; 161 break; 162 case LOCAL_GL_UNSIGNED_BYTE: 163 bytesPerType = 1; 164 calc.baseType = webgl::AttribBaseType::Uint; 165 break; 166 167 case LOCAL_GL_SHORT: 168 bytesPerType = 2; 169 calc.baseType = webgl::AttribBaseType::Int; 170 break; 171 case LOCAL_GL_UNSIGNED_SHORT: 172 bytesPerType = 2; 173 calc.baseType = webgl::AttribBaseType::Uint; 174 break; 175 176 case LOCAL_GL_FLOAT: 177 bytesPerType = 4; 178 calc.baseType = webgl::AttribBaseType::Float; 179 break; 180 181 // WebGL 2: 182 case LOCAL_GL_INT: 183 isTypeValid = isWebgl2; 184 bytesPerType = 4; 185 calc.baseType = webgl::AttribBaseType::Int; 186 break; 187 case LOCAL_GL_UNSIGNED_INT: 188 isTypeValid = isWebgl2; 189 bytesPerType = 4; 190 calc.baseType = webgl::AttribBaseType::Uint; 191 break; 192 193 case LOCAL_GL_HALF_FLOAT: 194 isTypeValid = isWebgl2; 195 bytesPerType = 2; 196 calc.baseType = webgl::AttribBaseType::Float; 197 break; 198 199 case LOCAL_GL_INT_2_10_10_10_REV: 200 case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV: 201 if (desc.channels != 4) { 202 return Err(webgl::ErrorInfo{LOCAL_GL_INVALID_OPERATION, 203 "Size must be 4 for this type."}); 204 } 205 isTypeValid = isWebgl2; 206 bytesPerType = 4; 207 calc.baseType = 208 webgl::AttribBaseType::Float; // Invalid for intFunc:true. 209 isPackedType = true; 210 break; 211 212 default: 213 isTypeValid = false; 214 break; 215 } 216 if (desc.intFunc) { 217 isTypeValid = (calc.baseType != webgl::AttribBaseType::Float); 218 } else { 219 calc.baseType = webgl::AttribBaseType::Float; 220 } 221 if (!isTypeValid) { 222 const auto info = 223 nsPrintfCString("Bad `type`: %s", EnumString(desc.type).c_str()); 224 return Err(webgl::ErrorInfo{LOCAL_GL_INVALID_ENUM, info.BeginReading()}); 225 } 226 227 //// 228 229 calc.byteSize = bytesPerType; 230 if (!isPackedType) { 231 calc.byteSize *= desc.channels; 232 } 233 234 calc.byteStride = 235 desc.byteStrideOrZero ? desc.byteStrideOrZero : calc.byteSize; 236 237 // `alignment` should always be a power of two. 238 MOZ_ASSERT(IsPowerOfTwo(bytesPerType)); 239 const auto typeAlignmentMask = bytesPerType - 1; 240 241 if (calc.byteStride & typeAlignmentMask || 242 desc.byteOffset & typeAlignmentMask) { 243 return Err( 244 webgl::ErrorInfo{LOCAL_GL_INVALID_OPERATION, 245 "`stride` and `byteOffset` must satisfy the alignment" 246 " requirement of `type`."}); 247 } 248 249 return calc; 250 } 251 252 void DoVertexAttribPointer(gl::GLContext& gl, const uint32_t index, 253 const webgl::VertAttribPointerDesc& desc) { 254 if (desc.intFunc) { 255 gl.fVertexAttribIPointer(index, desc.channels, desc.type, 256 desc.byteStrideOrZero, 257 reinterpret_cast<const void*>(desc.byteOffset)); 258 } else { 259 gl.fVertexAttribPointer(index, desc.channels, desc.type, desc.normalized, 260 desc.byteStrideOrZero, 261 reinterpret_cast<const void*>(desc.byteOffset)); 262 } 263 } 264 265 void WebGLContext::VertexAttribPointer( 266 const uint32_t index, const webgl::VertAttribPointerDesc& desc) { 267 if (IsContextLost()) return; 268 if (!ValidateAttribIndex(*this, index)) return; 269 270 const auto res = CheckVertexAttribPointer(IsWebGL2(), desc); 271 if (res.isErr()) { 272 const auto& err = res.inspectErr(); 273 GenerateError(err.type, "%s", err.info.c_str()); 274 return; 275 } 276 const auto& calc = res.inspect(); 277 278 //// 279 280 const auto& buffer = mBoundArrayBuffer; 281 282 mBoundVertexArray->AttribPointer(index, buffer, desc, calc); 283 284 const ScopedLazyBind lazyBind(gl, LOCAL_GL_ARRAY_BUFFER, buffer); 285 DoVertexAttribPointer(*gl, index, desc); 286 } 287 288 //////////////////////////////////////// 289 290 void WebGLContext::VertexAttribDivisor(GLuint index, GLuint divisor) { 291 const FuncScope funcScope(*this, "vertexAttribDivisor"); 292 if (IsContextLost()) return; 293 294 if (!ValidateAttribIndex(*this, index)) return; 295 296 MOZ_ASSERT(mBoundVertexArray); 297 mBoundVertexArray->AttribDivisor(index, divisor); 298 gl->fVertexAttribDivisor(index, divisor); 299 } 300 301 } // namespace mozilla