bool ShaderValidator::CanLinkTo(const ShaderValidator* prev, nsCString* const out_log) const { if (!prev) { nsPrintfCString error("Passed in NULL prev ShaderValidator."); *out_log = error; return false; } { const std::vector<sh::Uniform>* vertPtr = ShGetUniforms(prev->mHandle); const std::vector<sh::Uniform>* fragPtr = ShGetUniforms(mHandle); if (!vertPtr || !fragPtr) { nsPrintfCString error("Could not create uniform list."); *out_log = error; return false; } for (auto itrFrag = fragPtr->begin(); itrFrag != fragPtr->end(); ++itrFrag) { for (auto itrVert = vertPtr->begin(); itrVert != vertPtr->end(); ++itrVert) { if (itrVert->name != itrFrag->name) continue; if (!itrVert->isSameUniformAtLinkTime(*itrFrag)) { nsPrintfCString error("Uniform `%s`is not linkable between" " attached shaders.", itrFrag->name.c_str()); *out_log = error; return false; } break; } } } { const std::vector<sh::Varying>* vertPtr = ShGetVaryings(prev->mHandle); const std::vector<sh::Varying>* fragPtr = ShGetVaryings(mHandle); if (!vertPtr || !fragPtr) { nsPrintfCString error("Could not create varying list."); *out_log = error; return false; } nsTArray<ShVariableInfo> staticUseVaryingList; for (auto itrFrag = fragPtr->begin(); itrFrag != fragPtr->end(); ++itrFrag) { const ShVariableInfo varInfo = { itrFrag->type, (int)itrFrag->elementCount() }; static const char prefix[] = "gl_"; if (StartsWith(itrFrag->name, prefix)) { if (itrFrag->staticUse) staticUseVaryingList.AppendElement(varInfo); continue; } bool definedInVertShader = false; bool staticVertUse = false; for (auto itrVert = vertPtr->begin(); itrVert != vertPtr->end(); ++itrVert) { if (itrVert->name != itrFrag->name) continue; if (!itrVert->isSameVaryingAtLinkTime(*itrFrag)) { nsPrintfCString error("Varying `%s`is not linkable between" " attached shaders.", itrFrag->name.c_str()); *out_log = error; return false; } definedInVertShader = true; staticVertUse = itrVert->staticUse; break; } if (!definedInVertShader && itrFrag->staticUse) { nsPrintfCString error("Varying `%s` has static-use in the frag" " shader, but is undeclared in the vert" " shader.", itrFrag->name.c_str()); *out_log = error; return false; } if (staticVertUse && itrFrag->staticUse) staticUseVaryingList.AppendElement(varInfo); } if (!ShCheckVariablesWithinPackingLimits(mMaxVaryingVectors, staticUseVaryingList.Elements(), staticUseVaryingList.Length())) { *out_log = "Statically used varyings do not fit within packing limits. (see" " GLSL ES Specification 1.0.17, p111)"; return false; } } return true; }
bool ShaderValidator::CanLinkTo(const ShaderValidator* prev, nsCString* const out_log) const { if (!prev) { nsPrintfCString error("Passed in NULL prev ShaderValidator."); *out_log = error; return false; } const auto shaderVersion = ShGetShaderVersion(mHandle); if (ShGetShaderVersion(prev->mHandle) != shaderVersion) { nsPrintfCString error("Vertex shader version %d does not match" " fragment shader version %d.", ShGetShaderVersion(prev->mHandle), ShGetShaderVersion(mHandle)); *out_log = error; return false; } { const std::vector<sh::Uniform>* vertPtr = ShGetUniforms(prev->mHandle); const std::vector<sh::Uniform>* fragPtr = ShGetUniforms(mHandle); if (!vertPtr || !fragPtr) { nsPrintfCString error("Could not create uniform list."); *out_log = error; return false; } for (auto itrFrag = fragPtr->begin(); itrFrag != fragPtr->end(); ++itrFrag) { for (auto itrVert = vertPtr->begin(); itrVert != vertPtr->end(); ++itrVert) { if (itrVert->name != itrFrag->name) continue; if (!itrVert->isSameUniformAtLinkTime(*itrFrag)) { nsPrintfCString error("Uniform `%s` is not linkable between" " attached shaders.", itrFrag->name.c_str()); *out_log = error; return false; } break; } } } { const auto vertVars = sh::GetInterfaceBlocks(prev->mHandle); const auto fragVars = sh::GetInterfaceBlocks(mHandle); if (!vertVars || !fragVars) { nsPrintfCString error("Could not create uniform block list."); *out_log = error; return false; } for (const auto& fragVar : *fragVars) { for (const auto& vertVar : *vertVars) { if (vertVar.name != fragVar.name) continue; if (!vertVar.isSameInterfaceBlockAtLinkTime(fragVar)) { nsPrintfCString error("Interface block `%s` is not linkable between" " attached shaders.", fragVar.name.c_str()); *out_log = error; return false; } break; } } } const auto& vertVaryings = ShGetVaryings(prev->mHandle); const auto& fragVaryings = ShGetVaryings(mHandle); if (!vertVaryings || !fragVaryings) { nsPrintfCString error("Could not create varying list."); *out_log = error; return false; } { std::vector<sh::ShaderVariable> staticUseVaryingList; for (const auto& fragVarying : *fragVaryings) { static const char prefix[] = "gl_"; if (StartsWith(fragVarying.name, prefix)) { if (fragVarying.staticUse) { staticUseVaryingList.push_back(fragVarying); } continue; } bool definedInVertShader = false; bool staticVertUse = false; for (const auto& vertVarying : *vertVaryings) { if (vertVarying.name != fragVarying.name) continue; if (!vertVarying.isSameVaryingAtLinkTime(fragVarying, shaderVersion)) { nsPrintfCString error("Varying `%s`is not linkable between" " attached shaders.", fragVarying.name.c_str()); *out_log = error; return false; } definedInVertShader = true; staticVertUse = vertVarying.staticUse; break; } if (!definedInVertShader && fragVarying.staticUse) { nsPrintfCString error("Varying `%s` has static-use in the frag" " shader, but is undeclared in the vert" " shader.", fragVarying.name.c_str()); *out_log = error; return false; } if (staticVertUse && fragVarying.staticUse) { staticUseVaryingList.push_back(fragVarying); } } if (!ShCheckVariablesWithinPackingLimits(mMaxVaryingVectors, staticUseVaryingList)) { *out_log = "Statically used varyings do not fit within packing limits. (see" " GLSL ES Specification 1.0.17, p111)"; return false; } } if (shaderVersion == 100) { // Enforce ESSL1 invariant linking rules. bool isInvariant_Position = false; bool isInvariant_PointSize = false; bool isInvariant_FragCoord = false; bool isInvariant_PointCoord = false; for (const auto& varying : *vertVaryings) { if (varying.name == "gl_Position") { isInvariant_Position = varying.isInvariant; } else if (varying.name == "gl_PointSize") { isInvariant_PointSize = varying.isInvariant; } } for (const auto& varying : *fragVaryings) { if (varying.name == "gl_FragCoord") { isInvariant_FragCoord = varying.isInvariant; } else if (varying.name == "gl_PointCoord") { isInvariant_PointCoord = varying.isInvariant; } } //// const auto fnCanBuiltInsLink = [](bool vertIsInvariant, bool fragIsInvariant) { if (vertIsInvariant) return true; return !fragIsInvariant; }; if (!fnCanBuiltInsLink(isInvariant_Position, isInvariant_FragCoord)) { *out_log = "gl_Position must be invariant if gl_FragCoord is. (see GLSL ES" " Specification 1.0.17, p39)"; return false; } if (!fnCanBuiltInsLink(isInvariant_PointSize, isInvariant_PointCoord)) { *out_log = "gl_PointSize must be invariant if gl_PointCoord is. (see GLSL ES" " Specification 1.0.17, p39)"; return false; } } return true; }