void ShaderD3D::parseVaryings(ShHandle compiler) { if (!mTranslatedSource.empty()) { const std::vector<sh::Varying> *varyings = ShGetVaryings(compiler); ASSERT(varyings); mVaryings = *varyings; for (size_t varyingIndex = 0; varyingIndex < varyings->size(); varyingIndex++) { mPackedVaryings.push_back(PackedVarying(mVaryings[varyingIndex])); } mUsesMultipleRenderTargets = mTranslatedSource.find("GL_USES_MRT") != std::string::npos; mUsesFragColor = mTranslatedSource.find("GL_USES_FRAG_COLOR") != std::string::npos; mUsesFragData = mTranslatedSource.find("GL_USES_FRAG_DATA") != std::string::npos; mUsesFragCoord = mTranslatedSource.find("GL_USES_FRAG_COORD") != std::string::npos; mUsesFrontFacing = mTranslatedSource.find("GL_USES_FRONT_FACING") != std::string::npos; mUsesPointSize = mTranslatedSource.find("GL_USES_POINT_SIZE") != std::string::npos; mUsesPointCoord = mTranslatedSource.find("GL_USES_POINT_COORD") != std::string::npos; mUsesDepthRange = mTranslatedSource.find("GL_USES_DEPTH_RANGE") != std::string::npos; mUsesFragDepth = mTranslatedSource.find("GL_USES_FRAG_DEPTH") != std::string::npos; mUsesDiscardRewriting = mTranslatedSource.find("ANGLE_USES_DISCARD_REWRITING") != std::string::npos; mUsesNestedBreak = mTranslatedSource.find("ANGLE_USES_NESTED_BREAK") != std::string::npos; mUsesDeferredInit = mTranslatedSource.find("ANGLE_USES_DEFERRED_INIT") != std::string::npos; mRequiresIEEEStrictCompiling = mTranslatedSource.find("ANGLE_REQUIRES_IEEE_STRICT_COMPILING") != std::string::npos; } }
static bool getSymbolInfo(ShHandle compiler, ANGLEShaderSymbolType symbolType, Vector<ANGLEShaderSymbol>& symbols) { switch (symbolType) { case SHADER_SYMBOL_TYPE_UNIFORM: { auto uniforms = ShGetUniforms(compiler); if (!uniforms) return false; for (const auto& uniform : *uniforms) getSymbolInfo(uniform, symbolType, symbols); break; } case SHADER_SYMBOL_TYPE_VARYING: { auto varyings = ShGetVaryings(compiler); if (!varyings) return false; for (const auto& varying : *varyings) getSymbolInfo(varying, symbolType, symbols); break; } case SHADER_SYMBOL_TYPE_ATTRIBUTE: { auto attributes = ShGetAttributes(compiler); if (!attributes) return false; for (const auto& attribute : *attributes) getSymbolInfo(attribute, symbolType, symbols); break; } default: ASSERT_NOT_REACHED(); return false; } return true; }
void ShaderD3D::parseVaryings(void *compiler) { if (!mHlsl.empty()) { const std::vector<sh::Varying> *varyings = ShGetVaryings(compiler); ASSERT(varyings); for (size_t varyingIndex = 0; varyingIndex < varyings->size(); varyingIndex++) { mVaryings.push_back(gl::PackedVarying((*varyings)[varyingIndex])); } mUsesMultipleRenderTargets = mHlsl.find("GL_USES_MRT") != std::string::npos; mUsesFragColor = mHlsl.find("GL_USES_FRAG_COLOR") != std::string::npos; mUsesFragData = mHlsl.find("GL_USES_FRAG_DATA") != std::string::npos; mUsesFragCoord = mHlsl.find("GL_USES_FRAG_COORD") != std::string::npos; mUsesFrontFacing = mHlsl.find("GL_USES_FRONT_FACING") != std::string::npos; mUsesPointSize = mHlsl.find("GL_USES_POINT_SIZE") != std::string::npos; mUsesPointCoord = mHlsl.find("GL_USES_POINT_COORD") != std::string::npos; mUsesDepthRange = mHlsl.find("GL_USES_DEPTH_RANGE") != std::string::npos; mUsesFragDepth = mHlsl.find("GL_USES_FRAG_DEPTH") != std::string::npos; mUsesDiscardRewriting = mHlsl.find("ANGLE_USES_DISCARD_REWRITING") != std::string::npos; mUsesNestedBreak = mHlsl.find("ANGLE_USES_NESTED_BREAK") != std::string::npos; } }
bool ShaderValidator::FindVaryingMappedNameByUserName(const std::string& userName, const std::string** const out_mappedName) const { const std::vector<sh::Varying>& attribs = *ShGetVaryings(mHandle); for (auto itr = attribs.begin(); itr != attribs.end(); ++itr) { if (itr->name == userName) { *out_mappedName = &(itr->mappedName); return true; } } return false; }
bool ShaderValidator::FindVaryingByMappedName(const std::string& mappedName, std::string* const out_userName, bool* const out_isArray) const { const std::vector<sh::Varying>& varyings = *ShGetVaryings(mHandle); for (auto itr = varyings.begin(); itr != varyings.end(); ++itr) { const sh::ShaderVariable* found; if (!itr->findInfoByMappedName(mappedName, &found, out_userName)) continue; *out_isArray = found->isArray(); return true; } return false; }
static void PrintActiveVariables(ShHandle compiler) { const std::vector<sh::Uniform> *uniforms = ShGetUniforms(compiler); const std::vector<sh::Varying> *varyings = ShGetVaryings(compiler); const std::vector<sh::Attribute> *attributes = ShGetAttributes(compiler); for (size_t varCategory = 0; varCategory < 3; ++varCategory) { size_t numVars = 0; std::string varCategoryName; if (varCategory == 0) { numVars = uniforms->size(); varCategoryName = "uniform"; } else if (varCategory == 1) { numVars = varyings->size(); varCategoryName = "varying"; } else { numVars = attributes->size(); varCategoryName = "attribute"; } for (size_t i = 0; i < numVars; ++i) { const sh::ShaderVariable *var; if (varCategory == 0) var = &((*uniforms)[i]); else if (varCategory == 1) var = &((*varyings)[i]); else var = &((*attributes)[i]); PrintVariable(varCategoryName, i, *var); } printf("\n"); } }
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; }
void Shader::compile(Compiler *compiler) { mData.mTranslatedSource.clear(); mInfoLog.clear(); mData.mShaderVersion = 100; mData.mVaryings.clear(); mData.mUniforms.clear(); mData.mInterfaceBlocks.clear(); mData.mActiveAttributes.clear(); mData.mActiveOutputVariables.clear(); ShHandle compilerHandle = compiler->getCompilerHandle(mData.mShaderType); std::stringstream sourceStream; std::string sourcePath; int additionalOptions = mImplementation->prepareSourceAndReturnOptions(&sourceStream, &sourcePath); int compileOptions = (SH_OBJECT_CODE | SH_VARIABLES | additionalOptions); // Some targets (eg D3D11 Feature Level 9_3 and below) do not support non-constant loop indexes // in fragment shaders. Shader compilation will fail. To provide a better error message we can // instruct the compiler to pre-validate. if (mRendererLimitations.shadersRequireIndexedLoopValidation) { compileOptions |= SH_VALIDATE_LOOP_INDEXING; } std::string sourceString = sourceStream.str(); std::vector<const char *> sourceCStrings; if (!sourcePath.empty()) { sourceCStrings.push_back(sourcePath.c_str()); } sourceCStrings.push_back(sourceString.c_str()); bool result = ShCompile(compilerHandle, &sourceCStrings[0], sourceCStrings.size(), compileOptions); if (!result) { mInfoLog = ShGetInfoLog(compilerHandle); TRACE("\n%s", mInfoLog.c_str()); mCompiled = false; return; } mData.mTranslatedSource = ShGetObjectCode(compilerHandle); #ifndef NDEBUG // Prefix translated shader with commented out un-translated shader. // Useful in diagnostics tools which capture the shader source. std::ostringstream shaderStream; shaderStream << "// GLSL\n"; shaderStream << "//\n"; size_t curPos = 0; while (curPos != std::string::npos) { size_t nextLine = mData.mSource.find("\n", curPos); size_t len = (nextLine == std::string::npos) ? std::string::npos : (nextLine - curPos + 1); shaderStream << "// " << mData.mSource.substr(curPos, len); curPos = (nextLine == std::string::npos) ? std::string::npos : (nextLine + 1); } shaderStream << "\n\n"; shaderStream << mData.mTranslatedSource; mData.mTranslatedSource = shaderStream.str(); #endif // Gather the shader information mData.mShaderVersion = ShGetShaderVersion(compilerHandle); mData.mVaryings = GetShaderVariables(ShGetVaryings(compilerHandle)); mData.mUniforms = GetShaderVariables(ShGetUniforms(compilerHandle)); mData.mInterfaceBlocks = GetShaderVariables(ShGetInterfaceBlocks(compilerHandle)); if (mData.mShaderType == GL_VERTEX_SHADER) { mData.mActiveAttributes = GetActiveShaderVariables(ShGetAttributes(compilerHandle)); } else { ASSERT(mData.mShaderType == GL_FRAGMENT_SHADER); // TODO(jmadill): Figure out why we only sort in the FS, and if we need to. std::sort(mData.mVaryings.begin(), mData.mVaryings.end(), CompareShaderVar); mData.mActiveOutputVariables = GetActiveShaderVariables(ShGetOutputVariables(compilerHandle)); } ASSERT(!mData.mTranslatedSource.empty()); mCompiled = mImplementation->postTranslateCompile(compiler, &mInfoLog); }