tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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