WebGLContextValidate.cpp (21118B)
1 /* -*- Mode: C++; tab-width: 20; 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 <algorithm> 7 8 #include "CanvasUtils.h" 9 #include "GLContext.h" 10 #include "GLSLANG/ShaderLang.h" 11 #include "WebGLBuffer.h" 12 #include "WebGLContext.h" 13 #include "WebGLContextUtils.h" 14 #include "WebGLFormats.h" 15 #include "WebGLFramebuffer.h" 16 #include "WebGLProgram.h" 17 #include "WebGLRenderbuffer.h" 18 #include "WebGLSampler.h" 19 #include "WebGLShader.h" 20 #include "WebGLTexture.h" 21 #include "WebGLValidateStrings.h" 22 #include "WebGLVertexArray.h" 23 #include "gfxEnv.h" 24 #include "jsfriendapi.h" 25 #include "mozilla/Preferences.h" 26 #include "mozilla/StaticPrefs_webgl.h" 27 #include "nsPrintfCString.h" 28 29 //////////////////// 30 // Minimum value constants defined in GLES 2.0.25 $6.2 "State Tables": 31 const uint32_t kMinMaxVertexAttribs = 8; // Page 164 32 const uint32_t kMinMaxVertexUniformVectors = 128; // Page 164 33 const uint32_t kMinMaxFragmentUniformVectors = 16; // Page 164 34 const uint32_t kMinMaxVaryingVectors = 8; // Page 164 35 36 const uint32_t kMinMaxVertexTextureImageUnits = 0; // Page 164 37 const uint32_t kMinMaxFragmentTextureImageUnits = 8; // Page 164 38 const uint32_t kMinMaxCombinedTextureImageUnits = 8; // Page 164 39 40 const uint32_t kMinMaxDrawBuffers = 4; 41 42 // These few deviate from the spec: (The minimum values in the spec are 43 // ridiculously low) 44 const uint32_t kMinMaxTextureSize = 1024; // ES2 spec says `64` (p162) 45 const uint32_t kMinMaxCubeMapTextureSize = 512; // ES2 spec says `16` (p162) 46 const uint32_t kMinMaxRenderbufferSize = 1024; // ES2 spec says `1` (p164) 47 48 // Minimum value constants defined in GLES 3.0.4 $6.2 "State Tables": 49 const uint32_t kMinMax3DTextureSize = 256; 50 const uint32_t kMinMaxArrayTextureLayers = 256; 51 52 //////////////////// 53 // "Common" but usable values to avoid WebGL fingerprinting: 54 const uint32_t kCommonMaxTextureSize = 2048; 55 const uint32_t kCommonMaxCubeMapTextureSize = 2048; 56 const uint32_t kCommonMaxRenderbufferSize = 2048; 57 58 const uint32_t kCommonMaxVertexTextureImageUnits = 8; 59 const uint32_t kCommonMaxFragmentTextureImageUnits = 8; 60 const uint32_t kCommonMaxCombinedTextureImageUnits = 16; 61 62 const uint32_t kCommonMaxVertexAttribs = 16; 63 const uint32_t kCommonMaxVertexUniformVectors = 256; 64 const uint32_t kCommonMaxFragmentUniformVectors = 224; 65 const uint32_t kCommonMaxVaryingVectors = 8; 66 67 const uint32_t kCommonMaxViewportDims = 4096; 68 69 // The following ranges came from a 2013 Moto E and an old macbook. 70 const float kCommonAliasedPointSizeRangeMin = 1; 71 const float kCommonAliasedPointSizeRangeMax = 63; 72 const float kCommonAliasedLineWidthRangeMin = 1; 73 const float kCommonAliasedLineWidthRangeMax = 1; 74 75 template <class T> 76 static bool RestrictCap(T* const cap, const T restrictedVal) { 77 if (*cap < restrictedVal) { 78 return false; // already too low! 79 } 80 81 *cap = restrictedVal; 82 return true; 83 } 84 85 //////////////////// 86 87 namespace mozilla { 88 89 bool WebGLContext::ValidateBlendEquationEnum(GLenum mode, const char* info) { 90 switch (mode) { 91 case LOCAL_GL_FUNC_ADD: 92 case LOCAL_GL_FUNC_SUBTRACT: 93 case LOCAL_GL_FUNC_REVERSE_SUBTRACT: 94 return true; 95 96 case LOCAL_GL_MIN: 97 case LOCAL_GL_MAX: 98 if (IsWebGL2() || 99 IsExtensionEnabled(WebGLExtensionID::EXT_blend_minmax)) { 100 return true; 101 } 102 103 break; 104 105 default: 106 break; 107 } 108 109 ErrorInvalidEnumInfo(info, mode); 110 return false; 111 } 112 113 bool WebGLContext::ValidateBlendFuncEnumsCompatibility(GLenum sfactor, 114 GLenum dfactor, 115 const char* info) { 116 bool sfactorIsConstantColor = sfactor == LOCAL_GL_CONSTANT_COLOR || 117 sfactor == LOCAL_GL_ONE_MINUS_CONSTANT_COLOR; 118 bool sfactorIsConstantAlpha = sfactor == LOCAL_GL_CONSTANT_ALPHA || 119 sfactor == LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA; 120 bool dfactorIsConstantColor = dfactor == LOCAL_GL_CONSTANT_COLOR || 121 dfactor == LOCAL_GL_ONE_MINUS_CONSTANT_COLOR; 122 bool dfactorIsConstantAlpha = dfactor == LOCAL_GL_CONSTANT_ALPHA || 123 dfactor == LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA; 124 if ((sfactorIsConstantColor && dfactorIsConstantAlpha) || 125 (dfactorIsConstantColor && sfactorIsConstantAlpha)) { 126 ErrorInvalidOperation( 127 "%s are mutually incompatible, see section 6.8 in" 128 " the WebGL 1.0 spec", 129 info); 130 return false; 131 } 132 133 return true; 134 } 135 136 bool WebGLContext::ValidateStencilOpEnum(GLenum action, const char* info) { 137 switch (action) { 138 case LOCAL_GL_KEEP: 139 case LOCAL_GL_ZERO: 140 case LOCAL_GL_REPLACE: 141 case LOCAL_GL_INCR: 142 case LOCAL_GL_INCR_WRAP: 143 case LOCAL_GL_DECR: 144 case LOCAL_GL_DECR_WRAP: 145 case LOCAL_GL_INVERT: 146 return true; 147 148 default: 149 ErrorInvalidEnumInfo(info, action); 150 return false; 151 } 152 } 153 154 bool WebGLContext::ValidateFaceEnum(const GLenum face) { 155 switch (face) { 156 case LOCAL_GL_FRONT: 157 case LOCAL_GL_BACK: 158 case LOCAL_GL_FRONT_AND_BACK: 159 return true; 160 161 default: 162 ErrorInvalidEnumInfo("face", face); 163 return false; 164 } 165 } 166 167 bool WebGLContext::ValidateAttribArraySetter(uint32_t setterElemSize, 168 uint32_t arrayLength) { 169 if (IsContextLost()) return false; 170 171 if (arrayLength < setterElemSize) { 172 ErrorInvalidValue("Array must have >= %d elements.", setterElemSize); 173 return false; 174 } 175 176 return true; 177 } 178 179 // --------------------- 180 181 static webgl::Limits MakeLimits(const WebGLContext& webgl) { 182 webgl::Limits limits; 183 184 gl::GLContext& gl = *webgl.GL(); 185 186 // - 187 188 for (const auto i : IntegerRange(UnderlyingValue(WebGLExtensionID::Max))) { 189 const auto ext = WebGLExtensionID(i); 190 limits.supportedExtensions[ext] = webgl.IsExtensionSupported(ext); 191 } 192 193 // - 194 // WebGL 1 195 196 // Note: GL_MAX_TEXTURE_UNITS is fixed at 4 for most desktop hardware, 197 // even though the hardware supports much more. The 198 // GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS value is the accurate value. 199 gl.GetUIntegerv(LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, 200 &limits.maxTexUnits); 201 limits.maxTexUnits = std::min( 202 limits.maxTexUnits, uint32_t{UINT8_MAX}); // We want to use uint8_t. 203 204 gl.GetUIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &limits.maxTex2dSize); 205 gl.GetUIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, &limits.maxTexCubeSize); 206 gl.GetUIntegerv(LOCAL_GL_MAX_VERTEX_ATTRIBS, &limits.maxVertexAttribs); 207 208 auto dims = std::array<uint32_t, 2>{}; 209 gl.GetUIntegerv(LOCAL_GL_MAX_VIEWPORT_DIMS, dims.data()); 210 limits.maxViewportDim = std::min(dims[0], dims[1]); 211 212 if (!gl.IsCoreProfile()) { 213 gl.fGetFloatv(LOCAL_GL_ALIASED_LINE_WIDTH_RANGE, 214 limits.lineWidthRange.data()); 215 } 216 217 { 218 const GLenum driverPName = gl.IsCoreProfile() 219 ? LOCAL_GL_POINT_SIZE_RANGE 220 : LOCAL_GL_ALIASED_POINT_SIZE_RANGE; 221 gl.fGetFloatv(driverPName, limits.pointSizeRange.data()); 222 } 223 224 if (webgl.IsWebGL2()) { 225 gl.GetUIntegerv(LOCAL_GL_MAX_ARRAY_TEXTURE_LAYERS, 226 &limits.maxTexArrayLayers); 227 gl.GetUIntegerv(LOCAL_GL_MAX_3D_TEXTURE_SIZE, &limits.maxTex3dSize); 228 gl.GetUIntegerv(LOCAL_GL_MAX_UNIFORM_BUFFER_BINDINGS, 229 &limits.maxUniformBufferBindings); 230 gl.GetUIntegerv(LOCAL_GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, 231 &limits.uniformBufferOffsetAlignment); 232 } 233 234 if (limits.supportedExtensions 235 [WebGLExtensionID::WEBGL_compressed_texture_astc]) { 236 limits.astcHdr = gl.IsExtensionSupported( 237 gl::GLContext::KHR_texture_compression_astc_hdr); 238 } 239 240 if (webgl.IsWebGL2() || 241 limits.supportedExtensions[WebGLExtensionID::WEBGL_draw_buffers]) { 242 gl.GetUIntegerv(LOCAL_GL_MAX_DRAW_BUFFERS, &limits.maxColorDrawBuffers); 243 } 244 245 if (limits.supportedExtensions[WebGLExtensionID::EXT_disjoint_timer_query]) { 246 gl.fGetQueryiv(LOCAL_GL_TIME_ELAPSED_EXT, LOCAL_GL_QUERY_COUNTER_BITS, 247 (int32_t*)&limits.queryCounterBitsTimeElapsed); 248 gl.fGetQueryiv(LOCAL_GL_TIMESTAMP_EXT, LOCAL_GL_QUERY_COUNTER_BITS, 249 (int32_t*)&limits.queryCounterBitsTimestamp); 250 } 251 252 if (limits.supportedExtensions[WebGLExtensionID::OVR_multiview2]) { 253 gl.GetUIntegerv(LOCAL_GL_MAX_VIEWS_OVR, &limits.maxMultiviewLayers); 254 } 255 256 return limits; 257 } 258 259 bool WebGLContext::InitAndValidateGL(FailureReason* const out_failReason) { 260 MOZ_RELEASE_ASSERT(gl, "GFX: GL not initialized"); 261 262 // Unconditionally create a new format usage authority. This is 263 // important when restoring contexts and extensions need to add 264 // formats back into the authority. 265 mFormatUsage = CreateFormatUsage(gl); 266 if (!mFormatUsage) { 267 *out_failReason = {"FEATURE_FAILURE_WEBGL_FORMAT", 268 "Failed to create mFormatUsage."}; 269 return false; 270 } 271 272 GLenum error = gl->fGetError(); 273 if (error != LOCAL_GL_NO_ERROR) { 274 const nsPrintfCString reason( 275 "GL error 0x%x occurred during OpenGL context" 276 " initialization, before WebGL initialization!", 277 error); 278 *out_failReason = {"FEATURE_FAILURE_WEBGL_GLERR_1", reason}; 279 return false; 280 } 281 282 mLoseContextOnMemoryPressure = 283 StaticPrefs::webgl_lose_context_on_memory_pressure(); 284 mCanLoseContextInForeground = 285 StaticPrefs::webgl_can_lose_context_in_foreground(); 286 287 /* 288 // Technically, we should be setting mStencil[...] values to 289 // `allOnes`, but either ANGLE breaks or the SGX540s on Try break. 290 GLuint stencilBits = 0; 291 gl->GetUIntegerv(LOCAL_GL_STENCIL_BITS, &stencilBits); 292 GLuint allOnes = ~(UINT32_MAX << stencilBits); 293 mStencilValueMaskFront = allOnes; 294 mStencilValueMaskBack = allOnes; 295 mStencilWriteMaskFront = allOnes; 296 mStencilWriteMaskBack = allOnes; 297 */ 298 299 gl->GetUIntegerv(LOCAL_GL_STENCIL_VALUE_MASK, &mStencilValueMaskFront); 300 gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_VALUE_MASK, &mStencilValueMaskBack); 301 gl->GetUIntegerv(LOCAL_GL_STENCIL_WRITEMASK, &mStencilWriteMaskFront); 302 gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_WRITEMASK, &mStencilWriteMaskBack); 303 304 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_VALUE_MASK, 305 mStencilValueMaskFront); 306 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_VALUE_MASK, 307 mStencilValueMaskBack); 308 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_WRITEMASK, 309 mStencilWriteMaskFront); 310 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_WRITEMASK, 311 mStencilWriteMaskBack); 312 313 // Bindings, etc. 314 315 mBound2DTextures.Clear(); 316 mBoundCubeMapTextures.Clear(); 317 mBound3DTextures.Clear(); 318 mBound2DArrayTextures.Clear(); 319 mBoundSamplers.Clear(); 320 321 mBoundArrayBuffer = nullptr; 322 mCurrentProgram = nullptr; 323 324 mBoundDrawFramebuffer = nullptr; 325 mBoundReadFramebuffer = nullptr; 326 327 // ----------------------- 328 329 auto limits = MakeLimits(*this); 330 331 // - 332 333 if (limits.maxVertexAttribs < 8) { 334 const nsPrintfCString reason("GL_MAX_VERTEX_ATTRIBS: %d is < 8!", 335 limits.maxVertexAttribs); 336 *out_failReason = {"FEATURE_FAILURE_WEBGL_V_ATRB", reason}; 337 return false; 338 } 339 340 if (limits.maxTexUnits < 8) { 341 const nsPrintfCString reason( 342 "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: %u is < 8!", limits.maxTexUnits); 343 *out_failReason = {"FEATURE_FAILURE_WEBGL_T_UNIT", reason}; 344 return false; 345 } 346 347 mBound2DTextures.SetLength(limits.maxTexUnits); 348 mBoundCubeMapTextures.SetLength(limits.maxTexUnits); 349 mBound3DTextures.SetLength(limits.maxTexUnits); 350 mBound2DArrayTextures.SetLength(limits.maxTexUnits); 351 mBoundSamplers.SetLength(limits.maxTexUnits); 352 353 //////////////// 354 355 gl->GetUIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, &mGLMaxRenderbufferSize); 356 gl->GetUIntegerv(LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS, 357 &mGLMaxFragmentTextureImageUnits); 358 gl->GetUIntegerv(LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, 359 &mGLMaxVertexTextureImageUnits); 360 361 //////////////// 362 363 if (gl->IsGLES()) { 364 mGLMaxFragmentUniformVectors = 365 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS); 366 mGLMaxVertexUniformVectors = 367 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS); 368 if (gl->Version() >= 300) { 369 mGLMaxVertexOutputVectors = 370 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS) / 4; 371 mGLMaxFragmentInputVectors = 372 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS) / 4; 373 } else { 374 mGLMaxFragmentInputVectors = 375 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_VARYING_VECTORS); 376 mGLMaxVertexOutputVectors = mGLMaxFragmentInputVectors; 377 } 378 } else { 379 mGLMaxFragmentUniformVectors = 380 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS) / 4; 381 mGLMaxVertexUniformVectors = 382 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_VERTEX_UNIFORM_COMPONENTS) / 4; 383 384 if (gl->Version() >= 320) { 385 mGLMaxVertexOutputVectors = 386 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS) / 4; 387 mGLMaxFragmentInputVectors = 388 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS) / 4; 389 } else { 390 // Same enum val as GL2's GL_MAX_VARYING_FLOATS. 391 mGLMaxFragmentInputVectors = 392 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_VARYING_COMPONENTS) / 4; 393 mGLMaxVertexOutputVectors = mGLMaxFragmentInputVectors; 394 } 395 } 396 397 //////////////// 398 399 if (StaticPrefs::webgl_min_capability_mode()) { 400 bool ok = true; 401 402 ok &= RestrictCap(&mGLMaxVertexTextureImageUnits, 403 kMinMaxVertexTextureImageUnits); 404 ok &= RestrictCap(&mGLMaxFragmentTextureImageUnits, 405 kMinMaxFragmentTextureImageUnits); 406 ok &= RestrictCap(&limits.maxTexUnits, kMinMaxCombinedTextureImageUnits); 407 408 ok &= RestrictCap(&limits.maxVertexAttribs, kMinMaxVertexAttribs); 409 ok &= RestrictCap(&mGLMaxVertexUniformVectors, kMinMaxVertexUniformVectors); 410 ok &= RestrictCap(&mGLMaxFragmentUniformVectors, 411 kMinMaxFragmentUniformVectors); 412 ok &= RestrictCap(&mGLMaxVertexOutputVectors, kMinMaxVaryingVectors); 413 ok &= RestrictCap(&mGLMaxFragmentInputVectors, kMinMaxVaryingVectors); 414 415 ok &= RestrictCap(&limits.maxColorDrawBuffers, kMinMaxDrawBuffers); 416 417 ok &= RestrictCap(&limits.maxTex2dSize, kMinMaxTextureSize); 418 ok &= RestrictCap(&limits.maxTexCubeSize, kMinMaxCubeMapTextureSize); 419 ok &= RestrictCap(&limits.maxTex3dSize, kMinMax3DTextureSize); 420 421 ok &= RestrictCap(&limits.maxTexArrayLayers, kMinMaxArrayTextureLayers); 422 ok &= RestrictCap(&mGLMaxRenderbufferSize, kMinMaxRenderbufferSize); 423 424 if (!ok) { 425 GenerateWarning("Unable to restrict WebGL limits to minimums."); 426 return false; 427 } 428 429 mDisableFragHighP = true; 430 } else if (mResistFingerprinting) { 431 bool ok = true; 432 433 ok &= RestrictCap(&limits.maxTex2dSize, kCommonMaxTextureSize); 434 ok &= RestrictCap(&limits.maxTexCubeSize, kCommonMaxCubeMapTextureSize); 435 ok &= RestrictCap(&mGLMaxRenderbufferSize, kCommonMaxRenderbufferSize); 436 437 ok &= RestrictCap(&mGLMaxVertexTextureImageUnits, 438 kCommonMaxVertexTextureImageUnits); 439 ok &= RestrictCap(&mGLMaxFragmentTextureImageUnits, 440 kCommonMaxFragmentTextureImageUnits); 441 ok &= RestrictCap(&limits.maxTexUnits, kCommonMaxCombinedTextureImageUnits); 442 443 ok &= RestrictCap(&limits.maxVertexAttribs, kCommonMaxVertexAttribs); 444 ok &= RestrictCap(&mGLMaxVertexUniformVectors, 445 kCommonMaxVertexUniformVectors); 446 ok &= RestrictCap(&mGLMaxFragmentUniformVectors, 447 kCommonMaxFragmentUniformVectors); 448 ok &= RestrictCap(&mGLMaxVertexOutputVectors, kCommonMaxVaryingVectors); 449 ok &= RestrictCap(&mGLMaxFragmentInputVectors, kCommonMaxVaryingVectors); 450 451 if (limits.lineWidthRange[0] <= kCommonAliasedLineWidthRangeMin) { 452 limits.lineWidthRange[0] = kCommonAliasedLineWidthRangeMin; 453 } else { 454 ok = false; 455 } 456 if (limits.pointSizeRange[0] <= kCommonAliasedPointSizeRangeMin) { 457 limits.pointSizeRange[0] = kCommonAliasedPointSizeRangeMin; 458 } else { 459 ok = false; 460 } 461 462 ok &= 463 RestrictCap(&limits.lineWidthRange[1], kCommonAliasedLineWidthRangeMax); 464 ok &= 465 RestrictCap(&limits.pointSizeRange[1], kCommonAliasedPointSizeRangeMax); 466 ok &= RestrictCap(&limits.maxViewportDim, kCommonMaxViewportDims); 467 468 if (!ok) { 469 GenerateWarning( 470 "Unable to restrict WebGL limits in order to resist fingerprinting"); 471 return false; 472 } 473 } 474 475 mLimits = Some(limits); 476 477 //////////////// 478 479 if (gl->IsCompatibilityProfile()) { 480 gl->fEnable(LOCAL_GL_POINT_SPRITE); 481 } 482 483 if (!gl->IsGLES()) { 484 gl->fEnable(LOCAL_GL_PROGRAM_POINT_SIZE); 485 } 486 487 if (gl->IsSupported(gl::GLFeature::seamless_cube_map_opt_in)) { 488 gl->fEnable(LOCAL_GL_TEXTURE_CUBE_MAP_SEAMLESS); 489 } 490 491 // initialize shader translator 492 if (!sh::Initialize()) { 493 *out_failReason = {"FEATURE_FAILURE_WEBGL_GLSL", 494 "GLSL translator initialization failed!"}; 495 return false; 496 } 497 498 // Mesa can only be detected with the GL_VERSION string, of the form 499 // "2.1 Mesa 7.11.0" 500 const char* versionStr = (const char*)(gl->fGetString(LOCAL_GL_VERSION)); 501 mIsMesa = strstr(versionStr, "Mesa"); 502 503 // Notice that the point of calling fGetError here is not only to check for 504 // errors, but also to reset the error flags so that a subsequent WebGL 505 // getError call will give the correct result. 506 error = gl->fGetError(); 507 if (error != LOCAL_GL_NO_ERROR) { 508 const nsPrintfCString reason( 509 "GL error 0x%x occurred during WebGL context" 510 " initialization!", 511 error); 512 *out_failReason = {"FEATURE_FAILURE_WEBGL_GLERR_2", reason}; 513 return false; 514 } 515 516 if (IsWebGL2() && !InitWebGL2(out_failReason)) { 517 // Todo: Bug 898404: Only allow WebGL2 on GL>=3.0 on desktop GL. 518 return false; 519 } 520 521 // OpenGL core profiles remove the default VAO object from version 522 // 4.0.0. We create a default VAO for all core profiles, 523 // regardless of version. 524 // 525 // GL Spec 4.0.0: 526 // (https://www.opengl.org/registry/doc/glspec40.core.20100311.pdf) 527 // in Section E.2.2 "Removed Features", pg 397: "[...] The default 528 // vertex array object (the name zero) is also deprecated. [...]" 529 mDefaultVertexArray = WebGLVertexArray::Create(this); 530 mDefaultVertexArray->BindVertexArray(); 531 532 mPrimRestartTypeBytes = 0; 533 534 // - 535 536 mGenericVertexAttribTypes.assign(limits.maxVertexAttribs, 537 webgl::AttribBaseType::Float); 538 mGenericVertexAttribTypeInvalidator.InvalidateCaches(); 539 540 static const float kDefaultGenericVertexAttribData[4] = {0, 0, 0, 1}; 541 memcpy(mGenericVertexAttrib0Data, kDefaultGenericVertexAttribData, 542 sizeof(mGenericVertexAttrib0Data)); 543 544 mFakeVertexAttrib0BufferObject = 0; 545 546 mNeedsLegacyVertexAttrib0Handling = gl->IsCompatibilityProfile(); 547 if (gl->WorkAroundDriverBugs() && kIsMacOS) { 548 // Failures in conformance/attribs/gl-disabled-vertex-attrib. 549 // Even in Core profiles on NV. Sigh. 550 mNeedsLegacyVertexAttrib0Handling |= (gl->Vendor() == gl::GLVendor::NVIDIA); 551 552 mBug_DrawArraysInstancedUserAttribFetchAffectedByFirst |= 553 (gl->Vendor() == gl::GLVendor::Intel); 554 555 // Failures for programs with no attribs: 556 // conformance/attribs/gl-vertex-attrib-unconsumed-out-of-bounds.html 557 mMaybeNeedsLegacyVertexAttrib0Handling = true; 558 } 559 mMaybeNeedsLegacyVertexAttrib0Handling |= mNeedsLegacyVertexAttrib0Handling; 560 561 if (const auto& env = 562 gfxEnv::MOZ_WEBGL_WORKAROUND_FIRST_AFFECTS_INSTANCE_ID()) { 563 const auto was = mBug_DrawArraysInstancedUserAttribFetchAffectedByFirst; 564 mBug_DrawArraysInstancedUserAttribFetchAffectedByFirst = 565 (env.as_str != "0"); 566 printf_stderr( 567 "mBug_DrawArraysInstancedUserAttribFetchAffectedByFirst: %i -> %i\n", 568 int(was), int(mBug_DrawArraysInstancedUserAttribFetchAffectedByFirst)); 569 } 570 571 // - 572 573 mNeedsIndexValidation = 574 !gl->IsSupported(gl::GLFeature::robust_buffer_access_behavior); 575 switch (StaticPrefs::webgl_force_index_validation()) { 576 case -1: 577 mNeedsIndexValidation = false; 578 break; 579 case 1: 580 mNeedsIndexValidation = true; 581 break; 582 default: 583 MOZ_ASSERT(StaticPrefs::webgl_force_index_validation() == 0); 584 break; 585 } 586 587 for (auto& cur : mExtensions) { 588 cur = {}; 589 } 590 591 return true; 592 } 593 594 bool WebGLContext::ValidateFramebufferTarget(GLenum target) const { 595 bool isValid = true; 596 switch (target) { 597 case LOCAL_GL_FRAMEBUFFER: 598 break; 599 600 case LOCAL_GL_DRAW_FRAMEBUFFER: 601 case LOCAL_GL_READ_FRAMEBUFFER: 602 isValid = IsWebGL2(); 603 break; 604 605 default: 606 isValid = false; 607 break; 608 } 609 610 if (MOZ_LIKELY(isValid)) { 611 return true; 612 } 613 614 ErrorInvalidEnumArg("target", target); 615 return false; 616 } 617 618 } // namespace mozilla