tor-browser

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

WebGLProgram.cpp (37505B)


      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 "WebGLProgram.h"
      7 
      8 #include "GLContext.h"
      9 #include "WebGLBuffer.h"
     10 #include "WebGLContext.h"
     11 #include "WebGLFormats.h"
     12 #include "WebGLShader.h"
     13 #include "WebGLShaderValidator.h"
     14 #include "WebGLTransformFeedback.h"
     15 #include "WebGLValidateStrings.h"
     16 #include "WebGLVertexArray.h"
     17 #include "mozilla/CheckedInt.h"
     18 #include "mozilla/RefPtr.h"
     19 #include "mozilla/dom/WebGL2RenderingContextBinding.h"
     20 #include "mozilla/dom/WebGLRenderingContextBinding.h"
     21 #include "mozilla/gfx/Logging.h"
     22 #include "nsPrintfCString.h"
     23 
     24 namespace mozilla {
     25 
     26 static bool IsShadowSampler(const GLenum elemType) {
     27  switch (elemType) {
     28    case LOCAL_GL_SAMPLER_2D_SHADOW:
     29    case LOCAL_GL_SAMPLER_CUBE_SHADOW:
     30    case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
     31      return true;
     32    default:
     33      return false;
     34  }
     35 }
     36 
     37 static Maybe<webgl::TextureBaseType> SamplerBaseType(const GLenum elemType) {
     38  switch (elemType) {
     39    case LOCAL_GL_SAMPLER_2D:
     40    case LOCAL_GL_SAMPLER_3D:
     41    case LOCAL_GL_SAMPLER_CUBE:
     42    case LOCAL_GL_SAMPLER_2D_ARRAY:
     43    case LOCAL_GL_SAMPLER_2D_SHADOW:
     44    case LOCAL_GL_SAMPLER_CUBE_SHADOW:
     45    case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
     46      return Some(webgl::TextureBaseType::Float);
     47 
     48    case LOCAL_GL_INT_SAMPLER_2D:
     49    case LOCAL_GL_INT_SAMPLER_3D:
     50    case LOCAL_GL_INT_SAMPLER_CUBE:
     51    case LOCAL_GL_INT_SAMPLER_2D_ARRAY:
     52      return Some(webgl::TextureBaseType::Int);
     53 
     54    case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D:
     55    case LOCAL_GL_UNSIGNED_INT_SAMPLER_3D:
     56    case LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE:
     57    case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
     58      return Some(webgl::TextureBaseType::UInt);
     59 
     60    default:
     61      return {};
     62  }
     63 }
     64 
     65 //////////
     66 
     67 static webgl::TextureBaseType FragOutputBaseType(const GLenum type) {
     68  switch (type) {
     69    case LOCAL_GL_FLOAT:
     70    case LOCAL_GL_FLOAT_VEC2:
     71    case LOCAL_GL_FLOAT_VEC3:
     72    case LOCAL_GL_FLOAT_VEC4:
     73      return webgl::TextureBaseType::Float;
     74 
     75    case LOCAL_GL_INT:
     76    case LOCAL_GL_INT_VEC2:
     77    case LOCAL_GL_INT_VEC3:
     78    case LOCAL_GL_INT_VEC4:
     79      return webgl::TextureBaseType::Int;
     80 
     81    case LOCAL_GL_UNSIGNED_INT:
     82    case LOCAL_GL_UNSIGNED_INT_VEC2:
     83    case LOCAL_GL_UNSIGNED_INT_VEC3:
     84    case LOCAL_GL_UNSIGNED_INT_VEC4:
     85      return webgl::TextureBaseType::UInt;
     86 
     87    default:
     88      break;
     89  }
     90 
     91  const auto& str = EnumString(type);
     92  gfxCriticalError() << "Unhandled enum for FragOutputBaseType: "
     93                     << str.c_str();
     94  return webgl::TextureBaseType::Float;
     95 }
     96 
     97 // -----------------------------------------
     98 
     99 namespace webgl {
    100 
    101 void UniformAs1fv(gl::GLContext& gl, GLint location, GLsizei count,
    102                  bool transpose, const void* any) {
    103  gl.fUniform1fv(location, count, static_cast<const float*>(any));
    104 }
    105 void UniformAs2fv(gl::GLContext& gl, GLint location, GLsizei count,
    106                  bool transpose, const void* any) {
    107  gl.fUniform2fv(location, count, static_cast<const float*>(any));
    108 }
    109 void UniformAs3fv(gl::GLContext& gl, GLint location, GLsizei count,
    110                  bool transpose, const void* any) {
    111  gl.fUniform3fv(location, count, static_cast<const float*>(any));
    112 }
    113 void UniformAs4fv(gl::GLContext& gl, GLint location, GLsizei count,
    114                  bool transpose, const void* any) {
    115  gl.fUniform4fv(location, count, static_cast<const float*>(any));
    116 }
    117 
    118 void UniformAs1iv(gl::GLContext& gl, GLint location, GLsizei count,
    119                  bool transpose, const void* any) {
    120  gl.fUniform1iv(location, count, static_cast<const int32_t*>(any));
    121 }
    122 void UniformAs2iv(gl::GLContext& gl, GLint location, GLsizei count,
    123                  bool transpose, const void* any) {
    124  gl.fUniform2iv(location, count, static_cast<const int32_t*>(any));
    125 }
    126 void UniformAs3iv(gl::GLContext& gl, GLint location, GLsizei count,
    127                  bool transpose, const void* any) {
    128  gl.fUniform3iv(location, count, static_cast<const int32_t*>(any));
    129 }
    130 void UniformAs4iv(gl::GLContext& gl, GLint location, GLsizei count,
    131                  bool transpose, const void* any) {
    132  gl.fUniform4iv(location, count, static_cast<const int32_t*>(any));
    133 }
    134 
    135 void UniformAs1uiv(gl::GLContext& gl, GLint location, GLsizei count,
    136                   bool transpose, const void* any) {
    137  gl.fUniform1uiv(location, count, static_cast<const uint32_t*>(any));
    138 }
    139 void UniformAs2uiv(gl::GLContext& gl, GLint location, GLsizei count,
    140                   bool transpose, const void* any) {
    141  gl.fUniform2uiv(location, count, static_cast<const uint32_t*>(any));
    142 }
    143 void UniformAs3uiv(gl::GLContext& gl, GLint location, GLsizei count,
    144                   bool transpose, const void* any) {
    145  gl.fUniform3uiv(location, count, static_cast<const uint32_t*>(any));
    146 }
    147 void UniformAs4uiv(gl::GLContext& gl, GLint location, GLsizei count,
    148                   bool transpose, const void* any) {
    149  gl.fUniform4uiv(location, count, static_cast<const uint32_t*>(any));
    150 }
    151 
    152 void UniformAsMatrix2x2fv(gl::GLContext& gl, GLint location, GLsizei count,
    153                          bool transpose, const void* any) {
    154  gl.fUniformMatrix2fv(location, count, transpose,
    155                       static_cast<const float*>(any));
    156 }
    157 void UniformAsMatrix2x3fv(gl::GLContext& gl, GLint location, GLsizei count,
    158                          bool transpose, const void* any) {
    159  gl.fUniformMatrix2x3fv(location, count, transpose,
    160                         static_cast<const float*>(any));
    161 }
    162 void UniformAsMatrix2x4fv(gl::GLContext& gl, GLint location, GLsizei count,
    163                          bool transpose, const void* any) {
    164  gl.fUniformMatrix2x4fv(location, count, transpose,
    165                         static_cast<const float*>(any));
    166 }
    167 
    168 void UniformAsMatrix3x2fv(gl::GLContext& gl, GLint location, GLsizei count,
    169                          bool transpose, const void* any) {
    170  gl.fUniformMatrix3x2fv(location, count, transpose,
    171                         static_cast<const float*>(any));
    172 }
    173 void UniformAsMatrix3x3fv(gl::GLContext& gl, GLint location, GLsizei count,
    174                          bool transpose, const void* any) {
    175  gl.fUniformMatrix3fv(location, count, transpose,
    176                       static_cast<const float*>(any));
    177 }
    178 void UniformAsMatrix3x4fv(gl::GLContext& gl, GLint location, GLsizei count,
    179                          bool transpose, const void* any) {
    180  gl.fUniformMatrix3x4fv(location, count, transpose,
    181                         static_cast<const float*>(any));
    182 }
    183 
    184 void UniformAsMatrix4x2fv(gl::GLContext& gl, GLint location, GLsizei count,
    185                          bool transpose, const void* any) {
    186  gl.fUniformMatrix4x2fv(location, count, transpose,
    187                         static_cast<const float*>(any));
    188 }
    189 void UniformAsMatrix4x3fv(gl::GLContext& gl, GLint location, GLsizei count,
    190                          bool transpose, const void* any) {
    191  gl.fUniformMatrix4x3fv(location, count, transpose,
    192                         static_cast<const float*>(any));
    193 }
    194 void UniformAsMatrix4x4fv(gl::GLContext& gl, GLint location, GLsizei count,
    195                          bool transpose, const void* any) {
    196  gl.fUniformMatrix4fv(location, count, transpose,
    197                       static_cast<const float*>(any));
    198 }
    199 
    200 // -
    201 
    202 static bool EndsWith(const std::string& str, const std::string& needle) {
    203  if (str.length() < needle.length()) return false;
    204  return str.compare(str.length() - needle.length(), needle.length(), needle) ==
    205         0;
    206 }
    207 
    208 webgl::ActiveUniformValidationInfo webgl::ActiveUniformValidationInfo::Make(
    209    const webgl::ActiveUniformInfo& info) {
    210  auto ret = webgl::ActiveUniformValidationInfo{info};
    211  ret.isArray = EndsWith(info.name, "[0]");
    212 
    213  switch (info.elemType) {
    214    case LOCAL_GL_FLOAT:
    215      ret.channelsPerElem = 1;
    216      ret.pfn = &UniformAs1fv;
    217      break;
    218    case LOCAL_GL_FLOAT_VEC2:
    219      ret.channelsPerElem = 2;
    220      ret.pfn = &UniformAs2fv;
    221      break;
    222    case LOCAL_GL_FLOAT_VEC3:
    223      ret.channelsPerElem = 3;
    224      ret.pfn = &UniformAs3fv;
    225      break;
    226    case LOCAL_GL_FLOAT_VEC4:
    227      ret.channelsPerElem = 4;
    228      ret.pfn = &UniformAs4fv;
    229      break;
    230 
    231    case LOCAL_GL_SAMPLER_2D:
    232    case LOCAL_GL_SAMPLER_3D:
    233    case LOCAL_GL_SAMPLER_CUBE:
    234    case LOCAL_GL_SAMPLER_2D_SHADOW:
    235    case LOCAL_GL_SAMPLER_2D_ARRAY:
    236    case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
    237    case LOCAL_GL_SAMPLER_CUBE_SHADOW:
    238    case LOCAL_GL_INT_SAMPLER_2D:
    239    case LOCAL_GL_INT_SAMPLER_3D:
    240    case LOCAL_GL_INT_SAMPLER_CUBE:
    241    case LOCAL_GL_INT_SAMPLER_2D_ARRAY:
    242    case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D:
    243    case LOCAL_GL_UNSIGNED_INT_SAMPLER_3D:
    244    case LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE:
    245    case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
    246    case LOCAL_GL_BOOL:
    247    case LOCAL_GL_INT:
    248      ret.channelsPerElem = 1;
    249      ret.pfn = &UniformAs1iv;
    250      break;
    251    case LOCAL_GL_BOOL_VEC2:
    252    case LOCAL_GL_INT_VEC2:
    253      ret.channelsPerElem = 2;
    254      ret.pfn = &UniformAs2iv;
    255      break;
    256    case LOCAL_GL_BOOL_VEC3:
    257    case LOCAL_GL_INT_VEC3:
    258      ret.channelsPerElem = 3;
    259      ret.pfn = &UniformAs3iv;
    260      break;
    261    case LOCAL_GL_BOOL_VEC4:
    262    case LOCAL_GL_INT_VEC4:
    263      ret.channelsPerElem = 4;
    264      ret.pfn = &UniformAs4iv;
    265      break;
    266 
    267    case LOCAL_GL_UNSIGNED_INT:
    268      ret.channelsPerElem = 1;
    269      ret.pfn = &UniformAs1uiv;
    270      break;
    271    case LOCAL_GL_UNSIGNED_INT_VEC2:
    272      ret.channelsPerElem = 2;
    273      ret.pfn = &UniformAs2uiv;
    274      break;
    275    case LOCAL_GL_UNSIGNED_INT_VEC3:
    276      ret.channelsPerElem = 3;
    277      ret.pfn = &UniformAs3uiv;
    278      break;
    279    case LOCAL_GL_UNSIGNED_INT_VEC4:
    280      ret.channelsPerElem = 4;
    281      ret.pfn = &UniformAs4uiv;
    282      break;
    283 
    284      // -
    285 
    286    case LOCAL_GL_FLOAT_MAT2:
    287      ret.channelsPerElem = 2 * 2;
    288      ret.pfn = &UniformAsMatrix2x2fv;
    289      break;
    290    case LOCAL_GL_FLOAT_MAT2x3:
    291      ret.channelsPerElem = 2 * 3;
    292      ret.pfn = &UniformAsMatrix2x3fv;
    293      break;
    294    case LOCAL_GL_FLOAT_MAT2x4:
    295      ret.channelsPerElem = 2 * 4;
    296      ret.pfn = &UniformAsMatrix2x4fv;
    297      break;
    298 
    299    case LOCAL_GL_FLOAT_MAT3x2:
    300      ret.channelsPerElem = 3 * 2;
    301      ret.pfn = &UniformAsMatrix3x2fv;
    302      break;
    303    case LOCAL_GL_FLOAT_MAT3:
    304      ret.channelsPerElem = 3 * 3;
    305      ret.pfn = &UniformAsMatrix3x3fv;
    306      break;
    307    case LOCAL_GL_FLOAT_MAT3x4:
    308      ret.channelsPerElem = 3 * 4;
    309      ret.pfn = &UniformAsMatrix3x4fv;
    310      break;
    311 
    312    case LOCAL_GL_FLOAT_MAT4x2:
    313      ret.channelsPerElem = 4 * 2;
    314      ret.pfn = &UniformAsMatrix4x2fv;
    315      break;
    316    case LOCAL_GL_FLOAT_MAT4x3:
    317      ret.channelsPerElem = 4 * 3;
    318      ret.pfn = &UniformAsMatrix4x3fv;
    319      break;
    320    case LOCAL_GL_FLOAT_MAT4:
    321      ret.channelsPerElem = 4 * 4;
    322      ret.pfn = &UniformAsMatrix4x4fv;
    323      break;
    324 
    325    default:
    326      gfxCriticalError() << "Bad `elemType`: " << EnumString(info.elemType);
    327      MOZ_CRASH("`elemType`");
    328  }
    329  return ret;
    330 }
    331 
    332 }  // namespace webgl
    333 
    334 // -------------------------
    335 
    336 // #define DUMP_SHADERVAR_MAPPINGS
    337 
    338 RefPtr<const webgl::LinkedProgramInfo> QueryProgramInfo(WebGLProgram* prog,
    339                                                        gl::GLContext* gl) {
    340  WebGLContext* const webgl = prog->mContext;
    341 
    342  RefPtr<webgl::LinkedProgramInfo> info(new webgl::LinkedProgramInfo(prog));
    343 
    344  // Frag outputs
    345 
    346  {
    347    const auto& fragShader = prog->FragShader();
    348    const auto& compileResults = fragShader->CompileResults();
    349    const auto version = compileResults->mShaderVersion;
    350 
    351    const auto fnAddInfo = [&](const webgl::FragOutputInfo& x) {
    352      info->hasOutput[x.loc] = true;
    353      info->fragOutputs.insert({x.loc, x});
    354    };
    355 
    356    if (version == 300) {
    357      for (const auto& cur : compileResults->mOutputVariables) {
    358        auto loc = cur.location;
    359        if (loc == -1) loc = 0;
    360 
    361        const auto info =
    362            webgl::FragOutputInfo{uint8_t(loc), cur.name, cur.mappedName,
    363                                  FragOutputBaseType(cur.type)};
    364        if (!cur.isArray()) {
    365          fnAddInfo(info);
    366          continue;
    367        }
    368        MOZ_ASSERT(cur.arraySizes.size() == 1);
    369        for (uint32_t i = 0; i < cur.arraySizes[0]; ++i) {
    370          const auto indexStr = std::string("[") + std::to_string(i) + "]";
    371 
    372          const auto userName = info.userName + indexStr;
    373          const auto mappedName = info.mappedName + indexStr;
    374 
    375          const auto indexedInfo = webgl::FragOutputInfo{
    376              uint8_t(info.loc + i), userName, mappedName, info.baseType};
    377          fnAddInfo(indexedInfo);
    378        }
    379      }
    380    } else {
    381      // ANGLE's translator doesn't tell us about non-user frag outputs. :(
    382 
    383      const auto& translatedSource = compileResults->mObjectCode;
    384      uint32_t drawBuffers = 1;
    385      if (translatedSource.find("(gl_FragData[1]") != std::string::npos ||
    386          translatedSource.find("(webgl_FragData[1]") != std::string::npos) {
    387        // The matching with the leading '(' prevents cleverly-named user vars
    388        // breaking this. Since ANGLE initializes all outputs, if this is an MRT
    389        // shader, FragData[1] will be present. FragData[0] is valid for non-MRT
    390        // shaders.
    391        drawBuffers = webgl->GLMaxDrawBuffers();
    392      } else if (translatedSource.find("(gl_FragColor") == std::string::npos &&
    393                 translatedSource.find("(webgl_FragColor") ==
    394                     std::string::npos &&
    395                 translatedSource.find("(gl_FragData") == std::string::npos &&
    396                 translatedSource.find("(webgl_FragData") ==
    397                     std::string::npos) {
    398        // We have to support no-color-output shaders?
    399        drawBuffers = 0;
    400      }
    401 
    402      for (uint32_t i = 0; i < drawBuffers; ++i) {
    403        const auto name = std::string("gl_FragData[") + std::to_string(i) + "]";
    404        const auto info = webgl::FragOutputInfo{uint8_t(i), name, name,
    405                                                webgl::TextureBaseType::Float};
    406        fnAddInfo(info);
    407      }
    408    }
    409  }
    410 
    411  const auto& vertShader = prog->VertShader();
    412  const auto& vertCompileResults = vertShader->CompileResults();
    413  const auto numViews = vertCompileResults->mVertexShaderNumViews;
    414  if (numViews != -1) {
    415    info->zLayerCount = AssertedCast<uint8_t>(numViews);
    416  }
    417 
    418  // -
    419 
    420  auto& nameMap = info->nameMap;
    421 
    422  const auto fnAccum = [&](WebGLShader& shader) {
    423    const auto& compRes = shader.CompileResults();
    424    for (const auto& pair : compRes->mNameMap) {
    425      nameMap.insert(pair);
    426    }
    427  };
    428  fnAccum(*prog->VertShader());
    429  fnAccum(*prog->FragShader());
    430 
    431  // -
    432 
    433  std::unordered_map<std::string, std::string> nameUnmap;
    434  for (const auto& pair : nameMap) {
    435    nameUnmap.insert({pair.second, pair.first});
    436  }
    437 
    438  info->active =
    439      GetLinkActiveInfo(*gl, prog->mGLName, webgl->IsWebGL2(), nameUnmap);
    440 
    441  // -
    442 
    443  for (const auto& attrib : info->active.activeAttribs) {
    444    if (attrib.location == 0) {
    445      info->attrib0Active = true;
    446      break;
    447    }
    448  }
    449 
    450  info->webgl_gl_VertexID_Offset =
    451      gl->fGetUniformLocation(prog->mGLName, "webgl_gl_VertexID_Offset");
    452 
    453  // -
    454 
    455  for (const auto& uniform : info->active.activeUniforms) {
    456    const auto& elemType = uniform.elemType;
    457    webgl::SamplerUniformInfo* samplerInfo = nullptr;
    458    const auto baseType = SamplerBaseType(elemType);
    459    if (baseType) {
    460      const bool isShadowSampler = IsShadowSampler(elemType);
    461 
    462      auto* texList = &webgl->mBound2DTextures;
    463 
    464      switch (elemType) {
    465        case LOCAL_GL_SAMPLER_2D:
    466        case LOCAL_GL_SAMPLER_2D_SHADOW:
    467        case LOCAL_GL_INT_SAMPLER_2D:
    468        case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D:
    469          break;
    470 
    471        case LOCAL_GL_SAMPLER_CUBE:
    472        case LOCAL_GL_SAMPLER_CUBE_SHADOW:
    473        case LOCAL_GL_INT_SAMPLER_CUBE:
    474        case LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE:
    475          texList = &webgl->mBoundCubeMapTextures;
    476          break;
    477 
    478        case LOCAL_GL_SAMPLER_3D:
    479        case LOCAL_GL_INT_SAMPLER_3D:
    480        case LOCAL_GL_UNSIGNED_INT_SAMPLER_3D:
    481          texList = &webgl->mBound3DTextures;
    482          break;
    483 
    484        case LOCAL_GL_SAMPLER_2D_ARRAY:
    485        case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
    486        case LOCAL_GL_INT_SAMPLER_2D_ARRAY:
    487        case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
    488          texList = &webgl->mBound2DArrayTextures;
    489          break;
    490      }
    491 
    492      auto curInfo = std::unique_ptr<webgl::SamplerUniformInfo>(
    493          new webgl::SamplerUniformInfo{*texList, *baseType, isShadowSampler});
    494      MOZ_RELEASE_ASSERT(curInfo->texUnits.resize(uniform.elemCount));
    495      samplerInfo = curInfo.get();
    496      info->samplerUniforms.push_back(std::move(curInfo));
    497    }
    498 
    499    const auto valInfo = webgl::ActiveUniformValidationInfo::Make(uniform);
    500 
    501    for (const auto& pair : uniform.locByIndex) {
    502      info->locationMap.insert(
    503          {pair.second, {valInfo, pair.first, samplerInfo}});
    504    }
    505  }
    506 
    507  // -
    508 
    509  {
    510    const auto& activeBlocks = info->active.activeUniformBlocks;
    511    info->uniformBlocks.reserve(activeBlocks.size());
    512    for (const auto& cur : activeBlocks) {
    513      const auto curInfo = webgl::UniformBlockInfo{
    514          cur, &webgl->mIndexedUniformBufferBindings[0]};
    515      info->uniformBlocks.push_back(curInfo);
    516    }
    517  }
    518 
    519  return info;
    520 }
    521 
    522 ////////////////////////////////////////////////////////////////////////////////
    523 
    524 webgl::LinkedProgramInfo::LinkedProgramInfo(WebGLProgram* prog)
    525    : prog(prog),
    526      transformFeedbackBufferMode(prog->mNextLink_TransformFeedbackBufferMode) {
    527 }
    528 
    529 webgl::LinkedProgramInfo::~LinkedProgramInfo() = default;
    530 
    531 webgl::AttribBaseType webgl::ToAttribBaseType(const GLenum elemType) {
    532  switch (elemType) {
    533    case LOCAL_GL_BOOL:
    534    case LOCAL_GL_BOOL_VEC2:
    535    case LOCAL_GL_BOOL_VEC3:
    536    case LOCAL_GL_BOOL_VEC4:
    537      return webgl::AttribBaseType::Boolean;
    538 
    539    case LOCAL_GL_FLOAT:
    540    case LOCAL_GL_FLOAT_VEC2:
    541    case LOCAL_GL_FLOAT_VEC3:
    542    case LOCAL_GL_FLOAT_VEC4:
    543    case LOCAL_GL_FLOAT_MAT2:
    544    case LOCAL_GL_FLOAT_MAT2x3:
    545    case LOCAL_GL_FLOAT_MAT3x2:
    546    case LOCAL_GL_FLOAT_MAT2x4:
    547    case LOCAL_GL_FLOAT_MAT4x2:
    548    case LOCAL_GL_FLOAT_MAT3:
    549    case LOCAL_GL_FLOAT_MAT3x4:
    550    case LOCAL_GL_FLOAT_MAT4x3:
    551    case LOCAL_GL_FLOAT_MAT4:
    552      return webgl::AttribBaseType::Float;
    553 
    554    case LOCAL_GL_INT:
    555    case LOCAL_GL_INT_VEC2:
    556    case LOCAL_GL_INT_VEC3:
    557    case LOCAL_GL_INT_VEC4:
    558    case LOCAL_GL_SAMPLER_2D:
    559    case LOCAL_GL_SAMPLER_3D:
    560    case LOCAL_GL_SAMPLER_CUBE:
    561    case LOCAL_GL_SAMPLER_2D_SHADOW:
    562    case LOCAL_GL_SAMPLER_2D_ARRAY:
    563    case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
    564    case LOCAL_GL_SAMPLER_CUBE_SHADOW:
    565    case LOCAL_GL_INT_SAMPLER_2D:
    566    case LOCAL_GL_INT_SAMPLER_3D:
    567    case LOCAL_GL_INT_SAMPLER_CUBE:
    568    case LOCAL_GL_INT_SAMPLER_2D_ARRAY:
    569    case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D:
    570    case LOCAL_GL_UNSIGNED_INT_SAMPLER_3D:
    571    case LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE:
    572    case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
    573      return webgl::AttribBaseType::Int;
    574 
    575    case LOCAL_GL_UNSIGNED_INT:
    576    case LOCAL_GL_UNSIGNED_INT_VEC2:
    577    case LOCAL_GL_UNSIGNED_INT_VEC3:
    578    case LOCAL_GL_UNSIGNED_INT_VEC4:
    579      return webgl::AttribBaseType::Uint;
    580 
    581    default:
    582      gfxCriticalError() << "Bad `elemType`: " << EnumString(elemType);
    583      MOZ_CRASH("`elemType`");
    584  }
    585 }
    586 
    587 const char* webgl::ToString(const webgl::AttribBaseType x) {
    588  switch (x) {
    589    case webgl::AttribBaseType::Float:
    590      return "FLOAT";
    591    case webgl::AttribBaseType::Int:
    592      return "INT";
    593    case webgl::AttribBaseType::Uint:
    594      return "UINT";
    595    case webgl::AttribBaseType::Boolean:
    596      return "BOOL";
    597  }
    598  MOZ_CRASH("pacify gcc6 warning");
    599 }
    600 
    601 const char* webgl::ToString(const webgl::UniformBaseType x) {
    602  switch (x) {
    603    case webgl::UniformBaseType::Float:
    604      return "FLOAT";
    605    case webgl::UniformBaseType::Int:
    606      return "INT";
    607    case webgl::UniformBaseType::Uint:
    608      return "UINT";
    609  }
    610  MOZ_CRASH("pacify gcc6 warning");
    611 }
    612 
    613 const webgl::CachedDrawFetchLimits*
    614 webgl::LinkedProgramInfo::GetDrawFetchLimits() const {
    615  const auto& webgl = prog->mContext;
    616  const auto& vao = webgl->mBoundVertexArray;
    617 
    618  {
    619    // We have to ensure that every enabled attrib array (not just the active
    620    // ones) has a non-null buffer.
    621    const auto badIndex = vao->GetAttribIsArrayWithNullBuffer();
    622    if (badIndex) {
    623      webgl->ErrorInvalidOperation(
    624          "Vertex attrib array %u is enabled but"
    625          " has no buffer bound.",
    626          *badIndex);
    627      return nullptr;
    628    }
    629  }
    630 
    631  const auto& activeAttribs = active.activeAttribs;
    632 
    633  webgl::CachedDrawFetchLimits fetchLimits;
    634  fetchLimits.usedBuffers =
    635      std::move(mScratchFetchLimits.usedBuffers);  // Avoid realloc.
    636  fetchLimits.usedBuffers.clear();
    637  fetchLimits.usedBuffers.reserve(activeAttribs.size());
    638 
    639  bool hasActiveAttrib = false;
    640  bool hasActiveDivisor0 = false;
    641 
    642  for (const auto& progAttrib : activeAttribs) {
    643    const auto& loc = progAttrib.location;
    644    if (loc == -1) continue;
    645    hasActiveAttrib |= true;
    646 
    647    const auto& binding = vao->AttribBinding(loc);
    648    const auto& buffer = binding.buffer;
    649    const auto& layout = binding.layout;
    650    hasActiveDivisor0 |= (layout.divisor == 0);
    651 
    652    webgl::AttribBaseType attribDataBaseType;
    653    if (layout.isArray) {
    654      MOZ_ASSERT(buffer);
    655      fetchLimits.usedBuffers.push_back(
    656          {buffer.get(), static_cast<uint32_t>(loc)});
    657 
    658      attribDataBaseType = layout.baseType;
    659 
    660      const auto availBytes = buffer->ByteLength();
    661      const auto availElems = AvailGroups(availBytes, layout.byteOffset,
    662                                          layout.byteSize, layout.byteStride);
    663      if (layout.divisor) {
    664        const auto availInstances =
    665            CheckedInt<uint64_t>(availElems) * layout.divisor;
    666        if (availInstances.isValid()) {
    667          fetchLimits.maxInstances =
    668              std::min(fetchLimits.maxInstances, availInstances.value());
    669        }  // If not valid, it overflowed too large, so we're super safe.
    670      } else {
    671        fetchLimits.maxVerts = std::min(fetchLimits.maxVerts, availElems);
    672      }
    673    } else {
    674      attribDataBaseType = webgl->mGenericVertexAttribTypes[loc];
    675    }
    676 
    677    const auto& progBaseType = progAttrib.baseType;
    678    if ((attribDataBaseType != progBaseType) &&
    679        (progBaseType != webgl::AttribBaseType::Boolean)) {
    680      const auto& dataType = ToString(attribDataBaseType);
    681      const auto& progType = ToString(progBaseType);
    682      webgl->ErrorInvalidOperation(
    683          "Vertex attrib %u requires data of type %s,"
    684          " but is being supplied with type %s.",
    685          loc, progType, dataType);
    686      return nullptr;
    687    }
    688  }
    689 
    690  if (!webgl->IsWebGL2() && hasActiveAttrib && !hasActiveDivisor0) {
    691    webgl->ErrorInvalidOperation(
    692        "One active vertex attrib (if any are active)"
    693        " must have a divisor of 0.");
    694    return nullptr;
    695  }
    696 
    697  // -
    698 
    699  mScratchFetchLimits = std::move(fetchLimits);
    700  return &mScratchFetchLimits;
    701 }
    702 
    703 ////////////////////////////////////////////////////////////////////////////////
    704 // WebGLProgram
    705 
    706 WebGLProgram::WebGLProgram(WebGLContext* webgl)
    707    : WebGLContextBoundObject(webgl),
    708      mGLName(webgl->gl->fCreateProgram()),
    709      mNumActiveTFOs(0),
    710      mNextLink_TransformFeedbackBufferMode(LOCAL_GL_INTERLEAVED_ATTRIBS) {}
    711 
    712 WebGLProgram::~WebGLProgram() {
    713  mVertShader = nullptr;
    714  mFragShader = nullptr;
    715 
    716  mMostRecentLinkInfo = nullptr;
    717 
    718  if (!mContext) return;
    719  mContext->gl->fDeleteProgram(mGLName);
    720 }
    721 
    722 ////////////////////////////////////////////////////////////////////////////////
    723 // GL funcs
    724 
    725 void WebGLProgram::AttachShader(WebGLShader& shader) {
    726  RefPtr<WebGLShader>* shaderSlot = nullptr;
    727  switch (shader.mType) {
    728    case LOCAL_GL_VERTEX_SHADER:
    729      shaderSlot = &mVertShader;
    730      break;
    731    case LOCAL_GL_FRAGMENT_SHADER:
    732      shaderSlot = &mFragShader;
    733      break;
    734  }
    735  MOZ_ASSERT(shaderSlot);
    736 
    737  *shaderSlot = &shader;
    738 
    739  mContext->gl->fAttachShader(mGLName, shader.mGLName);
    740 }
    741 
    742 void WebGLProgram::BindAttribLocation(GLuint loc, const std::string& name) {
    743  const auto err = CheckGLSLVariableName(mContext->IsWebGL2(), name);
    744  if (err) {
    745    mContext->GenerateError(err->type, "%s", err->info.c_str());
    746    return;
    747  }
    748 
    749  if (loc >= mContext->MaxVertexAttribs()) {
    750    mContext->ErrorInvalidValue(
    751        "`location` must be less than"
    752        " MAX_VERTEX_ATTRIBS.");
    753    return;
    754  }
    755 
    756  if (name.find("gl_") == 0) {
    757    mContext->ErrorInvalidOperation(
    758        "Can't set the location of a"
    759        " name that starts with 'gl_'.");
    760    return;
    761  }
    762 
    763  auto res = mNextLink_BoundAttribLocs.insert({name, loc});
    764 
    765  const auto& wasInserted = res.second;
    766  if (!wasInserted) {
    767    const auto& itr = res.first;
    768    itr->second = loc;
    769  }
    770 }
    771 
    772 void WebGLProgram::DetachShader(const WebGLShader& shader) {
    773  RefPtr<WebGLShader>* shaderSlot = nullptr;
    774  switch (shader.mType) {
    775    case LOCAL_GL_VERTEX_SHADER:
    776      shaderSlot = &mVertShader;
    777      break;
    778    case LOCAL_GL_FRAGMENT_SHADER:
    779      shaderSlot = &mFragShader;
    780      break;
    781  }
    782  MOZ_ASSERT(shaderSlot);
    783 
    784  if (*shaderSlot != &shader) return;
    785 
    786  *shaderSlot = nullptr;
    787 
    788  mContext->gl->fDetachShader(mGLName, shader.mGLName);
    789 }
    790 
    791 void WebGLProgram::UniformBlockBinding(GLuint uniformBlockIndex,
    792                                       GLuint uniformBlockBinding) const {
    793  if (!IsLinked()) {
    794    mContext->ErrorInvalidOperation("`program` must be linked.");
    795    return;
    796  }
    797 
    798  auto& uniformBlocks = LinkInfo()->uniformBlocks;
    799  if (uniformBlockIndex >= uniformBlocks.size()) {
    800    mContext->ErrorInvalidValue("Index %u invalid.", uniformBlockIndex);
    801    return;
    802  }
    803  auto& uniformBlock = uniformBlocks[uniformBlockIndex];
    804 
    805  const auto& indexedBindings = mContext->mIndexedUniformBufferBindings;
    806  if (uniformBlockBinding >= indexedBindings.size()) {
    807    mContext->ErrorInvalidValue("Binding %u invalid.", uniformBlockBinding);
    808    return;
    809  }
    810  const auto& indexedBinding = indexedBindings[uniformBlockBinding];
    811 
    812  ////
    813 
    814  gl::GLContext* gl = mContext->GL();
    815  gl->fUniformBlockBinding(mGLName, uniformBlockIndex, uniformBlockBinding);
    816 
    817  ////
    818 
    819  uniformBlock.binding = &indexedBinding;
    820 }
    821 
    822 bool WebGLProgram::ValidateForLink() {
    823  const auto AppendCompileLog = [&](const WebGLShader* const shader) {
    824    if (!shader) {
    825      mLinkLog += " Missing shader.";
    826      return;
    827    }
    828    mLinkLog += "\nSHADER_INFO_LOG:\n";
    829    mLinkLog += shader->CompileLog();
    830  };
    831 
    832  if (!mVertShader || !mVertShader->IsCompiled()) {
    833    mLinkLog = "Must have a compiled vertex shader attached:";
    834    AppendCompileLog(mVertShader);
    835    return false;
    836  }
    837  const auto& vertInfo = *mVertShader->CompileResults();
    838 
    839  if (!mFragShader || !mFragShader->IsCompiled()) {
    840    mLinkLog = "Must have a compiled fragment shader attached:";
    841    AppendCompileLog(mFragShader);
    842    return false;
    843  }
    844  const auto& fragInfo = *mFragShader->CompileResults();
    845 
    846  nsCString errInfo;
    847  if (!fragInfo.CanLinkTo(vertInfo, &errInfo)) {
    848    mLinkLog = errInfo.BeginReading();
    849    return false;
    850  }
    851 
    852  const auto& gl = mContext->gl;
    853 
    854  if (gl->WorkAroundDriverBugs() && mContext->mIsMesa) {
    855    // Bug 1203135: Mesa crashes internally if we exceed the reported maximum
    856    // attribute count.
    857    if (mVertShader->NumAttributes() > mContext->MaxVertexAttribs()) {
    858      mLinkLog =
    859          "Number of attributes exceeds Mesa's reported max"
    860          " attribute count.";
    861      return false;
    862    }
    863  }
    864 
    865  return true;
    866 }
    867 
    868 void WebGLProgram::LinkProgram() {
    869  if (mNumActiveTFOs) {
    870    mContext->ErrorInvalidOperation(
    871        "Program is in-use by one or more active"
    872        " transform feedback objects.");
    873    return;
    874  }
    875 
    876  // as some of the validation changes program state
    877 
    878  mLinkLog = {};
    879  mMostRecentLinkInfo = nullptr;
    880 
    881  if (!ValidateForLink()) {
    882    mContext->GenerateWarning("%s", mLinkLog.c_str());
    883    return;
    884  }
    885 
    886  // Bind the attrib locations.
    887  // This can't be done trivially, because we have to deal with mapped attrib
    888  // names.
    889  for (const auto& pair : mNextLink_BoundAttribLocs) {
    890    const auto& name = pair.first;
    891    const auto& index = pair.second;
    892 
    893    mVertShader->BindAttribLocation(mGLName, name, index);
    894  }
    895 
    896  // Storage for transform feedback varyings before link.
    897  // (Work around for bug seen on nVidia drivers.)
    898  std::vector<std::string> scopedMappedTFVaryings;
    899 
    900  if (mContext->IsWebGL2()) {
    901    mVertShader->MapTransformFeedbackVaryings(
    902        mNextLink_TransformFeedbackVaryings, &scopedMappedTFVaryings);
    903 
    904    std::vector<const char*> driverVaryings;
    905    driverVaryings.reserve(scopedMappedTFVaryings.size());
    906    for (const auto& cur : scopedMappedTFVaryings) {
    907      driverVaryings.push_back(cur.c_str());
    908    }
    909 
    910    mContext->gl->fTransformFeedbackVaryings(
    911        mGLName, driverVaryings.size(), driverVaryings.data(),
    912        mNextLink_TransformFeedbackBufferMode);
    913  }
    914 
    915  LinkAndUpdate();
    916 
    917  if (mMostRecentLinkInfo) {
    918    std::string postLinkLog;
    919    if (ValidateAfterTentativeLink(&postLinkLog)) return;
    920 
    921    mMostRecentLinkInfo = nullptr;
    922    mLinkLog = std::move(postLinkLog);
    923  }
    924 
    925  // Failed link.
    926  if (mContext->ShouldGenerateWarnings()) {
    927    // report shader/program infoLogs as warnings.
    928    // note that shader compilation errors can be deferred to linkProgram,
    929    // which is why we can't do anything in compileShader. In practice we could
    930    // report in compileShader the translation errors generated by ANGLE,
    931    // but it seems saner to keep a single way of obtaining shader infologs.
    932    if (!mLinkLog.empty()) {
    933      mContext->GenerateWarning(
    934          "Failed to link, leaving the following"
    935          " log:\n%s\n",
    936          mLinkLog.c_str());
    937    }
    938  }
    939 }
    940 
    941 static uint8_t NumUsedLocationsByElemType(GLenum elemType) {
    942  // GLES 3.0.4 p55
    943 
    944  switch (elemType) {
    945    case LOCAL_GL_FLOAT_MAT2:
    946    case LOCAL_GL_FLOAT_MAT2x3:
    947    case LOCAL_GL_FLOAT_MAT2x4:
    948      return 2;
    949 
    950    case LOCAL_GL_FLOAT_MAT3x2:
    951    case LOCAL_GL_FLOAT_MAT3:
    952    case LOCAL_GL_FLOAT_MAT3x4:
    953      return 3;
    954 
    955    case LOCAL_GL_FLOAT_MAT4x2:
    956    case LOCAL_GL_FLOAT_MAT4x3:
    957    case LOCAL_GL_FLOAT_MAT4:
    958      return 4;
    959 
    960    default:
    961      return 1;
    962  }
    963 }
    964 
    965 uint8_t ElemTypeComponents(const GLenum elemType) {
    966  switch (elemType) {
    967    case LOCAL_GL_BOOL:
    968    case LOCAL_GL_FLOAT:
    969    case LOCAL_GL_INT:
    970    case LOCAL_GL_UNSIGNED_INT:
    971    case LOCAL_GL_SAMPLER_2D:
    972    case LOCAL_GL_SAMPLER_3D:
    973    case LOCAL_GL_SAMPLER_CUBE:
    974    case LOCAL_GL_SAMPLER_2D_SHADOW:
    975    case LOCAL_GL_SAMPLER_2D_ARRAY:
    976    case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
    977    case LOCAL_GL_SAMPLER_CUBE_SHADOW:
    978    case LOCAL_GL_INT_SAMPLER_2D:
    979    case LOCAL_GL_INT_SAMPLER_3D:
    980    case LOCAL_GL_INT_SAMPLER_CUBE:
    981    case LOCAL_GL_INT_SAMPLER_2D_ARRAY:
    982    case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D:
    983    case LOCAL_GL_UNSIGNED_INT_SAMPLER_3D:
    984    case LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE:
    985    case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
    986      return 1;
    987 
    988    case LOCAL_GL_BOOL_VEC2:
    989    case LOCAL_GL_FLOAT_VEC2:
    990    case LOCAL_GL_INT_VEC2:
    991    case LOCAL_GL_UNSIGNED_INT_VEC2:
    992      return 2;
    993 
    994    case LOCAL_GL_BOOL_VEC3:
    995    case LOCAL_GL_FLOAT_VEC3:
    996    case LOCAL_GL_INT_VEC3:
    997    case LOCAL_GL_UNSIGNED_INT_VEC3:
    998      return 3;
    999 
   1000    case LOCAL_GL_BOOL_VEC4:
   1001    case LOCAL_GL_FLOAT_VEC4:
   1002    case LOCAL_GL_INT_VEC4:
   1003    case LOCAL_GL_UNSIGNED_INT_VEC4:
   1004    case LOCAL_GL_FLOAT_MAT2:
   1005      return 4;
   1006 
   1007    case LOCAL_GL_FLOAT_MAT2x3:
   1008    case LOCAL_GL_FLOAT_MAT3x2:
   1009      return 2 * 3;
   1010 
   1011    case LOCAL_GL_FLOAT_MAT2x4:
   1012    case LOCAL_GL_FLOAT_MAT4x2:
   1013      return 2 * 4;
   1014 
   1015    case LOCAL_GL_FLOAT_MAT3:
   1016      return 3 * 3;
   1017 
   1018    case LOCAL_GL_FLOAT_MAT3x4:
   1019    case LOCAL_GL_FLOAT_MAT4x3:
   1020      return 3 * 4;
   1021 
   1022    case LOCAL_GL_FLOAT_MAT4:
   1023      return 4 * 4;
   1024 
   1025    default:
   1026      return 0;
   1027  }
   1028 }
   1029 
   1030 bool WebGLProgram::ValidateAfterTentativeLink(
   1031    std::string* const out_linkLog) const {
   1032  const auto& linkInfo = mMostRecentLinkInfo;
   1033  const auto& gl = mContext->gl;
   1034 
   1035  // Check for overlapping attrib locations.
   1036  {
   1037    std::unordered_map<uint32_t, const std::string&> nameByLoc;
   1038    for (const auto& attrib : linkInfo->active.activeAttribs) {
   1039      if (attrib.location == -1) continue;
   1040 
   1041      const auto& elemType = attrib.elemType;
   1042      const auto numUsedLocs = NumUsedLocationsByElemType(elemType);
   1043      for (uint32_t i = 0; i < numUsedLocs; i++) {
   1044        const uint32_t usedLoc = attrib.location + i;
   1045 
   1046        const auto res = nameByLoc.insert({usedLoc, attrib.name});
   1047        const bool& didInsert = res.second;
   1048        if (!didInsert) {
   1049          const auto& aliasingName = attrib.name;
   1050          const auto& itrExisting = res.first;
   1051          const auto& existingName = itrExisting->second;
   1052          *out_linkLog = nsPrintfCString(
   1053                             "Attrib \"%s\" aliases locations used by"
   1054                             " attrib \"%s\".",
   1055                             aliasingName.c_str(), existingName.c_str())
   1056                             .BeginReading();
   1057          return false;
   1058        }
   1059      }
   1060    }
   1061  }
   1062 
   1063  // Forbid too many components for specified buffer mode
   1064  const auto& activeTfVaryings = linkInfo->active.activeTfVaryings;
   1065  MOZ_ASSERT(mNextLink_TransformFeedbackVaryings.size() ==
   1066             activeTfVaryings.size());
   1067  if (!activeTfVaryings.empty()) {
   1068    GLuint maxComponentsPerIndex = 0;
   1069    switch (linkInfo->transformFeedbackBufferMode) {
   1070      case LOCAL_GL_INTERLEAVED_ATTRIBS:
   1071        gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS,
   1072                         &maxComponentsPerIndex);
   1073        break;
   1074 
   1075      case LOCAL_GL_SEPARATE_ATTRIBS:
   1076        gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS,
   1077                         &maxComponentsPerIndex);
   1078        break;
   1079 
   1080      default:
   1081        MOZ_CRASH("`bufferMode`");
   1082    }
   1083 
   1084    std::vector<size_t> componentsPerVert;
   1085    for (const auto& cur : activeTfVaryings) {
   1086      if (componentsPerVert.empty() ||
   1087          linkInfo->transformFeedbackBufferMode == LOCAL_GL_SEPARATE_ATTRIBS) {
   1088        componentsPerVert.push_back(0);
   1089      }
   1090 
   1091      size_t varyingComponents = ElemTypeComponents(cur.elemType);
   1092      MOZ_ASSERT(varyingComponents);
   1093      varyingComponents *= cur.elemCount;
   1094 
   1095      auto& totalComponentsForIndex = *(componentsPerVert.rbegin());
   1096      totalComponentsForIndex += varyingComponents;
   1097 
   1098      if (totalComponentsForIndex > maxComponentsPerIndex) {
   1099        *out_linkLog = nsPrintfCString(
   1100                           "Transform feedback varying \"%s\""
   1101                           " pushed `componentsForIndex` over the"
   1102                           " limit of %u.",
   1103                           cur.name.c_str(), maxComponentsPerIndex)
   1104                           .BeginReading();
   1105        return false;
   1106      }
   1107    }
   1108 
   1109    linkInfo->componentsPerTFVert = std::move(componentsPerVert);
   1110  }
   1111 
   1112  return true;
   1113 }
   1114 
   1115 bool WebGLProgram::UseProgram() const {
   1116  if (!mMostRecentLinkInfo) {
   1117    mContext->ErrorInvalidOperation(
   1118        "Program has not been successfully linked.");
   1119    return false;
   1120  }
   1121 
   1122  if (mContext->mBoundTransformFeedback &&
   1123      mContext->mBoundTransformFeedback->mIsActive &&
   1124      !mContext->mBoundTransformFeedback->mIsPaused) {
   1125    mContext->ErrorInvalidOperation(
   1126        "Transform feedback active and not paused.");
   1127    return false;
   1128  }
   1129 
   1130  mContext->gl->fUseProgram(mGLName);
   1131  return true;
   1132 }
   1133 
   1134 bool WebGLProgram::ValidateProgram() const {
   1135  gl::GLContext* gl = mContext->gl;
   1136 
   1137 #ifdef XP_MACOSX
   1138  // See bug 593867 for NVIDIA and bug 657201 for ATI. The latter is confirmed
   1139  // with Mac OS 10.6.7.
   1140  if (gl->WorkAroundDriverBugs()) {
   1141    mContext->GenerateWarning(
   1142        "Implemented as a no-op on"
   1143        " Mac to work around crashes.");
   1144    return true;
   1145  }
   1146 #endif
   1147 
   1148  gl->fValidateProgram(mGLName);
   1149  GLint ok = 0;
   1150  gl->fGetProgramiv(mGLName, LOCAL_GL_VALIDATE_STATUS, &ok);
   1151  return bool(ok);
   1152 }
   1153 
   1154 ////////////////////////////////////////////////////////////////////////////////
   1155 
   1156 void WebGLProgram::LinkAndUpdate() {
   1157  mMostRecentLinkInfo = nullptr;
   1158 
   1159  gl::GLContext* gl = mContext->gl;
   1160  gl->fLinkProgram(mGLName);
   1161 
   1162  // Grab the program log.
   1163  {
   1164    GLuint logLenWithNull = 0;
   1165    gl->fGetProgramiv(mGLName, LOCAL_GL_INFO_LOG_LENGTH,
   1166                      (GLint*)&logLenWithNull);
   1167    if (logLenWithNull > 1) {
   1168      std::vector<char> buffer(logLenWithNull);
   1169      gl->fGetProgramInfoLog(mGLName, buffer.size(), nullptr, buffer.data());
   1170      mLinkLog = buffer.data();
   1171    } else {
   1172      mLinkLog.clear();
   1173    }
   1174  }
   1175 
   1176  GLint ok = 0;
   1177  gl->fGetProgramiv(mGLName, LOCAL_GL_LINK_STATUS, &ok);
   1178  if (!ok) return;
   1179 
   1180  mMostRecentLinkInfo =
   1181      QueryProgramInfo(this, gl);  // Fallible after context loss.
   1182 }
   1183 
   1184 void WebGLProgram::TransformFeedbackVaryings(
   1185    const std::vector<std::string>& varyings, GLenum bufferMode) {
   1186  const auto& gl = mContext->gl;
   1187 
   1188  switch (bufferMode) {
   1189    case LOCAL_GL_INTERLEAVED_ATTRIBS:
   1190      break;
   1191 
   1192    case LOCAL_GL_SEPARATE_ATTRIBS: {
   1193      GLuint maxAttribs = 0;
   1194      gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
   1195                       &maxAttribs);
   1196      if (varyings.size() > maxAttribs) {
   1197        mContext->ErrorInvalidValue("Length of `varyings` exceeds %s.",
   1198                                    "TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS");
   1199        return;
   1200      }
   1201    } break;
   1202 
   1203    default:
   1204      mContext->ErrorInvalidEnumInfo("bufferMode", bufferMode);
   1205      return;
   1206  }
   1207 
   1208  ////
   1209 
   1210  mNextLink_TransformFeedbackVaryings = varyings;
   1211  mNextLink_TransformFeedbackBufferMode = bufferMode;
   1212 }
   1213 
   1214 }  // namespace mozilla