LCOV - code coverage report
Current view: top level - dom/canvas - WebGLProgram.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 762 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 56 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       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 "mozilla/CheckedInt.h"
      10             : #include "mozilla/dom/WebGL2RenderingContextBinding.h"
      11             : #include "mozilla/dom/WebGLRenderingContextBinding.h"
      12             : #include "mozilla/RefPtr.h"
      13             : #include "mozilla/SizePrintfMacros.h"
      14             : #include "nsPrintfCString.h"
      15             : #include "WebGLActiveInfo.h"
      16             : #include "WebGLContext.h"
      17             : #include "WebGLShader.h"
      18             : #include "WebGLTransformFeedback.h"
      19             : #include "WebGLUniformLocation.h"
      20             : #include "WebGLValidateStrings.h"
      21             : 
      22             : namespace mozilla {
      23             : 
      24             : /* If `name`: "foo[3]"
      25             :  * Then returns true, with
      26             :  *     `out_baseName`: "foo"
      27             :  *     `out_isArray`: true
      28             :  *     `out_index`: 3
      29             :  *
      30             :  * If `name`: "foo"
      31             :  * Then returns true, with
      32             :  *     `out_baseName`: "foo"
      33             :  *     `out_isArray`: false
      34             :  *     `out_index`: 0
      35             :  */
      36             : static bool
      37           0 : ParseName(const nsCString& name, nsCString* const out_baseName,
      38             :           bool* const out_isArray, size_t* const out_arrayIndex)
      39             : {
      40           0 :     int32_t indexEnd = name.RFind("]");
      41           0 :     if (indexEnd == -1 ||
      42           0 :         (uint32_t)indexEnd != name.Length() - 1)
      43             :     {
      44           0 :         *out_baseName = name;
      45           0 :         *out_isArray = false;
      46           0 :         *out_arrayIndex = 0;
      47           0 :         return true;
      48             :     }
      49             : 
      50           0 :     int32_t indexOpenBracket = name.RFind("[");
      51           0 :     if (indexOpenBracket == -1)
      52           0 :         return false;
      53             : 
      54           0 :     uint32_t indexStart = indexOpenBracket + 1;
      55           0 :     uint32_t indexLen = indexEnd - indexStart;
      56           0 :     if (indexLen == 0)
      57           0 :         return false;
      58             : 
      59           0 :     const nsAutoCString indexStr(Substring(name, indexStart, indexLen));
      60             : 
      61             :     nsresult errorcode;
      62           0 :     int32_t indexNum = indexStr.ToInteger(&errorcode);
      63           0 :     if (NS_FAILED(errorcode))
      64           0 :         return false;
      65             : 
      66           0 :     if (indexNum < 0)
      67           0 :         return false;
      68             : 
      69           0 :     *out_baseName = StringHead(name, indexOpenBracket);
      70           0 :     *out_isArray = true;
      71           0 :     *out_arrayIndex = indexNum;
      72           0 :     return true;
      73             : }
      74             : 
      75             : static void
      76           0 : AssembleName(const nsCString& baseName, bool isArray, size_t arrayIndex,
      77             :              nsCString* const out_name)
      78             : {
      79           0 :     *out_name = baseName;
      80           0 :     if (isArray) {
      81           0 :         out_name->Append('[');
      82           0 :         out_name->AppendInt(uint64_t(arrayIndex));
      83           0 :         out_name->Append(']');
      84             :     }
      85           0 : }
      86             : 
      87             : ////
      88             : 
      89             : static GLenum
      90           0 : AttribBaseType(GLenum attribType)
      91             : {
      92           0 :     switch (attribType) {
      93             :     case LOCAL_GL_FLOAT:
      94             :     case LOCAL_GL_FLOAT_VEC2:
      95             :     case LOCAL_GL_FLOAT_VEC3:
      96             :     case LOCAL_GL_FLOAT_VEC4:
      97             : 
      98             :     case LOCAL_GL_FLOAT_MAT2:
      99             :     case LOCAL_GL_FLOAT_MAT2x3:
     100             :     case LOCAL_GL_FLOAT_MAT2x4:
     101             : 
     102             :     case LOCAL_GL_FLOAT_MAT3x2:
     103             :     case LOCAL_GL_FLOAT_MAT3:
     104             :     case LOCAL_GL_FLOAT_MAT3x4:
     105             : 
     106             :     case LOCAL_GL_FLOAT_MAT4x2:
     107             :     case LOCAL_GL_FLOAT_MAT4x3:
     108             :     case LOCAL_GL_FLOAT_MAT4:
     109           0 :         return LOCAL_GL_FLOAT;
     110             : 
     111             :     case LOCAL_GL_INT:
     112             :     case LOCAL_GL_INT_VEC2:
     113             :     case LOCAL_GL_INT_VEC3:
     114             :     case LOCAL_GL_INT_VEC4:
     115           0 :         return LOCAL_GL_INT;
     116             : 
     117             :     case LOCAL_GL_UNSIGNED_INT:
     118             :     case LOCAL_GL_UNSIGNED_INT_VEC2:
     119             :     case LOCAL_GL_UNSIGNED_INT_VEC3:
     120             :     case LOCAL_GL_UNSIGNED_INT_VEC4:
     121           0 :         return LOCAL_GL_UNSIGNED_INT;
     122             : 
     123             :     default:
     124           0 :         MOZ_ASSERT(false, "unexpected attrib elemType");
     125             :         return 0;
     126             :     }
     127             : }
     128             : 
     129             : ////
     130             : 
     131             : /*static*/ const webgl::UniformInfo::TexListT*
     132           0 : webgl::UniformInfo::GetTexList(WebGLActiveInfo* activeInfo)
     133             : {
     134           0 :     const auto& webgl = activeInfo->mWebGL;
     135             : 
     136           0 :     switch (activeInfo->mElemType) {
     137             :     case LOCAL_GL_SAMPLER_2D:
     138             :     case LOCAL_GL_SAMPLER_2D_SHADOW:
     139             :     case LOCAL_GL_INT_SAMPLER_2D:
     140             :     case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D:
     141           0 :         return &webgl->mBound2DTextures;
     142             : 
     143             :     case LOCAL_GL_SAMPLER_CUBE:
     144             :     case LOCAL_GL_SAMPLER_CUBE_SHADOW:
     145             :     case LOCAL_GL_INT_SAMPLER_CUBE:
     146             :     case LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE:
     147           0 :         return &webgl->mBoundCubeMapTextures;
     148             : 
     149             :     case LOCAL_GL_SAMPLER_3D:
     150             :     case LOCAL_GL_INT_SAMPLER_3D:
     151             :     case LOCAL_GL_UNSIGNED_INT_SAMPLER_3D:
     152           0 :         return &webgl->mBound3DTextures;
     153             : 
     154             :     case LOCAL_GL_SAMPLER_2D_ARRAY:
     155             :     case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
     156             :     case LOCAL_GL_INT_SAMPLER_2D_ARRAY:
     157             :     case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
     158           0 :         return &webgl->mBound2DArrayTextures;
     159             : 
     160             :     default:
     161           0 :         return nullptr;
     162             :     }
     163             : }
     164             : 
     165           0 : webgl::UniformInfo::UniformInfo(WebGLActiveInfo* activeInfo)
     166             :     : mActiveInfo(activeInfo)
     167           0 :     , mSamplerTexList(GetTexList(activeInfo))
     168             : {
     169           0 :     if (mSamplerTexList) {
     170           0 :         mSamplerValues.assign(mActiveInfo->mElemCount, 0);
     171             :     }
     172           0 : }
     173             : 
     174             : //////////
     175             : 
     176             : //#define DUMP_SHADERVAR_MAPPINGS
     177             : 
     178             : static already_AddRefed<const webgl::LinkedProgramInfo>
     179           0 : QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
     180             : {
     181           0 :     WebGLContext* const webgl = prog->mContext;
     182             : 
     183           0 :     RefPtr<webgl::LinkedProgramInfo> info(new webgl::LinkedProgramInfo(prog));
     184             : 
     185           0 :     GLuint maxAttribLenWithNull = 0;
     186           0 :     gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_ATTRIBUTE_MAX_LENGTH,
     187           0 :                       (GLint*)&maxAttribLenWithNull);
     188           0 :     if (maxAttribLenWithNull < 1)
     189           0 :         maxAttribLenWithNull = 1;
     190             : 
     191           0 :     GLuint maxUniformLenWithNull = 0;
     192           0 :     gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH,
     193           0 :                       (GLint*)&maxUniformLenWithNull);
     194           0 :     if (maxUniformLenWithNull < 1)
     195           0 :         maxUniformLenWithNull = 1;
     196             : 
     197           0 :     GLuint maxUniformBlockLenWithNull = 0;
     198           0 :     if (gl->IsSupported(gl::GLFeature::uniform_buffer_object)) {
     199           0 :         gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH,
     200           0 :                           (GLint*)&maxUniformBlockLenWithNull);
     201           0 :         if (maxUniformBlockLenWithNull < 1)
     202           0 :             maxUniformBlockLenWithNull = 1;
     203             :     }
     204             : 
     205           0 :     GLuint maxTransformFeedbackVaryingLenWithNull = 0;
     206           0 :     if (gl->IsSupported(gl::GLFeature::transform_feedback2)) {
     207           0 :         gl->fGetProgramiv(prog->mGLName, LOCAL_GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH,
     208           0 :                           (GLint*)&maxTransformFeedbackVaryingLenWithNull);
     209           0 :         if (maxTransformFeedbackVaryingLenWithNull < 1)
     210           0 :             maxTransformFeedbackVaryingLenWithNull = 1;
     211             :     }
     212             : 
     213             :     // Attribs (can't be arrays)
     214             : 
     215           0 :     GLuint numActiveAttribs = 0;
     216           0 :     gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_ATTRIBUTES,
     217           0 :                       (GLint*)&numActiveAttribs);
     218             : 
     219           0 :     for (GLuint i = 0; i < numActiveAttribs; i++) {
     220           0 :         nsAutoCString mappedName;
     221           0 :         mappedName.SetLength(maxAttribLenWithNull - 1);
     222             : 
     223           0 :         GLsizei lengthWithoutNull = 0;
     224           0 :         GLint elemCount = 0; // `size`
     225           0 :         GLenum elemType = 0; // `type`
     226           0 :         gl->fGetActiveAttrib(prog->mGLName, i, mappedName.Length()+1, &lengthWithoutNull,
     227           0 :                              &elemCount, &elemType, mappedName.BeginWriting());
     228           0 :         GLenum error = gl->fGetError();
     229           0 :         if (error != LOCAL_GL_NO_ERROR) {
     230           0 :             gfxCriticalNote << "Failed to do glGetActiveAttrib: " << error;
     231             :         }
     232             : 
     233           0 :         mappedName.SetLength(lengthWithoutNull);
     234             : 
     235             :         ////
     236             : 
     237           0 :         nsCString userName;
     238           0 :         if (!prog->FindAttribUserNameByMappedName(mappedName, &userName)) {
     239           0 :             userName = mappedName;
     240             :         }
     241             : 
     242             :         ///////
     243             : 
     244           0 :         GLint loc = gl->fGetAttribLocation(prog->mGLName,
     245           0 :                                            mappedName.BeginReading());
     246           0 :         if (gl->WorkAroundDriverBugs() &&
     247           0 :             mappedName.EqualsIgnoreCase("gl_", 3))
     248             :         {
     249             :             // Bug 1328559: Appears problematic on ANGLE and OSX, but not Linux or Win+GL.
     250           0 :             loc = -1;
     251             :         }
     252             : #ifdef DUMP_SHADERVAR_MAPPINGS
     253             :         printf_stderr("[attrib %u/%u] @%i %s->%s\n", i, numActiveAttribs, loc,
     254             :                       userName.BeginReading(), mappedName.BeginReading());
     255             : #endif
     256           0 :         MOZ_ASSERT_IF(mappedName.EqualsIgnoreCase("gl_", 3), loc == -1);
     257             : 
     258             :         ///////
     259             : 
     260           0 :         const bool isArray = false;
     261             :         const RefPtr<WebGLActiveInfo> activeInfo = new WebGLActiveInfo(webgl, elemCount,
     262             :                                                                        elemType, isArray,
     263             :                                                                        userName,
     264           0 :                                                                        mappedName);
     265           0 :         const GLenum baseType = AttribBaseType(elemType);
     266           0 :         const webgl::AttribInfo attrib = {activeInfo, loc, baseType};
     267           0 :         info->attribs.push_back(attrib);
     268             :     }
     269             : 
     270             :     // Uniforms (can be basically anything)
     271             : 
     272           0 :     const bool needsCheckForArrays = gl->WorkAroundDriverBugs();
     273             : 
     274           0 :     GLuint numActiveUniforms = 0;
     275           0 :     gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_UNIFORMS,
     276           0 :                       (GLint*)&numActiveUniforms);
     277             : 
     278           0 :     for (GLuint i = 0; i < numActiveUniforms; i++) {
     279           0 :         nsAutoCString mappedName;
     280           0 :         mappedName.SetLength(maxUniformLenWithNull - 1);
     281             : 
     282           0 :         GLsizei lengthWithoutNull = 0;
     283           0 :         GLint elemCount = 0; // `size`
     284           0 :         GLenum elemType = 0; // `type`
     285           0 :         gl->fGetActiveUniform(prog->mGLName, i, mappedName.Length()+1, &lengthWithoutNull,
     286           0 :                               &elemCount, &elemType, mappedName.BeginWriting());
     287             : 
     288           0 :         mappedName.SetLength(lengthWithoutNull);
     289             : 
     290             :         ///////
     291             : 
     292           0 :         nsAutoCString baseMappedName;
     293             :         bool isArray;
     294             :         size_t arrayIndex;
     295           0 :         if (!ParseName(mappedName, &baseMappedName, &isArray, &arrayIndex))
     296           0 :             MOZ_CRASH("GFX: Failed to parse `mappedName` received from driver.");
     297             : 
     298             :         // Note that for good drivers, `isArray` should already be correct.
     299             :         // However, if FindUniform succeeds, it will be validator-guaranteed correct.
     300             : 
     301             :         ///////
     302             : 
     303           0 :         nsAutoCString baseUserName;
     304           0 :         if (!prog->FindUniformByMappedName(baseMappedName, &baseUserName, &isArray)) {
     305             :             // Validator likely missing.
     306           0 :             baseUserName = baseMappedName;
     307             : 
     308           0 :             if (needsCheckForArrays && !isArray) {
     309             :                 // By GLES 3, GetUniformLocation("foo[0]") should return -1 if `foo` is
     310             :                 // not an array. Our current linux Try slaves return the location of `foo`
     311             :                 // anyways, though.
     312           0 :                 std::string mappedNameStr = baseMappedName.BeginReading();
     313           0 :                 mappedNameStr += "[0]";
     314             : 
     315           0 :                 GLint loc = gl->fGetUniformLocation(prog->mGLName, mappedNameStr.c_str());
     316           0 :                 if (loc != -1)
     317           0 :                     isArray = true;
     318             :             }
     319             :         }
     320             : 
     321             :         ///////
     322             : 
     323             : #ifdef DUMP_SHADERVAR_MAPPINGS
     324             :         printf_stderr("[uniform %u/%u] %s->%s\n", i, numActiveUniforms,
     325             :                       baseUserName.BeginReading(), mappedName.BeginReading());
     326             : #endif
     327             : 
     328             :         ///////
     329             : 
     330             :         const RefPtr<WebGLActiveInfo> activeInfo = new WebGLActiveInfo(webgl, elemCount,
     331             :                                                                        elemType, isArray,
     332             :                                                                        baseUserName,
     333           0 :                                                                        baseMappedName);
     334             : 
     335           0 :         auto* uniform = new webgl::UniformInfo(activeInfo);
     336           0 :         info->uniforms.push_back(uniform);
     337             : 
     338           0 :         if (uniform->mSamplerTexList) {
     339           0 :             info->uniformSamplers.push_back(uniform);
     340             :         }
     341             :     }
     342             : 
     343             :     // Uniform Blocks (can be arrays, but can't contain sampler types)
     344             : 
     345           0 :     if (gl->IsSupported(gl::GLFeature::uniform_buffer_object)) {
     346           0 :         GLuint numActiveUniformBlocks = 0;
     347           0 :         gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_UNIFORM_BLOCKS,
     348           0 :                           (GLint*)&numActiveUniformBlocks);
     349             : 
     350           0 :         for (GLuint i = 0; i < numActiveUniformBlocks; i++) {
     351           0 :             nsAutoCString mappedName;
     352           0 :             mappedName.SetLength(maxUniformBlockLenWithNull - 1);
     353             : 
     354             :             GLint lengthWithoutNull;
     355           0 :             gl->fGetActiveUniformBlockiv(prog->mGLName, i, LOCAL_GL_UNIFORM_BLOCK_NAME_LENGTH, &lengthWithoutNull);
     356           0 :             gl->fGetActiveUniformBlockName(prog->mGLName, i, maxUniformBlockLenWithNull, &lengthWithoutNull, mappedName.BeginWriting());
     357           0 :             mappedName.SetLength(lengthWithoutNull);
     358             : 
     359             :             ////
     360             : 
     361           0 :             nsCString userName;
     362           0 :             if (!prog->UnmapUniformBlockName(mappedName, &userName))
     363           0 :                 continue;
     364             : 
     365             : #ifdef DUMP_SHADERVAR_MAPPINGS
     366             :             printf_stderr("[uniform block %u/%u] %s->%s\n", i, numActiveUniformBlocks,
     367             :                           userName.BeginReading(), mappedName.BeginReading());
     368             : #endif
     369             : 
     370             :             ////
     371             : 
     372           0 :             GLuint dataSize = 0;
     373           0 :             gl->fGetActiveUniformBlockiv(prog->mGLName, i,
     374             :                                          LOCAL_GL_UNIFORM_BLOCK_DATA_SIZE,
     375           0 :                                          (GLint*)&dataSize);
     376             : 
     377             : 
     378             :             auto* block = new webgl::UniformBlockInfo(webgl, userName, mappedName,
     379           0 :                                                       dataSize);
     380           0 :             info->uniformBlocks.push_back(block);
     381             :         }
     382             :     }
     383             : 
     384             :     // Transform feedback varyings (can be arrays)
     385             : 
     386           0 :     if (gl->IsSupported(gl::GLFeature::transform_feedback2)) {
     387           0 :         GLuint numTransformFeedbackVaryings = 0;
     388           0 :         gl->fGetProgramiv(prog->mGLName, LOCAL_GL_TRANSFORM_FEEDBACK_VARYINGS,
     389           0 :                           (GLint*)&numTransformFeedbackVaryings);
     390             : 
     391           0 :         for (GLuint i = 0; i < numTransformFeedbackVaryings; i++) {
     392           0 :             nsAutoCString mappedName;
     393           0 :             mappedName.SetLength(maxTransformFeedbackVaryingLenWithNull - 1);
     394             : 
     395             :             GLint lengthWithoutNull;
     396             :             GLsizei elemCount;
     397             :             GLenum elemType;
     398           0 :             gl->fGetTransformFeedbackVarying(prog->mGLName, i,
     399             :                                              maxTransformFeedbackVaryingLenWithNull,
     400             :                                              &lengthWithoutNull, &elemCount, &elemType,
     401           0 :                                              mappedName.BeginWriting());
     402           0 :             mappedName.SetLength(lengthWithoutNull);
     403             : 
     404             :             ////
     405             : 
     406           0 :             nsAutoCString baseMappedName;
     407             :             bool isArray;
     408             :             size_t arrayIndex;
     409           0 :             if (!ParseName(mappedName, &baseMappedName, &isArray, &arrayIndex))
     410           0 :                 MOZ_CRASH("GFX: Failed to parse `mappedName` received from driver.");
     411             : 
     412           0 :             nsAutoCString baseUserName;
     413           0 :             if (!prog->FindVaryingByMappedName(mappedName, &baseUserName, &isArray)) {
     414           0 :                 baseUserName = baseMappedName;
     415             :             }
     416             : 
     417             :             ////
     418             : 
     419             : #ifdef DUMP_SHADERVAR_MAPPINGS
     420             :             printf_stderr("[transform feedback varying %u/%u] %s->%s\n", i,
     421             :                           numTransformFeedbackVaryings, baseUserName.BeginReading(),
     422             :                           mappedName.BeginReading());
     423             : #endif
     424             : 
     425             :             const RefPtr<WebGLActiveInfo> activeInfo = new WebGLActiveInfo(webgl,
     426             :                                                                            elemCount,
     427             :                                                                            elemType,
     428             :                                                                            isArray,
     429             :                                                                            baseUserName,
     430           0 :                                                                            mappedName);
     431           0 :             info->transformFeedbackVaryings.push_back(activeInfo);
     432             :         }
     433             :     }
     434             : 
     435             :     // Frag outputs
     436             : 
     437           0 :     prog->EnumerateFragOutputs(info->fragDataMap);
     438             : 
     439           0 :     return info.forget();
     440             : }
     441             : 
     442             : ////////////////////////////////////////////////////////////////////////////////
     443             : 
     444           0 : webgl::LinkedProgramInfo::LinkedProgramInfo(WebGLProgram* prog)
     445             :     : prog(prog)
     446           0 :     , transformFeedbackBufferMode(prog->mNextLink_TransformFeedbackBufferMode)
     447           0 : { }
     448             : 
     449           0 : webgl::LinkedProgramInfo::~LinkedProgramInfo()
     450             : {
     451           0 :     for (auto& cur : uniforms) {
     452           0 :         delete cur;
     453             :     }
     454           0 :     for (auto& cur : uniformBlocks) {
     455           0 :         delete cur;
     456             :     }
     457           0 : }
     458             : 
     459             : ////////////////////////////////////////////////////////////////////////////////
     460             : // WebGLProgram
     461             : 
     462             : static GLuint
     463           0 : CreateProgram(gl::GLContext* gl)
     464             : {
     465           0 :     gl->MakeCurrent();
     466           0 :     return gl->fCreateProgram();
     467             : }
     468             : 
     469           0 : WebGLProgram::WebGLProgram(WebGLContext* webgl)
     470             :     : WebGLRefCountedObject(webgl)
     471           0 :     , mGLName(CreateProgram(webgl->GL()))
     472             :     , mNumActiveTFOs(0)
     473           0 :     , mNextLink_TransformFeedbackBufferMode(LOCAL_GL_INTERLEAVED_ATTRIBS)
     474             : {
     475           0 :     mContext->mPrograms.insertBack(this);
     476           0 : }
     477             : 
     478           0 : WebGLProgram::~WebGLProgram()
     479             : {
     480           0 :     DeleteOnce();
     481           0 : }
     482             : 
     483             : void
     484           0 : WebGLProgram::Delete()
     485             : {
     486           0 :     gl::GLContext* gl = mContext->GL();
     487             : 
     488           0 :     gl->MakeCurrent();
     489           0 :     gl->fDeleteProgram(mGLName);
     490             : 
     491           0 :     mVertShader = nullptr;
     492           0 :     mFragShader = nullptr;
     493             : 
     494           0 :     mMostRecentLinkInfo = nullptr;
     495             : 
     496           0 :     LinkedListElement<WebGLProgram>::removeFrom(mContext->mPrograms);
     497           0 : }
     498             : 
     499             : ////////////////////////////////////////////////////////////////////////////////
     500             : // GL funcs
     501             : 
     502             : void
     503           0 : WebGLProgram::AttachShader(WebGLShader* shader)
     504             : {
     505             :     WebGLRefPtr<WebGLShader>* shaderSlot;
     506           0 :     switch (shader->mType) {
     507             :     case LOCAL_GL_VERTEX_SHADER:
     508           0 :         shaderSlot = &mVertShader;
     509           0 :         break;
     510             :     case LOCAL_GL_FRAGMENT_SHADER:
     511           0 :         shaderSlot = &mFragShader;
     512           0 :         break;
     513             :     default:
     514           0 :         mContext->ErrorInvalidOperation("attachShader: Bad type for shader.");
     515           0 :         return;
     516             :     }
     517             : 
     518           0 :     if (*shaderSlot) {
     519           0 :         if (shader == *shaderSlot) {
     520           0 :             mContext->ErrorInvalidOperation("attachShader: `shader` is already attached.");
     521             :         } else {
     522           0 :             mContext->ErrorInvalidOperation("attachShader: Only one of each type of"
     523           0 :                                             " shader may be attached to a program.");
     524             :         }
     525           0 :         return;
     526             :     }
     527             : 
     528           0 :     *shaderSlot = shader;
     529             : 
     530           0 :     mContext->MakeContextCurrent();
     531           0 :     mContext->gl->fAttachShader(mGLName, shader->mGLName);
     532             : }
     533             : 
     534             : void
     535           0 : WebGLProgram::BindAttribLocation(GLuint loc, const nsAString& name)
     536             : {
     537           0 :     if (!ValidateGLSLVariableName(name, mContext, "bindAttribLocation"))
     538           0 :         return;
     539             : 
     540           0 :     if (loc >= mContext->MaxVertexAttribs()) {
     541           0 :         mContext->ErrorInvalidValue("bindAttribLocation: `location` must be less than"
     542           0 :                                     " MAX_VERTEX_ATTRIBS.");
     543           0 :         return;
     544             :     }
     545             : 
     546           0 :     if (StringBeginsWith(name, NS_LITERAL_STRING("gl_"))) {
     547           0 :         mContext->ErrorInvalidOperation("bindAttribLocation: Can't set the location of a"
     548           0 :                                         " name that starts with 'gl_'.");
     549           0 :         return;
     550             :     }
     551             : 
     552           0 :     NS_LossyConvertUTF16toASCII asciiName(name);
     553             : 
     554           0 :     auto res = mNextLink_BoundAttribLocs.insert({asciiName, loc});
     555             : 
     556           0 :     const bool wasInserted = res.second;
     557           0 :     if (!wasInserted) {
     558           0 :         auto itr = res.first;
     559           0 :         itr->second = loc;
     560             :     }
     561             : }
     562             : 
     563             : void
     564           0 : WebGLProgram::DetachShader(const WebGLShader* shader)
     565             : {
     566           0 :     MOZ_ASSERT(shader);
     567             : 
     568             :     WebGLRefPtr<WebGLShader>* shaderSlot;
     569           0 :     switch (shader->mType) {
     570             :     case LOCAL_GL_VERTEX_SHADER:
     571           0 :         shaderSlot = &mVertShader;
     572           0 :         break;
     573             :     case LOCAL_GL_FRAGMENT_SHADER:
     574           0 :         shaderSlot = &mFragShader;
     575           0 :         break;
     576             :     default:
     577           0 :         mContext->ErrorInvalidOperation("attachShader: Bad type for shader.");
     578           0 :         return;
     579             :     }
     580             : 
     581           0 :     if (*shaderSlot != shader) {
     582           0 :         mContext->ErrorInvalidOperation("detachShader: `shader` is not attached.");
     583           0 :         return;
     584             :     }
     585             : 
     586           0 :     *shaderSlot = nullptr;
     587             : 
     588           0 :     mContext->MakeContextCurrent();
     589           0 :     mContext->gl->fDetachShader(mGLName, shader->mGLName);
     590             : }
     591             : 
     592             : already_AddRefed<WebGLActiveInfo>
     593           0 : WebGLProgram::GetActiveAttrib(GLuint index) const
     594             : {
     595           0 :     if (!mMostRecentLinkInfo) {
     596           0 :         RefPtr<WebGLActiveInfo> ret = WebGLActiveInfo::CreateInvalid(mContext);
     597           0 :         return ret.forget();
     598             :     }
     599             : 
     600           0 :     const auto& attribs = mMostRecentLinkInfo->attribs;
     601             : 
     602           0 :     if (index >= attribs.size()) {
     603           0 :         mContext->ErrorInvalidValue("`index` (%i) must be less than %s (%" PRIuSIZE ").",
     604           0 :                                     index, "ACTIVE_ATTRIBS", attribs.size());
     605           0 :         return nullptr;
     606             :     }
     607             : 
     608           0 :     RefPtr<WebGLActiveInfo> ret = attribs[index].mActiveInfo;
     609           0 :     return ret.forget();
     610             : }
     611             : 
     612             : already_AddRefed<WebGLActiveInfo>
     613           0 : WebGLProgram::GetActiveUniform(GLuint index) const
     614             : {
     615           0 :     if (!mMostRecentLinkInfo) {
     616             :         // According to the spec, this can return null.
     617           0 :         RefPtr<WebGLActiveInfo> ret = WebGLActiveInfo::CreateInvalid(mContext);
     618           0 :         return ret.forget();
     619             :     }
     620             : 
     621           0 :     const auto& uniforms = mMostRecentLinkInfo->uniforms;
     622             : 
     623           0 :     if (index >= uniforms.size()) {
     624           0 :         mContext->ErrorInvalidValue("`index` (%i) must be less than %s (%" PRIuSIZE ").",
     625           0 :                                     index, "ACTIVE_UNIFORMS", uniforms.size());
     626           0 :         return nullptr;
     627             :     }
     628             : 
     629           0 :     RefPtr<WebGLActiveInfo> ret = uniforms[index]->mActiveInfo;
     630           0 :     return ret.forget();
     631             : }
     632             : 
     633             : void
     634           0 : WebGLProgram::GetAttachedShaders(nsTArray<RefPtr<WebGLShader>>* const out) const
     635             : {
     636           0 :     out->TruncateLength(0);
     637             : 
     638           0 :     if (mVertShader)
     639           0 :         out->AppendElement(mVertShader);
     640             : 
     641           0 :     if (mFragShader)
     642           0 :         out->AppendElement(mFragShader);
     643           0 : }
     644             : 
     645             : GLint
     646           0 : WebGLProgram::GetAttribLocation(const nsAString& userName_wide) const
     647             : {
     648           0 :     if (!ValidateGLSLVariableName(userName_wide, mContext, "getAttribLocation"))
     649           0 :         return -1;
     650             : 
     651           0 :     if (!IsLinked()) {
     652           0 :         mContext->ErrorInvalidOperation("getAttribLocation: `program` must be linked.");
     653           0 :         return -1;
     654             :     }
     655             : 
     656           0 :     const NS_LossyConvertUTF16toASCII userName(userName_wide);
     657             : 
     658             :     const webgl::AttribInfo* info;
     659           0 :     if (!LinkInfo()->FindAttrib(userName, &info))
     660           0 :         return -1;
     661             : 
     662           0 :     return GLint(info->mLoc);
     663             : }
     664             : 
     665             : static GLint
     666           0 : GetFragDataByUserName(const WebGLProgram* prog,
     667             :                       const nsCString& userName)
     668             : {
     669           0 :     nsCString mappedName;
     670           0 :     if (!prog->LinkInfo()->MapFragDataName(userName, &mappedName))
     671           0 :         return -1;
     672             : 
     673           0 :     return prog->mContext->gl->fGetFragDataLocation(prog->mGLName, mappedName.BeginReading());
     674             : }
     675             : 
     676             : GLint
     677           0 : WebGLProgram::GetFragDataLocation(const nsAString& userName_wide) const
     678             : {
     679           0 :     if (!ValidateGLSLVariableName(userName_wide, mContext, "getFragDataLocation"))
     680           0 :         return -1;
     681             : 
     682           0 :     if (!IsLinked()) {
     683           0 :         mContext->ErrorInvalidOperation("getFragDataLocation: `program` must be linked.");
     684           0 :         return -1;
     685             :     }
     686             : 
     687             : 
     688           0 :     const auto& gl = mContext->gl;
     689           0 :     gl->MakeCurrent();
     690             : 
     691           0 :     const NS_LossyConvertUTF16toASCII userName(userName_wide);
     692             : #ifdef XP_MACOSX
     693             :     if (gl->WorkAroundDriverBugs()) {
     694             :         // OSX doesn't return locs for indexed names, just the base names.
     695             :         // Indicated by failure in: conformance2/programs/gl-get-frag-data-location.html
     696             :         bool isArray;
     697             :         size_t arrayIndex;
     698             :         nsCString baseUserName;
     699             :         if (!ParseName(userName, &baseUserName, &isArray, &arrayIndex))
     700             :             return -1;
     701             : 
     702             :         if (arrayIndex >= mContext->mImplMaxDrawBuffers)
     703             :             return -1;
     704             : 
     705             :         const auto baseLoc = GetFragDataByUserName(this, baseUserName);
     706             :         const auto loc = baseLoc + GLint(arrayIndex);
     707             :         return loc;
     708             :     }
     709             : #endif
     710           0 :     return GetFragDataByUserName(this, userName);
     711             : }
     712             : 
     713             : void
     714           0 : WebGLProgram::GetProgramInfoLog(nsAString* const out) const
     715             : {
     716           0 :     CopyASCIItoUTF16(mLinkLog, *out);
     717           0 : }
     718             : 
     719             : static GLint
     720           0 : GetProgramiv(gl::GLContext* gl, GLuint program, GLenum pname)
     721             : {
     722           0 :     GLint ret = 0;
     723           0 :     gl->fGetProgramiv(program, pname, &ret);
     724           0 :     return ret;
     725             : }
     726             : 
     727             : JS::Value
     728           0 : WebGLProgram::GetProgramParameter(GLenum pname) const
     729             : {
     730           0 :     gl::GLContext* gl = mContext->gl;
     731           0 :     gl->MakeCurrent();
     732             : 
     733           0 :     if (mContext->IsWebGL2()) {
     734           0 :         switch (pname) {
     735             :         case LOCAL_GL_ACTIVE_UNIFORM_BLOCKS:
     736           0 :             if (!IsLinked())
     737           0 :                 return JS::NumberValue(0);
     738           0 :             return JS::NumberValue(LinkInfo()->uniformBlocks.size());
     739             : 
     740             :         case LOCAL_GL_TRANSFORM_FEEDBACK_VARYINGS:
     741           0 :             if (!IsLinked())
     742           0 :                 return JS::NumberValue(0);
     743           0 :             return JS::NumberValue(LinkInfo()->transformFeedbackVaryings.size());
     744             : 
     745             :         case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
     746           0 :             if (!IsLinked())
     747           0 :                 return JS::NumberValue(LOCAL_GL_INTERLEAVED_ATTRIBS);
     748           0 :             return JS::NumberValue(LinkInfo()->transformFeedbackBufferMode);
     749             :        }
     750             :     }
     751             : 
     752           0 :     switch (pname) {
     753             :     case LOCAL_GL_ATTACHED_SHADERS:
     754           0 :         return JS::NumberValue( int(bool(mVertShader.get())) + int(bool(mFragShader)) );
     755             : 
     756             :     case LOCAL_GL_ACTIVE_UNIFORMS:
     757           0 :         if (!IsLinked())
     758           0 :             return JS::NumberValue(0);
     759           0 :         return JS::NumberValue(LinkInfo()->uniforms.size());
     760             : 
     761             :     case LOCAL_GL_ACTIVE_ATTRIBUTES:
     762           0 :         if (!IsLinked())
     763           0 :             return JS::NumberValue(0);
     764           0 :         return JS::NumberValue(LinkInfo()->attribs.size());
     765             : 
     766             :     case LOCAL_GL_DELETE_STATUS:
     767           0 :         return JS::BooleanValue(IsDeleteRequested());
     768             : 
     769             :     case LOCAL_GL_LINK_STATUS:
     770           0 :         return JS::BooleanValue(IsLinked());
     771             : 
     772             :     case LOCAL_GL_VALIDATE_STATUS:
     773             : #ifdef XP_MACOSX
     774             :         // See comment in ValidateProgram.
     775             :         if (gl->WorkAroundDriverBugs())
     776             :             return JS::BooleanValue(true);
     777             : #endif
     778             :         // Todo: Implement this in our code.
     779           0 :         return JS::BooleanValue(bool(GetProgramiv(gl, mGLName, pname)));
     780             : 
     781             :     default:
     782           0 :         mContext->ErrorInvalidEnumInfo("getProgramParameter: `pname`",
     783           0 :                                        pname);
     784           0 :         return JS::NullValue();
     785             :     }
     786             : }
     787             : 
     788             : GLuint
     789           0 : WebGLProgram::GetUniformBlockIndex(const nsAString& userName_wide) const
     790             : {
     791           0 :     if (!ValidateGLSLVariableName(userName_wide, mContext, "getUniformBlockIndex"))
     792           0 :         return LOCAL_GL_INVALID_INDEX;
     793             : 
     794           0 :     if (!IsLinked()) {
     795           0 :         mContext->ErrorInvalidOperation("getUniformBlockIndex: `program` must be linked.");
     796           0 :         return LOCAL_GL_INVALID_INDEX;
     797             :     }
     798             : 
     799           0 :     const NS_LossyConvertUTF16toASCII userName(userName_wide);
     800             : 
     801           0 :     const webgl::UniformBlockInfo* info = nullptr;
     802           0 :     for (const auto& cur : LinkInfo()->uniformBlocks) {
     803           0 :         if (cur->mUserName == userName) {
     804           0 :             info = cur;
     805           0 :             break;
     806             :         }
     807             :     }
     808           0 :     if (!info)
     809           0 :         return LOCAL_GL_INVALID_INDEX;
     810             : 
     811           0 :     const auto& mappedName = info->mMappedName;
     812             : 
     813           0 :     gl::GLContext* gl = mContext->GL();
     814           0 :     gl->MakeCurrent();
     815           0 :     return gl->fGetUniformBlockIndex(mGLName, mappedName.BeginReading());
     816             : }
     817             : 
     818             : void
     819           0 : WebGLProgram::GetActiveUniformBlockName(GLuint uniformBlockIndex, nsAString& retval) const
     820             : {
     821           0 :     if (!IsLinked()) {
     822           0 :         mContext->ErrorInvalidOperation("getActiveUniformBlockName: `program` must be linked.");
     823           0 :         return;
     824             :     }
     825             : 
     826           0 :     const webgl::LinkedProgramInfo* linkInfo = LinkInfo();
     827           0 :     GLuint uniformBlockCount = (GLuint) linkInfo->uniformBlocks.size();
     828           0 :     if (uniformBlockIndex >= uniformBlockCount) {
     829           0 :         mContext->ErrorInvalidValue("getActiveUniformBlockName: index %u invalid.", uniformBlockIndex);
     830           0 :         return;
     831             :     }
     832             : 
     833           0 :     const auto& blockInfo = linkInfo->uniformBlocks[uniformBlockIndex];
     834           0 :     retval.Assign(NS_ConvertASCIItoUTF16(blockInfo->mUserName));
     835             : }
     836             : 
     837             : JS::Value
     838           0 : WebGLProgram::GetActiveUniformBlockParam(GLuint uniformBlockIndex, GLenum pname) const
     839             : {
     840           0 :     if (!IsLinked()) {
     841           0 :         mContext->ErrorInvalidOperation("getActiveUniformBlockParameter: `program` must be linked.");
     842           0 :         return JS::NullValue();
     843             :     }
     844             : 
     845           0 :     const webgl::LinkedProgramInfo* linkInfo = LinkInfo();
     846           0 :     GLuint uniformBlockCount = (GLuint)linkInfo->uniformBlocks.size();
     847           0 :     if (uniformBlockIndex >= uniformBlockCount) {
     848           0 :         mContext->ErrorInvalidValue("getActiveUniformBlockParameter: index %u invalid.", uniformBlockIndex);
     849           0 :         return JS::NullValue();
     850             :     }
     851             : 
     852           0 :     gl::GLContext* gl = mContext->GL();
     853           0 :     GLint param = 0;
     854             : 
     855           0 :     switch (pname) {
     856             :     case LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
     857             :     case LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
     858           0 :         gl->fGetActiveUniformBlockiv(mGLName, uniformBlockIndex, pname, &param);
     859           0 :         return JS::BooleanValue(bool(param));
     860             : 
     861             :     case LOCAL_GL_UNIFORM_BLOCK_BINDING:
     862             :     case LOCAL_GL_UNIFORM_BLOCK_DATA_SIZE:
     863             :     case LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
     864           0 :         gl->fGetActiveUniformBlockiv(mGLName, uniformBlockIndex, pname, &param);
     865           0 :         return JS::NumberValue(param);
     866             : 
     867             :     default:
     868           0 :         MOZ_CRASH("bad `pname`.");
     869             :     }
     870             : }
     871             : 
     872             : JS::Value
     873           0 : WebGLProgram::GetActiveUniformBlockActiveUniforms(JSContext* cx, GLuint uniformBlockIndex,
     874             :                                                   ErrorResult* const out_error) const
     875             : {
     876           0 :     const char funcName[] = "getActiveUniformBlockParameter";
     877           0 :     if (!IsLinked()) {
     878           0 :         mContext->ErrorInvalidOperation("%s: `program` must be linked.", funcName);
     879           0 :         return JS::NullValue();
     880             :     }
     881             : 
     882           0 :     const webgl::LinkedProgramInfo* linkInfo = LinkInfo();
     883           0 :     GLuint uniformBlockCount = (GLuint)linkInfo->uniformBlocks.size();
     884           0 :     if (uniformBlockIndex >= uniformBlockCount) {
     885           0 :         mContext->ErrorInvalidValue("%s: Index %u invalid.", funcName, uniformBlockIndex);
     886           0 :         return JS::NullValue();
     887             :     }
     888             : 
     889           0 :     gl::GLContext* gl = mContext->GL();
     890           0 :     GLint activeUniformCount = 0;
     891           0 :     gl->fGetActiveUniformBlockiv(mGLName, uniformBlockIndex,
     892             :                                  LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS,
     893           0 :                                  &activeUniformCount);
     894           0 :     JS::RootedObject obj(cx, dom::Uint32Array::Create(cx, mContext, activeUniformCount,
     895           0 :                                                       nullptr));
     896           0 :     if (!obj) {
     897           0 :         *out_error = NS_ERROR_OUT_OF_MEMORY;
     898           0 :         return JS::NullValue();
     899             :     }
     900             : 
     901           0 :     dom::Uint32Array result;
     902           0 :     DebugOnly<bool> inited = result.Init(obj);
     903           0 :     MOZ_ASSERT(inited);
     904           0 :     result.ComputeLengthAndData();
     905           0 :     gl->fGetActiveUniformBlockiv(mGLName, uniformBlockIndex,
     906             :                                  LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES,
     907           0 :                                  (GLint*)result.Data());
     908             : 
     909           0 :     return JS::ObjectValue(*obj);
     910             : }
     911             : 
     912             : already_AddRefed<WebGLUniformLocation>
     913           0 : WebGLProgram::GetUniformLocation(const nsAString& userName_wide) const
     914             : {
     915           0 :     if (!ValidateGLSLVariableName(userName_wide, mContext, "getUniformLocation"))
     916           0 :         return nullptr;
     917             : 
     918           0 :     if (!IsLinked()) {
     919           0 :         mContext->ErrorInvalidOperation("getUniformLocation: `program` must be linked.");
     920           0 :         return nullptr;
     921             :     }
     922             : 
     923           0 :     const NS_LossyConvertUTF16toASCII userName(userName_wide);
     924             : 
     925             :     // GLES 2.0.25, Section 2.10, p35
     926             :     // If the the uniform location is an array, then the location of the first
     927             :     // element of that array can be retrieved by either using the name of the
     928             :     // uniform array, or the name of the uniform array appended with "[0]".
     929           0 :     nsCString mappedName;
     930             :     size_t arrayIndex;
     931             :     webgl::UniformInfo* info;
     932           0 :     if (!LinkInfo()->FindUniform(userName, &mappedName, &arrayIndex, &info))
     933           0 :         return nullptr;
     934             : 
     935           0 :     gl::GLContext* gl = mContext->GL();
     936           0 :     gl->MakeCurrent();
     937             : 
     938           0 :     GLint loc = gl->fGetUniformLocation(mGLName, mappedName.BeginReading());
     939           0 :     if (loc == -1)
     940           0 :         return nullptr;
     941             : 
     942           0 :     RefPtr<WebGLUniformLocation> locObj = new WebGLUniformLocation(mContext, LinkInfo(),
     943           0 :                                                                    info, loc, arrayIndex);
     944           0 :     return locObj.forget();
     945             : }
     946             : 
     947             : void
     948           0 : WebGLProgram::GetUniformIndices(const dom::Sequence<nsString>& uniformNames,
     949             :                                 dom::Nullable< nsTArray<GLuint> >& retval) const
     950             : {
     951           0 :     const char funcName[] = "getUniformIndices";
     952           0 :     if (!IsLinked()) {
     953           0 :         mContext->ErrorInvalidOperation("%s: `program` must be linked.", funcName);
     954           0 :         return;
     955             :     }
     956             : 
     957           0 :     size_t count = uniformNames.Length();
     958           0 :     nsTArray<GLuint>& arr = retval.SetValue();
     959             : 
     960           0 :     gl::GLContext* gl = mContext->GL();
     961           0 :     gl->MakeCurrent();
     962             : 
     963           0 :     for (size_t i = 0; i < count; i++) {
     964           0 :         const NS_LossyConvertUTF16toASCII userName(uniformNames[i]);
     965             : 
     966           0 :         nsCString mappedName;
     967             :         size_t arrayIndex;
     968             :         webgl::UniformInfo* info;
     969           0 :         if (!LinkInfo()->FindUniform(userName, &mappedName, &arrayIndex, &info)) {
     970           0 :             arr.AppendElement(LOCAL_GL_INVALID_INDEX);
     971           0 :             continue;
     972             :         }
     973             : 
     974           0 :         const GLchar* const mappedNameBegin = mappedName.get();
     975             : 
     976           0 :         GLuint index = LOCAL_GL_INVALID_INDEX;
     977           0 :         gl->fGetUniformIndices(mGLName, 1, &mappedNameBegin, &index);
     978           0 :         arr.AppendElement(index);
     979             :     }
     980             : }
     981             : 
     982             : void
     983           0 : WebGLProgram::UniformBlockBinding(GLuint uniformBlockIndex,
     984             :                                   GLuint uniformBlockBinding) const
     985             : {
     986           0 :     const char funcName[] = "getActiveUniformBlockName";
     987           0 :     if (!IsLinked()) {
     988           0 :         mContext->ErrorInvalidOperation("%s: `program` must be linked.", funcName);
     989           0 :         return;
     990             :     }
     991             : 
     992           0 :     const auto& uniformBlocks = LinkInfo()->uniformBlocks;
     993           0 :     if (uniformBlockIndex >= uniformBlocks.size()) {
     994           0 :         mContext->ErrorInvalidValue("%s: Index %u invalid.", funcName, uniformBlockIndex);
     995           0 :         return;
     996             :     }
     997           0 :     const auto& uniformBlock = uniformBlocks[uniformBlockIndex];
     998             : 
     999           0 :     const auto& indexedBindings = mContext->mIndexedUniformBufferBindings;
    1000           0 :     if (uniformBlockBinding >= indexedBindings.size()) {
    1001           0 :         mContext->ErrorInvalidValue("%s: Binding %u invalid.", funcName,
    1002           0 :                                     uniformBlockBinding);
    1003           0 :         return;
    1004             :     }
    1005           0 :     const auto& indexedBinding = indexedBindings[uniformBlockBinding];
    1006             : 
    1007             :     ////
    1008             : 
    1009           0 :     gl::GLContext* gl = mContext->GL();
    1010           0 :     gl->MakeCurrent();
    1011           0 :     gl->fUniformBlockBinding(mGLName, uniformBlockIndex, uniformBlockBinding);
    1012             : 
    1013             :     ////
    1014             : 
    1015           0 :     uniformBlock->mBinding = &indexedBinding;
    1016             : }
    1017             : 
    1018             : bool
    1019           0 : WebGLProgram::ValidateForLink()
    1020             : {
    1021           0 :     if (!mVertShader || !mVertShader->IsCompiled()) {
    1022           0 :         mLinkLog.AssignLiteral("Must have a compiled vertex shader attached.");
    1023           0 :         return false;
    1024             :     }
    1025             : 
    1026           0 :     if (!mFragShader || !mFragShader->IsCompiled()) {
    1027           0 :         mLinkLog.AssignLiteral("Must have an compiled fragment shader attached.");
    1028           0 :         return false;
    1029             :     }
    1030             : 
    1031           0 :     if (!mFragShader->CanLinkTo(mVertShader, &mLinkLog))
    1032           0 :         return false;
    1033             : 
    1034           0 :     const auto& gl = mContext->gl;
    1035             : 
    1036           0 :     if (gl->WorkAroundDriverBugs() &&
    1037           0 :         mContext->mIsMesa)
    1038             :     {
    1039             :         // Bug 777028: Mesa can't handle more than 16 samplers per program,
    1040             :         // counting each array entry.
    1041           0 :         size_t numSamplerUniforms_upperBound = mVertShader->CalcNumSamplerUniforms() +
    1042           0 :                                                mFragShader->CalcNumSamplerUniforms();
    1043           0 :         if (numSamplerUniforms_upperBound > 16) {
    1044           0 :             mLinkLog.AssignLiteral("Programs with more than 16 samplers are disallowed on"
    1045           0 :                                    " Mesa drivers to avoid crashing.");
    1046           0 :             return false;
    1047             :         }
    1048             : 
    1049             :         // Bug 1203135: Mesa crashes internally if we exceed the reported maximum attribute count.
    1050           0 :         if (mVertShader->NumAttributes() > mContext->MaxVertexAttribs()) {
    1051           0 :             mLinkLog.AssignLiteral("Number of attributes exceeds Mesa's reported max"
    1052           0 :                                    " attribute count.");
    1053           0 :             return false;
    1054             :         }
    1055             :     }
    1056             : 
    1057           0 :     return true;
    1058             : }
    1059             : 
    1060             : void
    1061           0 : WebGLProgram::LinkProgram()
    1062             : {
    1063           0 :     const char funcName[] = "linkProgram";
    1064             : 
    1065           0 :     if (mNumActiveTFOs) {
    1066           0 :         mContext->ErrorInvalidOperation("%s: Program is in-use by one or more active"
    1067             :                                         " transform feedback objects.",
    1068           0 :                                         funcName);
    1069           0 :         return;
    1070             :     }
    1071             : 
    1072           0 :     mContext->MakeContextCurrent();
    1073           0 :     mContext->InvalidateBufferFetching(); // we do it early in this function
    1074             :     // as some of the validation changes program state
    1075             : 
    1076           0 :     mLinkLog.Truncate();
    1077           0 :     mMostRecentLinkInfo = nullptr;
    1078             : 
    1079           0 :     if (!ValidateForLink()) {
    1080           0 :         mContext->GenerateWarning("%s: %s", funcName, mLinkLog.BeginReading());
    1081           0 :         return;
    1082             :     }
    1083             : 
    1084             :     // Bind the attrib locations.
    1085             :     // This can't be done trivially, because we have to deal with mapped attrib names.
    1086           0 :     for (const auto& pair : mNextLink_BoundAttribLocs) {
    1087           0 :         const auto& name = pair.first;
    1088           0 :         const auto& index = pair.second;
    1089             : 
    1090           0 :         mVertShader->BindAttribLocation(mGLName, name, index);
    1091             :     }
    1092             : 
    1093             :     // Storage for transform feedback varyings before link.
    1094             :     // (Work around for bug seen on nVidia drivers.)
    1095           0 :     std::vector<std::string> scopedMappedTFVaryings;
    1096             : 
    1097           0 :     if (mContext->IsWebGL2()) {
    1098           0 :         mVertShader->MapTransformFeedbackVaryings(mNextLink_TransformFeedbackVaryings,
    1099           0 :                                                   &scopedMappedTFVaryings);
    1100             : 
    1101           0 :         std::vector<const char*> driverVaryings;
    1102           0 :         driverVaryings.reserve(scopedMappedTFVaryings.size());
    1103           0 :         for (const auto& cur : scopedMappedTFVaryings) {
    1104           0 :             driverVaryings.push_back(cur.c_str());
    1105             :         }
    1106             : 
    1107           0 :         mContext->gl->fTransformFeedbackVaryings(mGLName, driverVaryings.size(),
    1108           0 :                                                  driverVaryings.data(),
    1109           0 :                                                  mNextLink_TransformFeedbackBufferMode);
    1110             :     }
    1111             : 
    1112           0 :     LinkAndUpdate();
    1113             : 
    1114           0 :     if (mMostRecentLinkInfo) {
    1115           0 :         nsCString postLinkLog;
    1116           0 :         if (ValidateAfterTentativeLink(&postLinkLog))
    1117           0 :             return;
    1118             : 
    1119           0 :         mMostRecentLinkInfo = nullptr;
    1120           0 :         mLinkLog = postLinkLog;
    1121             :     }
    1122             : 
    1123             :     // Failed link.
    1124           0 :     if (mContext->ShouldGenerateWarnings()) {
    1125             :         // report shader/program infoLogs as warnings.
    1126             :         // note that shader compilation errors can be deferred to linkProgram,
    1127             :         // which is why we can't do anything in compileShader. In practice we could
    1128             :         // report in compileShader the translation errors generated by ANGLE,
    1129             :         // but it seems saner to keep a single way of obtaining shader infologs.
    1130           0 :         if (!mLinkLog.IsEmpty()) {
    1131           0 :             mContext->GenerateWarning("linkProgram: Failed to link, leaving the following"
    1132             :                                       " log:\n%s\n",
    1133           0 :                                       mLinkLog.BeginReading());
    1134             :         }
    1135             :     }
    1136             : }
    1137             : 
    1138             : static uint8_t
    1139           0 : NumUsedLocationsByElemType(GLenum elemType)
    1140             : {
    1141             :     // GLES 3.0.4 p55
    1142             : 
    1143           0 :     switch (elemType) {
    1144             :     case LOCAL_GL_FLOAT_MAT2:
    1145             :     case LOCAL_GL_FLOAT_MAT2x3:
    1146             :     case LOCAL_GL_FLOAT_MAT2x4:
    1147           0 :         return 2;
    1148             : 
    1149             :     case LOCAL_GL_FLOAT_MAT3x2:
    1150             :     case LOCAL_GL_FLOAT_MAT3:
    1151             :     case LOCAL_GL_FLOAT_MAT3x4:
    1152           0 :         return 3;
    1153             : 
    1154             :     case LOCAL_GL_FLOAT_MAT4x2:
    1155             :     case LOCAL_GL_FLOAT_MAT4x3:
    1156             :     case LOCAL_GL_FLOAT_MAT4:
    1157           0 :         return 4;
    1158             : 
    1159             :     default:
    1160           0 :         return 1;
    1161             :     }
    1162             : }
    1163             : 
    1164             : static uint8_t
    1165           0 : NumComponents(GLenum elemType)
    1166             : {
    1167           0 :     switch (elemType) {
    1168             :     case LOCAL_GL_FLOAT:
    1169             :     case LOCAL_GL_INT:
    1170             :     case LOCAL_GL_UNSIGNED_INT:
    1171             :     case LOCAL_GL_BOOL:
    1172           0 :         return 1;
    1173             : 
    1174             :     case LOCAL_GL_FLOAT_VEC2:
    1175             :     case LOCAL_GL_INT_VEC2:
    1176             :     case LOCAL_GL_UNSIGNED_INT_VEC2:
    1177             :     case LOCAL_GL_BOOL_VEC2:
    1178           0 :         return 2;
    1179             : 
    1180             :     case LOCAL_GL_FLOAT_VEC3:
    1181             :     case LOCAL_GL_INT_VEC3:
    1182             :     case LOCAL_GL_UNSIGNED_INT_VEC3:
    1183             :     case LOCAL_GL_BOOL_VEC3:
    1184           0 :         return 3;
    1185             : 
    1186             :     case LOCAL_GL_FLOAT_VEC4:
    1187             :     case LOCAL_GL_INT_VEC4:
    1188             :     case LOCAL_GL_UNSIGNED_INT_VEC4:
    1189             :     case LOCAL_GL_BOOL_VEC4:
    1190             :     case LOCAL_GL_FLOAT_MAT2:
    1191           0 :         return 4;
    1192             : 
    1193             :     case LOCAL_GL_FLOAT_MAT2x3:
    1194             :     case LOCAL_GL_FLOAT_MAT3x2:
    1195           0 :         return 6;
    1196             : 
    1197             :     case LOCAL_GL_FLOAT_MAT2x4:
    1198             :     case LOCAL_GL_FLOAT_MAT4x2:
    1199           0 :         return 8;
    1200             : 
    1201             :     case LOCAL_GL_FLOAT_MAT3:
    1202           0 :         return 9;
    1203             : 
    1204             :     case LOCAL_GL_FLOAT_MAT3x4:
    1205             :     case LOCAL_GL_FLOAT_MAT4x3:
    1206           0 :         return 12;
    1207             : 
    1208             :     case LOCAL_GL_FLOAT_MAT4:
    1209           0 :         return 16;
    1210             : 
    1211             :     default:
    1212           0 :         MOZ_CRASH("`elemType`");
    1213             :     }
    1214             : }
    1215             : 
    1216             : bool
    1217           0 : WebGLProgram::ValidateAfterTentativeLink(nsCString* const out_linkLog) const
    1218             : {
    1219           0 :     const auto& linkInfo = mMostRecentLinkInfo;
    1220           0 :     const auto& gl = mContext->gl;
    1221             : 
    1222             :     // Check if the attrib name conflicting to uniform name
    1223           0 :     for (const auto& attrib : linkInfo->attribs) {
    1224           0 :         const auto& attribName = attrib.mActiveInfo->mBaseUserName;
    1225             : 
    1226           0 :         for (const auto& uniform : linkInfo->uniforms) {
    1227           0 :             const auto& uniformName = uniform->mActiveInfo->mBaseUserName;
    1228           0 :             if (attribName == uniformName) {
    1229           0 :                 *out_linkLog = nsPrintfCString("Attrib name conflicts with uniform name:"
    1230             :                                                " %s",
    1231           0 :                                                attribName.BeginReading());
    1232           0 :                 return false;
    1233             :             }
    1234             :         }
    1235             :     }
    1236             : 
    1237           0 :     std::map<uint32_t, const webgl::AttribInfo*> attribsByLoc;
    1238           0 :     for (const auto& attrib : linkInfo->attribs) {
    1239           0 :         if (attrib.mLoc == -1)
    1240           0 :             continue;
    1241             : 
    1242           0 :         const auto& elemType = attrib.mActiveInfo->mElemType;
    1243           0 :         const auto numUsedLocs = NumUsedLocationsByElemType(elemType);
    1244           0 :         for (uint32_t i = 0; i < numUsedLocs; i++) {
    1245           0 :             const uint32_t usedLoc = attrib.mLoc + i;
    1246             : 
    1247           0 :             const auto res = attribsByLoc.insert({usedLoc, &attrib});
    1248           0 :             const bool& didInsert = res.second;
    1249           0 :             if (!didInsert) {
    1250           0 :                 const auto& aliasingName = attrib.mActiveInfo->mBaseUserName;
    1251           0 :                 const auto& itrExisting = res.first;
    1252           0 :                 const auto& existingInfo = itrExisting->second;
    1253           0 :                 const auto& existingName = existingInfo->mActiveInfo->mBaseUserName;
    1254           0 :                 *out_linkLog = nsPrintfCString("Attrib \"%s\" aliases locations used by"
    1255             :                                                " attrib \"%s\".",
    1256             :                                                aliasingName.BeginReading(),
    1257           0 :                                                existingName.BeginReading());
    1258           0 :                 return false;
    1259             :             }
    1260             :         }
    1261             :     }
    1262             : 
    1263             :     // Forbid:
    1264             :     // * Unrecognized varying name
    1265             :     // * Duplicate varying name
    1266             :     // * Too many components for specified buffer mode
    1267           0 :     if (mNextLink_TransformFeedbackVaryings.size()) {
    1268           0 :         GLuint maxComponentsPerIndex = 0;
    1269           0 :         switch (mNextLink_TransformFeedbackBufferMode) {
    1270             :         case LOCAL_GL_INTERLEAVED_ATTRIBS:
    1271           0 :             gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS,
    1272           0 :                              &maxComponentsPerIndex);
    1273           0 :             break;
    1274             : 
    1275             :         case LOCAL_GL_SEPARATE_ATTRIBS:
    1276           0 :             gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS,
    1277           0 :                              &maxComponentsPerIndex);
    1278           0 :             break;
    1279             : 
    1280             :         default:
    1281           0 :             MOZ_CRASH("`bufferMode`");
    1282             :         }
    1283             : 
    1284           0 :         std::vector<size_t> componentsPerVert;
    1285           0 :         std::set<const WebGLActiveInfo*> alreadyUsed;
    1286           0 :         for (const auto& wideUserName : mNextLink_TransformFeedbackVaryings) {
    1287           0 :             if (!componentsPerVert.size() ||
    1288           0 :                 mNextLink_TransformFeedbackBufferMode == LOCAL_GL_SEPARATE_ATTRIBS)
    1289             :             {
    1290           0 :                 componentsPerVert.push_back(0);
    1291             :             }
    1292             : 
    1293             :             ////
    1294             : 
    1295           0 :             const WebGLActiveInfo* curInfo = nullptr;
    1296           0 :             for (const auto& info : linkInfo->transformFeedbackVaryings) {
    1297           0 :                 const NS_ConvertASCIItoUTF16 info_wideUserName(info->mBaseUserName);
    1298           0 :                 if (info_wideUserName == wideUserName) {
    1299           0 :                     curInfo = info.get();
    1300           0 :                     break;
    1301             :                 }
    1302             :             }
    1303             : 
    1304           0 :             if (!curInfo) {
    1305           0 :                 const NS_LossyConvertUTF16toASCII asciiUserName(wideUserName);
    1306           0 :                 *out_linkLog = nsPrintfCString("Transform feedback varying \"%s\" not"
    1307             :                                                " found.",
    1308           0 :                                                asciiUserName.BeginReading());
    1309           0 :                 return false;
    1310             :             }
    1311             : 
    1312           0 :             const auto insertResPair = alreadyUsed.insert(curInfo);
    1313           0 :             const auto& didInsert = insertResPair.second;
    1314           0 :             if (!didInsert) {
    1315           0 :                 const NS_LossyConvertUTF16toASCII asciiUserName(wideUserName);
    1316           0 :                 *out_linkLog = nsPrintfCString("Transform feedback varying \"%s\""
    1317             :                                                " specified twice.",
    1318           0 :                                                asciiUserName.BeginReading());
    1319           0 :                 return false;
    1320             :             }
    1321             : 
    1322             :             ////
    1323             : 
    1324           0 :             size_t varyingComponents = NumComponents(curInfo->mElemType);
    1325           0 :             varyingComponents *= curInfo->mElemCount;
    1326             : 
    1327           0 :             auto& totalComponentsForIndex = *(componentsPerVert.rbegin());
    1328           0 :             totalComponentsForIndex += varyingComponents;
    1329             : 
    1330           0 :             if (totalComponentsForIndex > maxComponentsPerIndex) {
    1331           0 :                 const NS_LossyConvertUTF16toASCII asciiUserName(wideUserName);
    1332           0 :                 *out_linkLog = nsPrintfCString("Transform feedback varying \"%s\""
    1333             :                                                " pushed `componentsForIndex` over the"
    1334             :                                                " limit of %u.",
    1335             :                                                asciiUserName.BeginReading(),
    1336           0 :                                                maxComponentsPerIndex);
    1337           0 :                 return false;
    1338             :             }
    1339             :         }
    1340             : 
    1341           0 :         linkInfo->componentsPerTFVert.swap(componentsPerVert);
    1342             :     }
    1343             : 
    1344           0 :     return true;
    1345             : }
    1346             : 
    1347             : bool
    1348           0 : WebGLProgram::UseProgram() const
    1349             : {
    1350           0 :     const char funcName[] = "useProgram";
    1351             : 
    1352           0 :     if (!mMostRecentLinkInfo) {
    1353           0 :         mContext->ErrorInvalidOperation("%s: Program has not been successfully linked.",
    1354           0 :                                         funcName);
    1355           0 :         return false;
    1356             :     }
    1357             : 
    1358           0 :     if (mContext->mBoundTransformFeedback &&
    1359           0 :         mContext->mBoundTransformFeedback->mIsActive &&
    1360           0 :         !mContext->mBoundTransformFeedback->mIsPaused)
    1361             :     {
    1362           0 :         mContext->ErrorInvalidOperation("%s: Transform feedback active and not paused.",
    1363           0 :                                         funcName);
    1364           0 :         return false;
    1365             :     }
    1366             : 
    1367           0 :     mContext->MakeContextCurrent();
    1368             : 
    1369           0 :     mContext->InvalidateBufferFetching();
    1370             : 
    1371           0 :     mContext->gl->fUseProgram(mGLName);
    1372           0 :     return true;
    1373             : }
    1374             : 
    1375             : void
    1376           0 : WebGLProgram::ValidateProgram() const
    1377             : {
    1378           0 :     mContext->MakeContextCurrent();
    1379           0 :     gl::GLContext* gl = mContext->gl;
    1380             : 
    1381             : #ifdef XP_MACOSX
    1382             :     // See bug 593867 for NVIDIA and bug 657201 for ATI. The latter is confirmed
    1383             :     // with Mac OS 10.6.7.
    1384             :     if (gl->WorkAroundDriverBugs()) {
    1385             :         mContext->GenerateWarning("validateProgram: Implemented as a no-op on"
    1386             :                                   " Mac to work around crashes.");
    1387             :         return;
    1388             :     }
    1389             : #endif
    1390             : 
    1391           0 :     gl->fValidateProgram(mGLName);
    1392           0 : }
    1393             : 
    1394             : 
    1395             : ////////////////////////////////////////////////////////////////////////////////
    1396             : 
    1397             : void
    1398           0 : WebGLProgram::LinkAndUpdate()
    1399             : {
    1400           0 :     mMostRecentLinkInfo = nullptr;
    1401             : 
    1402           0 :     gl::GLContext* gl = mContext->gl;
    1403           0 :     gl->fLinkProgram(mGLName);
    1404             : 
    1405             :     // Grab the program log.
    1406           0 :     GLuint logLenWithNull = 0;
    1407           0 :     gl->fGetProgramiv(mGLName, LOCAL_GL_INFO_LOG_LENGTH, (GLint*)&logLenWithNull);
    1408           0 :     if (logLenWithNull > 1) {
    1409           0 :         mLinkLog.SetLength(logLenWithNull - 1);
    1410           0 :         gl->fGetProgramInfoLog(mGLName, logLenWithNull, nullptr, mLinkLog.BeginWriting());
    1411             :     } else {
    1412           0 :         mLinkLog.SetLength(0);
    1413             :     }
    1414             : 
    1415           0 :     GLint ok = 0;
    1416           0 :     gl->fGetProgramiv(mGLName, LOCAL_GL_LINK_STATUS, &ok);
    1417           0 :     if (!ok)
    1418           0 :         return;
    1419             : 
    1420           0 :     mMostRecentLinkInfo = QueryProgramInfo(this, gl);
    1421           0 :     MOZ_RELEASE_ASSERT(mMostRecentLinkInfo, "GFX: most recent link info not set.");
    1422             : }
    1423             : 
    1424             : bool
    1425           0 : WebGLProgram::FindAttribUserNameByMappedName(const nsACString& mappedName,
    1426             :                                              nsCString* const out_userName) const
    1427             : {
    1428           0 :     if (mVertShader->FindAttribUserNameByMappedName(mappedName, out_userName))
    1429           0 :         return true;
    1430             : 
    1431           0 :     return false;
    1432             : }
    1433             : 
    1434             : bool
    1435           0 : WebGLProgram::FindVaryingByMappedName(const nsACString& mappedName,
    1436             :                                               nsCString* const out_userName,
    1437             :                                               bool* const out_isArray) const
    1438             : {
    1439           0 :     if (mVertShader->FindVaryingByMappedName(mappedName, out_userName, out_isArray))
    1440           0 :         return true;
    1441             : 
    1442           0 :     return false;
    1443             : }
    1444             : 
    1445             : 
    1446             : bool
    1447           0 : WebGLProgram::FindUniformByMappedName(const nsACString& mappedName,
    1448             :                                       nsCString* const out_userName,
    1449             :                                       bool* const out_isArray) const
    1450             : {
    1451           0 :     if (mVertShader->FindUniformByMappedName(mappedName, out_userName, out_isArray))
    1452           0 :         return true;
    1453             : 
    1454           0 :     if (mFragShader->FindUniformByMappedName(mappedName, out_userName, out_isArray))
    1455           0 :         return true;
    1456             : 
    1457           0 :     return false;
    1458             : }
    1459             : 
    1460             : void
    1461           0 : WebGLProgram::TransformFeedbackVaryings(const dom::Sequence<nsString>& varyings,
    1462             :                                         GLenum bufferMode)
    1463             : {
    1464           0 :     const char funcName[] = "transformFeedbackVaryings";
    1465             : 
    1466           0 :     const auto& gl = mContext->gl;
    1467           0 :     gl->MakeCurrent();
    1468             : 
    1469           0 :     switch (bufferMode) {
    1470             :     case LOCAL_GL_INTERLEAVED_ATTRIBS:
    1471           0 :         break;
    1472             : 
    1473             :     case LOCAL_GL_SEPARATE_ATTRIBS:
    1474             :         {
    1475           0 :             GLuint maxAttribs = 0;
    1476           0 :             gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
    1477           0 :                              &maxAttribs);
    1478           0 :             if (varyings.Length() > maxAttribs) {
    1479           0 :                 mContext->ErrorInvalidValue("%s: Length of `varyings` exceeds %s.",
    1480             :                                             funcName,
    1481           0 :                                             "TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS");
    1482           0 :                 return;
    1483             :             }
    1484             :         }
    1485           0 :         break;
    1486             : 
    1487             :     default:
    1488           0 :         mContext->ErrorInvalidEnum("%s: Bad `bufferMode`: 0x%04x.", funcName, bufferMode);
    1489           0 :         return;
    1490             :     }
    1491             : 
    1492             :     ////
    1493             : 
    1494           0 :     mNextLink_TransformFeedbackVaryings.assign(varyings.Elements(),
    1495           0 :                                                varyings.Elements() + varyings.Length());
    1496           0 :     mNextLink_TransformFeedbackBufferMode = bufferMode;
    1497             : }
    1498             : 
    1499             : already_AddRefed<WebGLActiveInfo>
    1500           0 : WebGLProgram::GetTransformFeedbackVarying(GLuint index) const
    1501             : {
    1502             :     // No docs in the WebGL 2 spec for this function. Taking the language for
    1503             :     // getActiveAttrib, which states that the function returns null on any error.
    1504           0 :     if (!IsLinked()) {
    1505           0 :         mContext->ErrorInvalidOperation("getTransformFeedbackVarying: `program` must be "
    1506           0 :                                         "linked.");
    1507           0 :         return nullptr;
    1508             :     }
    1509             : 
    1510           0 :     if (index >= LinkInfo()->transformFeedbackVaryings.size()) {
    1511           0 :         mContext->ErrorInvalidValue("getTransformFeedbackVarying: `index` is greater or "
    1512           0 :                                     "equal to TRANSFORM_FEEDBACK_VARYINGS.");
    1513           0 :         return nullptr;
    1514             :     }
    1515             : 
    1516           0 :     RefPtr<WebGLActiveInfo> ret = LinkInfo()->transformFeedbackVaryings[index];
    1517           0 :     return ret.forget();
    1518             : }
    1519             : 
    1520             : bool
    1521           0 : WebGLProgram::UnmapUniformBlockName(const nsCString& mappedName,
    1522             :                                     nsCString* const out_userName) const
    1523             : {
    1524           0 :     nsCString baseMappedName;
    1525             :     bool isArray;
    1526             :     size_t arrayIndex;
    1527           0 :     if (!ParseName(mappedName, &baseMappedName, &isArray, &arrayIndex))
    1528           0 :         return false;
    1529             : 
    1530           0 :     nsCString baseUserName;
    1531           0 :     if (!mVertShader->UnmapUniformBlockName(baseMappedName, &baseUserName) &&
    1532           0 :         !mFragShader->UnmapUniformBlockName(baseMappedName, &baseUserName))
    1533             :     {
    1534           0 :         return false;
    1535             :     }
    1536             : 
    1537           0 :     AssembleName(baseUserName, isArray, arrayIndex, out_userName);
    1538           0 :     return true;
    1539             : }
    1540             : 
    1541             : void
    1542           0 : WebGLProgram::EnumerateFragOutputs(std::map<nsCString, const nsCString> &out_FragOutputs) const
    1543             : {
    1544           0 :     MOZ_ASSERT(mFragShader);
    1545             : 
    1546           0 :     mFragShader->EnumerateFragOutputs(out_FragOutputs);
    1547           0 : }
    1548             : 
    1549             : ////////////////////////////////////////////////////////////////////////////////
    1550             : 
    1551             : bool
    1552           0 : IsBaseName(const nsCString& name)
    1553             : {
    1554           0 :     if (!name.Length())
    1555           0 :         return true;
    1556             : 
    1557           0 :     return name[name.Length() - 1] != ']'; // Doesn't end in ']'.
    1558             : }
    1559             : 
    1560             : bool
    1561           0 : webgl::LinkedProgramInfo::FindAttrib(const nsCString& userName,
    1562             :                                      const webgl::AttribInfo** const out) const
    1563             : {
    1564             :     // VS inputs cannot be arrays or structures.
    1565             :     // `userName` is thus always `baseUserName`.
    1566           0 :     for (const auto& attrib : attribs) {
    1567           0 :         if (attrib.mActiveInfo->mBaseUserName == userName) {
    1568           0 :             *out = &attrib;
    1569           0 :             return true;
    1570             :         }
    1571             :     }
    1572             : 
    1573           0 :     return false;
    1574             : }
    1575             : 
    1576             : bool
    1577           0 : webgl::LinkedProgramInfo::FindUniform(const nsCString& userName,
    1578             :                                       nsCString* const out_mappedName,
    1579             :                                       size_t* const out_arrayIndex,
    1580             :                                       webgl::UniformInfo** const out_info) const
    1581             : {
    1582           0 :     nsCString baseUserName;
    1583             :     bool isArray;
    1584             :     size_t arrayIndex;
    1585           0 :     if (!ParseName(userName, &baseUserName, &isArray, &arrayIndex))
    1586           0 :         return false;
    1587             : 
    1588           0 :     webgl::UniformInfo* info = nullptr;
    1589           0 :     for (const auto& uniform : uniforms) {
    1590           0 :         if (uniform->mActiveInfo->mBaseUserName == baseUserName) {
    1591           0 :             info = uniform;
    1592           0 :             break;
    1593             :         }
    1594             :     }
    1595           0 :     if (!info)
    1596           0 :         return false;
    1597             : 
    1598           0 :     const auto& baseMappedName = info->mActiveInfo->mBaseMappedName;
    1599           0 :     AssembleName(baseMappedName, isArray, arrayIndex, out_mappedName);
    1600             : 
    1601           0 :     *out_arrayIndex = arrayIndex;
    1602           0 :     *out_info = info;
    1603           0 :     return true;
    1604             : }
    1605             : 
    1606             : bool
    1607           0 : webgl::LinkedProgramInfo::MapFragDataName(const nsCString& userName,
    1608             :                                           nsCString* const out_mappedName) const
    1609             : {
    1610             :     // FS outputs can be arrays, but not structures.
    1611             : 
    1612           0 :     if (!fragDataMap.size()) {
    1613             :         // No mappings map from validation, so just forward it.
    1614           0 :         *out_mappedName = userName;
    1615           0 :         return true;
    1616             :     }
    1617             : 
    1618           0 :     nsCString baseUserName;
    1619             :     bool isArray;
    1620             :     size_t arrayIndex;
    1621           0 :     if (!ParseName(userName, &baseUserName, &isArray, &arrayIndex))
    1622           0 :         return false;
    1623             : 
    1624           0 :     const auto itr = fragDataMap.find(baseUserName);
    1625           0 :     if (itr == fragDataMap.end())
    1626           0 :         return false;
    1627             : 
    1628           0 :     const auto& baseMappedName = itr->second;
    1629           0 :     AssembleName(baseMappedName, isArray, arrayIndex, out_mappedName);
    1630           0 :     return true;
    1631             : }
    1632             : 
    1633             : ////////////////////////////////////////////////////////////////////////////////
    1634             : 
    1635             : JSObject*
    1636           0 : WebGLProgram::WrapObject(JSContext* js, JS::Handle<JSObject*> givenProto)
    1637             : {
    1638           0 :     return dom::WebGLProgramBinding::Wrap(js, this, givenProto);
    1639             : }
    1640             : 
    1641           0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLProgram, mVertShader, mFragShader)
    1642             : 
    1643           0 : NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLProgram, AddRef)
    1644           0 : NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLProgram, Release)
    1645             : 
    1646             : } // namespace mozilla

Generated by: LCOV version 1.13