bool WebGLProgram::ValidateAfterTentativeLink(nsCString* const out_linkLog) const { const auto& linkInfo = mMostRecentLinkInfo; // Check if the attrib name conflicting to uniform name for (const auto& attrib : linkInfo->attribs) { const auto& attribName = attrib.mActiveInfo->mBaseUserName; for (const auto& uniform : linkInfo->uniforms) { const auto& uniformName = uniform->mActiveInfo->mBaseUserName; if (attribName == uniformName) { *out_linkLog = nsPrintfCString("Attrib name conflicts with uniform name:" " %s", attribName.BeginReading()); return false; } } } std::map<uint32_t, const webgl::AttribInfo*> attribsByLoc; for (const auto& attrib : linkInfo->attribs) { const auto& elemType = attrib.mActiveInfo->mElemType; const auto numUsedLocs = NumUsedLocationsByElemType(elemType); for (uint32_t i = 0; i < numUsedLocs; i++) { const uint32_t usedLoc = attrib.mLoc + i; const auto res = attribsByLoc.insert({usedLoc, &attrib}); const bool& didInsert = res.second; if (!didInsert) { const auto& aliasingName = attrib.mActiveInfo->mBaseUserName; const auto& itrExisting = res.first; const auto& existingInfo = itrExisting->second; const auto& existingName = existingInfo->mActiveInfo->mBaseUserName; *out_linkLog = nsPrintfCString("Attrib \"%s\" aliases locations used by" " attrib \"%s\".", aliasingName.BeginReading(), existingName.BeginReading()); return false; } } } return true; }
bool WebGLProgram::ValidateAfterTentativeLink(nsCString* const out_linkLog) const { const auto& linkInfo = mMostRecentLinkInfo; const auto& gl = mContext->gl; // Check if the attrib name conflicting to uniform name for (const auto& attrib : linkInfo->attribs) { const auto& attribName = attrib.mActiveInfo->mBaseUserName; for (const auto& uniform : linkInfo->uniforms) { const auto& uniformName = uniform->mActiveInfo->mBaseUserName; if (attribName == uniformName) { *out_linkLog = nsPrintfCString("Attrib name conflicts with uniform name:" " %s", attribName.BeginReading()); return false; } } } std::map<uint32_t, const webgl::AttribInfo*> attribsByLoc; for (const auto& attrib : linkInfo->attribs) { const auto& elemType = attrib.mActiveInfo->mElemType; const auto numUsedLocs = NumUsedLocationsByElemType(elemType); for (uint32_t i = 0; i < numUsedLocs; i++) { const uint32_t usedLoc = attrib.mLoc + i; const auto res = attribsByLoc.insert({usedLoc, &attrib}); const bool& didInsert = res.second; if (!didInsert) { const auto& aliasingName = attrib.mActiveInfo->mBaseUserName; const auto& itrExisting = res.first; const auto& existingInfo = itrExisting->second; const auto& existingName = existingInfo->mActiveInfo->mBaseUserName; *out_linkLog = nsPrintfCString("Attrib \"%s\" aliases locations used by" " attrib \"%s\".", aliasingName.BeginReading(), existingName.BeginReading()); return false; } } } // Forbid: // * Unrecognized varying name // * Duplicate varying name // * Too many components for specified buffer mode if (mNextLink_TransformFeedbackVaryings.size()) { GLuint maxComponentsPerIndex = 0; switch (mNextLink_TransformFeedbackBufferMode) { case LOCAL_GL_INTERLEAVED_ATTRIBS: gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, &maxComponentsPerIndex); break; case LOCAL_GL_SEPARATE_ATTRIBS: gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, &maxComponentsPerIndex); break; default: MOZ_CRASH("`bufferMode`"); } std::vector<size_t> componentsPerVert; std::set<const WebGLActiveInfo*> alreadyUsed; for (const auto& wideUserName : mNextLink_TransformFeedbackVaryings) { if (!componentsPerVert.size() || mNextLink_TransformFeedbackBufferMode == LOCAL_GL_SEPARATE_ATTRIBS) { componentsPerVert.push_back(0); } //// const WebGLActiveInfo* curInfo = nullptr; for (const auto& info : linkInfo->transformFeedbackVaryings) { const NS_ConvertASCIItoUTF16 info_wideUserName(info->mBaseUserName); if (info_wideUserName == wideUserName) { curInfo = info.get(); break; } } if (!curInfo) { const NS_LossyConvertUTF16toASCII asciiUserName(wideUserName); *out_linkLog = nsPrintfCString("Transform feedback varying \"%s\" not" " found.", asciiUserName.BeginReading()); return false; } const auto insertResPair = alreadyUsed.insert(curInfo); const auto& didInsert = insertResPair.second; if (!didInsert) { const NS_LossyConvertUTF16toASCII asciiUserName(wideUserName); *out_linkLog = nsPrintfCString("Transform feedback varying \"%s\"" " specified twice.", asciiUserName.BeginReading()); return false; } //// size_t varyingComponents = NumComponents(curInfo->mElemType); varyingComponents *= curInfo->mElemCount; auto& totalComponentsForIndex = *(componentsPerVert.rbegin()); totalComponentsForIndex += varyingComponents; if (totalComponentsForIndex > maxComponentsPerIndex) { const NS_LossyConvertUTF16toASCII asciiUserName(wideUserName); *out_linkLog = nsPrintfCString("Transform feedback varying \"%s\"" " pushed `componentsForIndex` over the" " limit of %u.", asciiUserName.BeginReading(), maxComponentsPerIndex); return false; } } linkInfo->componentsPerTFVert.swap(componentsPerVert); } return true; }