void Shader::resolveCompile() { if (!mState.compilePending()) { return; } ASSERT(mBoundCompiler.get()); ShHandle compilerHandle = mBoundCompiler->getCompilerHandle(mState.mShaderType); std::vector<const char *> srcStrings; if (!mLastCompiledSourcePath.empty()) { srcStrings.push_back(mLastCompiledSourcePath.c_str()); } srcStrings.push_back(mLastCompiledSource.c_str()); if (!sh::Compile(compilerHandle, &srcStrings[0], srcStrings.size(), mLastCompileOptions)) { mInfoLog = sh::GetInfoLog(compilerHandle); WARN() << std::endl << mInfoLog; mState.mCompileStatus = CompileStatus::NOT_COMPILED; return; } mState.mTranslatedSource = sh::GetObjectCode(compilerHandle); #if !defined(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"; std::istringstream inputSourceStream(mState.mSource); std::string line; while (std::getline(inputSourceStream, line)) { // Remove null characters from the source line line.erase(std::remove(line.begin(), line.end(), '\0'), line.end()); shaderStream << "// " << line << std::endl; } shaderStream << "\n\n"; shaderStream << mState.mTranslatedSource; mState.mTranslatedSource = shaderStream.str(); #endif // !defined(NDEBUG) // Gather the shader information mState.mShaderVersion = sh::GetShaderVersion(compilerHandle); mState.mUniforms = GetShaderVariables(sh::GetUniforms(compilerHandle)); mState.mUniformBlocks = GetShaderVariables(sh::GetUniformBlocks(compilerHandle)); mState.mShaderStorageBlocks = GetShaderVariables(sh::GetShaderStorageBlocks(compilerHandle)); switch (mState.mShaderType) { case ShaderType::Compute: { mState.mLocalSize = sh::GetComputeShaderLocalGroupSize(compilerHandle); if (mState.mLocalSize.isDeclared()) { angle::CheckedNumeric<uint32_t> checked_local_size_product(mState.mLocalSize[0]); checked_local_size_product *= mState.mLocalSize[1]; checked_local_size_product *= mState.mLocalSize[2]; if (!checked_local_size_product.IsValid()) { WARN() << std::endl << "Integer overflow when computing the product of local_size_x, " << "local_size_y and local_size_z."; mState.mCompileStatus = CompileStatus::NOT_COMPILED; return; } if (checked_local_size_product.ValueOrDie() > mCurrentMaxComputeWorkGroupInvocations) { WARN() << std::endl << "The total number of invocations within a work group exceeds " << "MAX_COMPUTE_WORK_GROUP_INVOCATIONS."; mState.mCompileStatus = CompileStatus::NOT_COMPILED; return; } } break; } case ShaderType::Vertex: { { mState.mOutputVaryings = GetShaderVariables(sh::GetOutputVaryings(compilerHandle)); mState.mAllAttributes = GetShaderVariables(sh::GetAttributes(compilerHandle)); mState.mActiveAttributes = GetActiveShaderVariables(&mState.mAllAttributes); mState.mNumViews = sh::GetVertexShaderNumViews(compilerHandle); } break; } case ShaderType::Fragment: { mState.mInputVaryings = GetShaderVariables(sh::GetInputVaryings(compilerHandle)); // TODO(jmadill): Figure out why we only sort in the FS, and if we need to. std::sort(mState.mInputVaryings.begin(), mState.mInputVaryings.end(), CompareShaderVar); mState.mActiveOutputVariables = GetActiveShaderVariables(sh::GetOutputVariables(compilerHandle)); break; } case ShaderType::Geometry: { mState.mInputVaryings = GetShaderVariables(sh::GetInputVaryings(compilerHandle)); mState.mOutputVaryings = GetShaderVariables(sh::GetOutputVaryings(compilerHandle)); if (sh::HasValidGeometryShaderInputPrimitiveType(compilerHandle)) { mState.mGeometryShaderInputPrimitiveType = FromGLenum<PrimitiveMode>( sh::GetGeometryShaderInputPrimitiveType(compilerHandle)); } if (sh::HasValidGeometryShaderOutputPrimitiveType(compilerHandle)) { mState.mGeometryShaderOutputPrimitiveType = FromGLenum<PrimitiveMode>( sh::GetGeometryShaderOutputPrimitiveType(compilerHandle)); } if (sh::HasValidGeometryShaderMaxVertices(compilerHandle)) { mState.mGeometryShaderMaxVertices = sh::GetGeometryShaderMaxVertices(compilerHandle); } mState.mGeometryShaderInvocations = sh::GetGeometryShaderInvocations(compilerHandle); break; } default: UNREACHABLE(); } ASSERT(!mState.mTranslatedSource.empty()); bool success = mImplementation->postTranslateCompile(mBoundCompiler.get(), &mInfoLog); mState.mCompileStatus = success ? CompileStatus::COMPILED : CompileStatus::NOT_COMPILED; }
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); }