bool WebGLProgram::LinkProgram() { mContext->InvalidateBufferFetching(); // we do it early in this function // as some of the validation below changes program state mLinkLog.Truncate(); mMostRecentLinkInfo = nullptr; if (!mVertShader || !mVertShader->IsCompiled()) { mLinkLog.AssignLiteral("Must have a compiled vertex shader attached."); mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading()); return false; } if (!mFragShader || !mFragShader->IsCompiled()) { mLinkLog.AssignLiteral("Must have an compiled fragment shader attached."); mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading()); return false; } if (!mFragShader->CanLinkTo(mVertShader, &mLinkLog)) { mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading()); return false; } gl::GLContext* gl = mContext->gl; gl->MakeCurrent(); if (gl->WorkAroundDriverBugs() && mContext->mIsMesa) { // Bug 777028: Mesa can't handle more than 16 samplers per program, // counting each array entry. size_t numSamplerUniforms_upperBound = mVertShader->CalcNumSamplerUniforms() + mFragShader->CalcNumSamplerUniforms(); if (numSamplerUniforms_upperBound > 16) { mLinkLog.AssignLiteral("Programs with more than 16 samplers are disallowed on" " Mesa drivers to avoid crashing."); mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading()); return false; } // Bug 1203135: Mesa crashes internally if we exceed the reported maximum attribute count. if (mVertShader->NumAttributes() > mContext->MaxVertexAttribs()) { mLinkLog.AssignLiteral("Number of attributes exceeds Mesa's reported max attribute count."); mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading()); return false; } } // Bind the attrib locations. // This can't be done trivially, because we have to deal with mapped attrib names. for (auto itr = mBoundAttribLocs.begin(); itr != mBoundAttribLocs.end(); ++itr) { const nsCString& name = itr->first; GLuint index = itr->second; mVertShader->BindAttribLocation(mGLName, name, index); } if (!mTransformFeedbackVaryings.empty()) { // Bind the transform feedback varyings. // This can't be done trivially, because we have to deal with mapped names too. mVertShader->ApplyTransformFeedbackVaryings(mGLName, mTransformFeedbackVaryings, mTransformFeedbackBufferMode, &mTempMappedVaryings); } if (LinkAndUpdate()) return true; // Failed link. if (mContext->ShouldGenerateWarnings()) { // report shader/program infoLogs as warnings. // note that shader compilation errors can be deferred to linkProgram, // which is why we can't do anything in compileShader. In practice we could // report in compileShader the translation errors generated by ANGLE, // but it seems saner to keep a single way of obtaining shader infologs. if (!mLinkLog.IsEmpty()) { mContext->GenerateWarning("linkProgram: Failed to link, leaving the following" " log:\n%s\n", mLinkLog.BeginReading()); } } return false; }
void WebGLProgram::LinkProgram() { const char funcName[] = "linkProgram"; if (mNumActiveTFOs) { mContext->ErrorInvalidOperation("%s: Program is in-use by one or more active" " transform feedback objects.", funcName); return; } mContext->MakeContextCurrent(); mContext->InvalidateBufferFetching(); // we do it early in this function // as some of the validation changes program state mLinkLog.Truncate(); mMostRecentLinkInfo = nullptr; if (!ValidateForLink()) { mContext->GenerateWarning("%s: %s", funcName, mLinkLog.BeginReading()); return; } // Bind the attrib locations. // This can't be done trivially, because we have to deal with mapped attrib names. for (const auto& pair : mNextLink_BoundAttribLocs) { const auto& name = pair.first; const auto& index = pair.second; mVertShader->BindAttribLocation(mGLName, name, index); } // Storage for transform feedback varyings before link. // (Work around for bug seen on nVidia drivers.) std::vector<std::string> scopedMappedTFVaryings; if (mContext->IsWebGL2()) { mVertShader->MapTransformFeedbackVaryings(mNextLink_TransformFeedbackVaryings, &scopedMappedTFVaryings); std::vector<const char*> driverVaryings; driverVaryings.reserve(scopedMappedTFVaryings.size()); for (const auto& cur : scopedMappedTFVaryings) { driverVaryings.push_back(cur.c_str()); } mContext->gl->fTransformFeedbackVaryings(mGLName, driverVaryings.size(), driverVaryings.data(), mNextLink_TransformFeedbackBufferMode); } LinkAndUpdate(); if (mMostRecentLinkInfo) { nsCString postLinkLog; if (ValidateAfterTentativeLink(&postLinkLog)) return; mMostRecentLinkInfo = nullptr; mLinkLog = postLinkLog; } // Failed link. if (mContext->ShouldGenerateWarnings()) { // report shader/program infoLogs as warnings. // note that shader compilation errors can be deferred to linkProgram, // which is why we can't do anything in compileShader. In practice we could // report in compileShader the translation errors generated by ANGLE, // but it seems saner to keep a single way of obtaining shader infologs. if (!mLinkLog.IsEmpty()) { mContext->GenerateWarning("linkProgram: Failed to link, leaving the following" " log:\n%s\n", mLinkLog.BeginReading()); } } }