/// Initializize the symbol table /// \param BuiltInStrings /// Pointer to built in strings. /// \param language /// Shading language to initialize symbol table for /// \param infoSink /// Information sink (for errors/warnings) /// \param symbolTables /// Array of symbol tables (one for each language) /// \param bUseGlobalSymbolTable /// Whether to use the global symbol table or the per-language symbol table /// \return /// True if succesfully initialized, false otherwise bool InitializeSymbolTable( TBuiltInStrings* BuiltInStrings, EShLanguage language, TInfoSink& infoSink, TSymbolTable* symbolTables, bool bUseGlobalSymbolTable ) { TIntermediate intermediate(infoSink); TSymbolTable* symbolTable; if ( bUseGlobalSymbolTable ) symbolTable = symbolTables; else symbolTable = &symbolTables[language]; TParseContext parseContext(*symbolTable, intermediate, language, infoSink); GlobalParseContext = &parseContext; setInitialState(); assert(symbolTable->isEmpty() || symbolTable->atSharedBuiltInLevel()); // // Parse the built-ins. This should only happen once per // language symbol table. // // Push the symbol table to give it an initial scope. This // push should not have a corresponding pop, so that built-ins // are preserved, and the test for an empty table fails. // symbolTable->push(); //Initialize the Preprocessor int ret = InitPreprocessor(); if (ret) { infoSink.info.message(EPrefixInternalError, "Unable to intialize the Preprocessor"); return false; } for (TBuiltInStrings::iterator i = BuiltInStrings[parseContext.language].begin(); i != BuiltInStrings[parseContext.language].end(); ++i) { const char* builtInShaders = (*i).c_str(); if (PaParseString(const_cast<char*>(builtInShaders), parseContext) != 0) { infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins"); return false; } } if ( !bUseGlobalSymbolTable ) { IdentifyBuiltIns(parseContext.language, *symbolTable); } FinalizePreprocessor(); return true; }
/// Initializize the symbol table /// \param BuiltInStrings /// Pointer to built in strings. /// \param language /// Shading language to initialize symbol table for /// \param infoSink /// Information sink (for errors/warnings) /// \param symbolTables /// Array of symbol tables (one for each language) /// \param bUseGlobalSymbolTable /// Whether to use the global symbol table or the per-language symbol table /// \return /// True if succesfully initialized, false otherwise static bool InitializeSymbolTable( TBuiltInStrings* BuiltInStrings, EShLanguage language, TInfoSink& infoSink, TSymbolTable* symbolTables, bool bUseGlobalSymbolTable ) { TSymbolTable* symbolTable; if ( bUseGlobalSymbolTable ) symbolTable = symbolTables; else symbolTable = &symbolTables[language]; //@TODO: for now, we use same global symbol table for all target language versions. // This is wrong and will have to be changed at some point. TParseContext parseContext(*symbolTable, language, ETargetVersionCount, 0, infoSink); GlobalParseContext = &parseContext; setInitialState(); assert(symbolTable->isEmpty() || symbolTable->atSharedBuiltInLevel()); // // Parse the built-ins. This should only happen once per // language symbol table. // // Push the symbol table to give it an initial scope. This // push should not have a corresponding pop, so that built-ins // are preserved, and the test for an empty table fails. // symbolTable->push(); for (TBuiltInStrings::iterator i = BuiltInStrings[parseContext.language].begin(); i != BuiltInStrings[parseContext.language].end(); ++i) { const char* builtInShaders = (*i).c_str(); if (PaParseString(const_cast<char*>(builtInShaders), parseContext, NULL) != 0) { infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins"); return false; } } if ( !bUseGlobalSymbolTable ) { IdentifyBuiltIns(parseContext.language, *symbolTable); } return true; }
static bool InitializeSymbolTable( const TBuiltInStrings& builtInStrings, EShLanguage language, EShSpec spec, const TBuiltInResource& resources, TInfoSink& infoSink, TSymbolTable& symbolTable) { TIntermediate intermediate(infoSink); TParseContext parseContext(symbolTable, intermediate, language, spec, infoSink); GlobalParseContext = &parseContext; setInitialState(); assert(symbolTable.isEmpty()); // // Parse the built-ins. This should only happen once per // language symbol table. // // Push the symbol table to give it an initial scope. This // push should not have a corresponding pop, so that built-ins // are preserved, and the test for an empty table fails. // symbolTable.push(); //Initialize the Preprocessor if (InitPreprocessor()) { infoSink.info.message(EPrefixInternalError, "Unable to intialize the Preprocessor"); return false; } for (TBuiltInStrings::const_iterator i = builtInStrings.begin(); i != builtInStrings.end(); ++i) { const char* builtInShaders[1]; int builtInLengths[1]; builtInShaders[0] = (*i).c_str(); builtInLengths[0] = (int) (*i).size(); if (PaParseStrings(const_cast<char**>(builtInShaders), builtInLengths, 1, parseContext) != 0) { infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins"); return false; } } IdentifyBuiltIns(language, spec, resources, symbolTable); FinalizePreprocessor(); return true; }
bool Object::parse( ResourceManager *resMgr, Module *module, SSIZE_T &off, WORD objectInfoLen ) { // Need parse Object Info if (objectInfoLen && needObjectInfo()) { // Parse ObjectInfo if (!parseObjectInfo( module, off, objectInfoLen )) { printf( "[biop::Object] Warning, Cannot parse biop::ObjectInfo\n" ); return false; } } // Update offset to skip objectInfo off += objectInfoLen; // Read Service Context List Count BYTE serviceContextListCount; if (!module->readB( off, serviceContextListCount )) { printf( "[biop::Object] Warning, Cannot read bytes to parse ServiceContextList\n" ); return false; } // Parse Service Context List for (BYTE context=0; context<serviceContextListCount; context++) { if (!parseContext( module, off )) { printf( "[biop::Object] Warning, Cannot parse Service Context List: context=%d", context ); return false; } } // Skip body len DWORD bodyLen; if (!module->readDW( off, bodyLen )) { printf( "[biop::Object] Warning, Cannot parse body len" ); return false; } SSIZE_T old = off; off += bodyLen; // Parse body return parseBody( resMgr, module, old, bodyLen ); }
bool TCompiler::compile(const char* const shaderStrings[], size_t numStrings, int compileOptions) { TScopedPoolAllocator scopedAlloc(&allocator, true); clearResults(); if (numStrings == 0) return true; // If compiling for WebGL, validate loop and indexing as well. if (isWebGLBasedSpec(shaderSpec)) compileOptions |= SH_VALIDATE_LOOP_INDEXING; // First string is path of source file if flag is set. The actual source follows. const char* sourcePath = NULL; size_t firstSource = 0; if (compileOptions & SH_SOURCE_PATH) { sourcePath = shaderStrings[0]; ++firstSource; } TIntermediate intermediate(infoSink); TParseContext parseContext(symbolTable, extensionBehavior, intermediate, shaderType, shaderSpec, compileOptions, true, sourcePath, infoSink); parseContext.fragmentPrecisionHigh = fragmentPrecisionHigh; GlobalParseContext = &parseContext; // We preserve symbols at the built-in level from compile-to-compile. // Start pushing the user-defined symbols at global level. symbolTable.push(); if (!symbolTable.atGlobalLevel()) { infoSink.info.prefix(EPrefixInternalError); infoSink.info << "Wrong symbol table level"; } // Parse shader. bool success = (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) && (parseContext.treeRoot != NULL); if (success) { TIntermNode* root = parseContext.treeRoot; success = intermediate.postProcess(root); if (success) success = detectCallDepth(root, infoSink, (compileOptions & SH_LIMIT_CALL_STACK_DEPTH) != 0); if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING)) success = validateLimitations(root); if (success && (compileOptions & SH_TIMING_RESTRICTIONS)) success = enforceTimingRestrictions(root, (compileOptions & SH_DEPENDENCY_GRAPH) != 0); if (success && shaderSpec == SH_CSS_SHADERS_SPEC) rewriteCSSShader(root); // Unroll for-loop markup needs to happen after validateLimitations pass. if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX)) ForLoopUnroll::MarkForLoopsWithIntegerIndicesForUnrolling(root); // Built-in function emulation needs to happen after validateLimitations pass. if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS)) builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root); // Clamping uniform array bounds needs to happen after validateLimitations pass. if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS)) arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root); // Disallow expressions deemed too complex. if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY)) success = limitExpressionComplexity(root); // Call mapLongVariableNames() before collectAttribsUniforms() so in // collectAttribsUniforms() we already have the mapped symbol names and // we could composite mapped and original variable names. // Also, if we hash all the names, then no need to do this for long names. if (success && (compileOptions & SH_MAP_LONG_VARIABLE_NAMES) && hashFunction == NULL) mapLongVariableNames(root); if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS)) { collectAttribsUniforms(root); if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS) { success = enforcePackingRestrictions(); if (!success) { infoSink.info.prefix(EPrefixError); infoSink.info << "too many uniforms"; } } } if (success && (compileOptions & SH_INTERMEDIATE_TREE)) intermediate.outputTree(root); if (success && (compileOptions & SH_OBJECT_CODE)) translate(root); } // Cleanup memory. intermediate.remove(parseContext.treeRoot); // Ensure symbol table is returned to the built-in level, // throwing away all but the built-ins. while (!symbolTable.atBuiltInLevel()) symbolTable.pop(); return success; }
// // Do an actual compile on the given strings. The result is left // in the given compile object. // // Return: The return value of ShCompile is really boolean, indicating // success or failure. // int ShCompile( const ShHandle handle, const char* const shaderStrings[], const int numStrings, const EShOptimizationLevel optLevel, const TBuiltInResource* resources, int debugOptions ) { if (!InitThread()) return 0; if (handle == 0) return 0; TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle); TCompiler* compiler = base->getAsCompiler(); if (compiler == 0) return 0; GlobalPoolAllocator.push(); compiler->infoSink.info.erase(); compiler->infoSink.debug.erase(); if (numStrings == 0) return 1; TIntermediate intermediate(compiler->infoSink); TSymbolTable symbolTable(SymbolTables[compiler->getLanguage()]); GenerateBuiltInSymbolTable(resources, compiler->infoSink, &symbolTable, compiler->getLanguage()); TParseContext parseContext(symbolTable, intermediate, compiler->getLanguage(), compiler->infoSink); parseContext.initializeExtensionBehavior(); GlobalParseContext = &parseContext; setInitialState(); InitPreprocessor(); // // Parse the application's shaders. All the following symbol table // work will be throw-away, so push a new allocation scope that can // be thrown away, then push a scope for the current shader's globals. // bool success = true; symbolTable.push(); if (!symbolTable.atGlobalLevel()) parseContext.infoSink.info.message(EPrefixInternalError, "Wrong symbol table level"); if (parseContext.insertBuiltInArrayAtGlobalLevel()) success = false; int ret = PaParseStrings(const_cast<char**>(shaderStrings), 0, numStrings, parseContext); if (ret) success = false; if (success && parseContext.treeRoot) { if (optLevel == EShOptNoGeneration) parseContext.infoSink.info.message(EPrefixNone, "No errors. No code generation or linking was requested."); else { success = intermediate.postProcess(parseContext.treeRoot, parseContext.language); if (success) { if (debugOptions & EDebugOpIntermediate) intermediate.outputTree(parseContext.treeRoot); // // Call the machine dependent compiler // if (! compiler->compile(parseContext.treeRoot)) success = false; } } } else if (!success) { parseContext.infoSink.info.prefix(EPrefixError); parseContext.infoSink.info << parseContext.numErrors << " compilation errors. No code generated.\n\n"; success = false; if (debugOptions & EDebugOpIntermediate) intermediate.outputTree(parseContext.treeRoot); } intermediate.remove(parseContext.treeRoot); // // Ensure symbol table is returned to the built-in level, // throwing away all but the built-ins. // while (! symbolTable.atSharedBuiltInLevel()) symbolTable.pop(); FinalizePreprocessor(); // // Throw away all the temporary memory used by the compilation process. // GlobalPoolAllocator.pop(); return success ? 1 : 0; }
TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[], size_t numStrings, const int compileOptions) { clearResults(); ASSERT(numStrings > 0); ASSERT(GetGlobalPoolAllocator()); // Reset the extension behavior for each compilation unit. ResetExtensionBehavior(extensionBehavior); // First string is path of source file if flag is set. The actual source follows. size_t firstSource = 0; if (compileOptions & SH_SOURCE_PATH) { mSourcePath = shaderStrings[0]; ++firstSource; } TIntermediate intermediate(infoSink); TParseContext parseContext(symbolTable, extensionBehavior, intermediate, shaderType, shaderSpec, compileOptions, true, infoSink, getResources()); parseContext.setFragmentPrecisionHighOnESSL1(fragmentPrecisionHigh); SetGlobalParseContext(&parseContext); // We preserve symbols at the built-in level from compile-to-compile. // Start pushing the user-defined symbols at global level. TScopedSymbolTableLevel scopedSymbolLevel(&symbolTable); // Parse shader. bool success = (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], nullptr, &parseContext) == 0) && (parseContext.getTreeRoot() != nullptr); shaderVersion = parseContext.getShaderVersion(); if (success && MapSpecToShaderVersion(shaderSpec) < shaderVersion) { infoSink.info.prefix(EPrefixError); infoSink.info << "unsupported shader version"; success = false; } TIntermNode *root = nullptr; if (success) { mPragma = parseContext.pragma(); if (mPragma.stdgl.invariantAll) { symbolTable.setGlobalInvariant(); } root = parseContext.getTreeRoot(); root = intermediate.postProcess(root); // Highp might have been auto-enabled based on shader version fragmentPrecisionHigh = parseContext.getFragmentPrecisionHigh(); // Disallow expressions deemed too complex. if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY)) success = limitExpressionComplexity(root); // Create the function DAG and check there is no recursion if (success) success = initCallDag(root); if (success && (compileOptions & SH_LIMIT_CALL_STACK_DEPTH)) success = checkCallDepth(); // Checks which functions are used and if "main" exists if (success) { functionMetadata.clear(); functionMetadata.resize(mCallDag.size()); success = tagUsedFunctions(); } if (success && !(compileOptions & SH_DONT_PRUNE_UNUSED_FUNCTIONS)) success = pruneUnusedFunctions(root); // Prune empty declarations to work around driver bugs and to keep declaration output simple. if (success) PruneEmptyDeclarations(root); if (success && shaderVersion == 300 && shaderType == GL_FRAGMENT_SHADER) success = validateOutputs(root); if (success && shouldRunLoopAndIndexingValidation(compileOptions)) success = validateLimitations(root); if (success && (compileOptions & SH_TIMING_RESTRICTIONS)) success = enforceTimingRestrictions(root, (compileOptions & SH_DEPENDENCY_GRAPH) != 0); if (success && shaderSpec == SH_CSS_SHADERS_SPEC) rewriteCSSShader(root); // Unroll for-loop markup needs to happen after validateLimitations pass. if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX)) { ForLoopUnrollMarker marker(ForLoopUnrollMarker::kIntegerIndex, shouldRunLoopAndIndexingValidation(compileOptions)); root->traverse(&marker); } if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX)) { ForLoopUnrollMarker marker(ForLoopUnrollMarker::kSamplerArrayIndex, shouldRunLoopAndIndexingValidation(compileOptions)); root->traverse(&marker); if (marker.samplerArrayIndexIsFloatLoopIndex()) { infoSink.info.prefix(EPrefixError); infoSink.info << "sampler array index is float loop index"; success = false; } } // Built-in function emulation needs to happen after validateLimitations pass. if (success) { initBuiltInFunctionEmulator(&builtInFunctionEmulator, compileOptions); builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root); } // Clamping uniform array bounds needs to happen after validateLimitations pass. if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS)) arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root); // gl_Position is always written in compatibility output mode if (success && shaderType == GL_VERTEX_SHADER && ((compileOptions & SH_INIT_GL_POSITION) || (outputType == SH_GLSL_COMPATIBILITY_OUTPUT))) initializeGLPosition(root); // This pass might emit short circuits so keep it before the short circuit unfolding if (success && (compileOptions & SH_REWRITE_DO_WHILE_LOOPS)) RewriteDoWhile(root, getTemporaryIndex()); if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT)) { UnfoldShortCircuitAST unfoldShortCircuit; root->traverse(&unfoldShortCircuit); unfoldShortCircuit.updateTree(); } if (success && (compileOptions & SH_REMOVE_POW_WITH_CONSTANT_EXPONENT)) { RemovePow(root); } if (success && shouldCollectVariables(compileOptions)) { collectVariables(root); if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS) { success = enforcePackingRestrictions(); if (!success) { infoSink.info.prefix(EPrefixError); infoSink.info << "too many uniforms"; } } if (success && shaderType == GL_VERTEX_SHADER && (compileOptions & SH_INIT_VARYINGS_WITHOUT_STATIC_USE)) initializeVaryingsWithoutStaticUse(root); } if (success && (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS)) { ScalarizeVecAndMatConstructorArgs scalarizer( shaderType, fragmentPrecisionHigh); root->traverse(&scalarizer); } if (success && (compileOptions & SH_REGENERATE_STRUCT_NAMES)) { RegenerateStructNames gen(symbolTable, shaderVersion); root->traverse(&gen); } } SetGlobalParseContext(NULL); if (success) return root; return NULL; }
int C_DECL Hlsl2Glsl_Parse( const ShHandle handle, const char* shaderString, ETargetVersion targetVersion, Hlsl2Glsl_ParseCallbacks* callbacks, unsigned options) { if (!InitThread()) return 0; if (handle == 0) return 0; HlslCrossCompiler* compiler = handle; GlobalPoolAllocator.push(); compiler->infoSink.info.erase(); compiler->infoSink.debug.erase(); if (!shaderString) return 1; TSymbolTable symbolTable(SymbolTables[compiler->getLanguage()]); GenerateBuiltInSymbolTable(compiler->infoSink, &symbolTable, compiler->getLanguage()); TParseContext parseContext(symbolTable, compiler->getLanguage(), targetVersion, options, compiler->infoSink); GlobalParseContext = &parseContext; setInitialState(); // // Parse the application's shaders. All the following symbol table // work will be throw-away, so push a new allocation scope that can // be thrown away, then push a scope for the current shader's globals. // bool success = true; symbolTable.push(); if (!symbolTable.atGlobalLevel()) parseContext.infoSink.info.message(EPrefixInternalError, "Wrong symbol table level"); int ret = PaParseString(const_cast<char*>(shaderString), parseContext, callbacks); if (ret) success = false; if (success && parseContext.treeRoot) { TIntermAggregate* aggRoot = parseContext.treeRoot->getAsAggregate(); if (aggRoot && aggRoot->getOp() == EOpNull) aggRoot->setOperator(EOpSequence); if (options & ETranslateOpIntermediate) ir_output_tree(parseContext.treeRoot, parseContext.infoSink); compiler->TransformAST (parseContext.treeRoot); compiler->ProduceGLSL (parseContext.treeRoot, targetVersion, options); } else if (!success) { // only add "X compilation errors" message if somehow there are no other errors whatsoever, yet // we still failed. for some reason. if (parseContext.infoSink.info.IsEmpty()) { parseContext.infoSink.info.prefix(EPrefixError); parseContext.infoSink.info << parseContext.numErrors << " compilation errors. No code generated.\n\n"; } success = false; if (options & ETranslateOpIntermediate) ir_output_tree(parseContext.treeRoot, parseContext.infoSink); } ir_remove_tree(parseContext.treeRoot); // // Ensure symbol table is returned to the built-in level, // throwing away all but the built-ins. // while (! symbolTable.atSharedBuiltInLevel()) symbolTable.pop(); // // Throw away all the temporary memory used by the compilation process. // GlobalPoolAllocator.pop(); return success ? 1 : 0; }
bool TCompiler::compile(const char* const shaderStrings[], const int numStrings, int compileOptions) { TScopedPoolAllocator scopedAlloc(&allocator, true); clearResults(); if (numStrings == 0) return true; // If compiling for WebGL, validate loop and indexing as well. if (shaderSpec == SH_WEBGL_SPEC) compileOptions |= SH_VALIDATE_LOOP_INDEXING; // First string is path of source file if flag is set. The actual source follows. const char* sourcePath = NULL; int firstSource = 0; if (compileOptions & SH_SOURCE_PATH) { sourcePath = shaderStrings[0]; ++firstSource; } TIntermediate intermediate(infoSink); TParseContext parseContext(symbolTable, extensionBehavior, intermediate, shaderType, shaderSpec, compileOptions, sourcePath, infoSink); GlobalParseContext = &parseContext; // We preserve symbols at the built-in level from compile-to-compile. // Start pushing the user-defined symbols at global level. symbolTable.push(); if (!symbolTable.atGlobalLevel()) infoSink.info.message(EPrefixInternalError, "Wrong symbol table level"); // Parse shader. bool success = (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) && (parseContext.treeRoot != NULL); if (success) { TIntermNode* root = parseContext.treeRoot; success = intermediate.postProcess(root); if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING)) success = validateLimitations(root); if (success && (compileOptions & SH_INTERMEDIATE_TREE)) intermediate.outputTree(root); if (success && (compileOptions & SH_OBJECT_CODE)) translate(root); if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS)) collectAttribsUniforms(root); } // Cleanup memory. intermediate.remove(parseContext.treeRoot); // Ensure symbol table is returned to the built-in level, // throwing away all but the built-ins. while (!symbolTable.atBuiltInLevel()) symbolTable.pop(); return success; }
bool ClientContext::parse() { return filter_path(m_input.c_str(), m_path, m_context) && parseContext(m_input, m_data); }
bool TCompiler::compile(const char* const shaderStrings[], const int numStrings, int compileOptions) { TScopedPoolAllocator scopedAlloc(&allocator, true); clearResults(); if (numStrings == 0) return true; // If compiling for WebGL, validate loop and indexing as well. if (shaderSpec == SH_WEBGL_SPEC) compileOptions |= SH_VALIDATE_LOOP_INDEXING; // First string is path of source file if flag is set. The actual source follows. const char* sourcePath = NULL; int firstSource = 0; if (compileOptions & SH_SOURCE_PATH) { sourcePath = shaderStrings[0]; ++firstSource; } TIntermediate intermediate(infoSink); TParseContext parseContext(symbolTable, extensionBehavior, intermediate, shaderType, shaderSpec, compileOptions, true, sourcePath, infoSink); GlobalParseContext = &parseContext; // We preserve symbols at the built-in level from compile-to-compile. // Start pushing the user-defined symbols at global level. symbolTable.push(); if (!symbolTable.atGlobalLevel()) infoSink.info.message(EPrefixInternalError, "Wrong symbol table level"); // Parse shader. bool success = (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) && (parseContext.treeRoot != NULL); if (success) { TIntermNode* root = parseContext.treeRoot; success = intermediate.postProcess(root); if (success) success = detectRecursion(root); if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING)) success = validateLimitations(root); // Unroll for-loop markup needs to happen after validateLimitations pass. if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX)) ForLoopUnroll::MarkForLoopsWithIntegerIndicesForUnrolling(root); // Built-in function emulation needs to happen after validateLimitations pass. if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS)) builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root); // Call mapLongVariableNames() before collectAttribsUniforms() so in // collectAttribsUniforms() we already have the mapped symbol names and // we could composite mapped and original variable names. if (success && (compileOptions & SH_MAP_LONG_VARIABLE_NAMES)) mapLongVariableNames(root); if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS)) collectAttribsUniforms(root); if (success && (compileOptions & SH_INTERMEDIATE_TREE)) intermediate.outputTree(root); if (success && (compileOptions & SH_OBJECT_CODE)) translate(root); } // Cleanup memory. intermediate.remove(parseContext.treeRoot); // Ensure symbol table is returned to the built-in level, // throwing away all but the built-ins. while (!symbolTable.atBuiltInLevel()) symbolTable.pop(); return success; }
TIntermNode *TCompiler::compileTreeImpl(const char* const shaderStrings[], size_t numStrings, int compileOptions) { clearResults(); ASSERT(numStrings > 0); ASSERT(GetGlobalPoolAllocator()); // Reset the extension behavior for each compilation unit. ResetExtensionBehavior(extensionBehavior); // If compiling for WebGL, validate loop and indexing as well. if (IsWebGLBasedSpec(shaderSpec)) compileOptions |= SH_VALIDATE_LOOP_INDEXING; // First string is path of source file if flag is set. The actual source follows. size_t firstSource = 0; if (compileOptions & SH_SOURCE_PATH) { mSourcePath = shaderStrings[0]; ++firstSource; } bool debugShaderPrecision = getResources().WEBGL_debug_shader_precision == 1; TIntermediate intermediate(infoSink); TParseContext parseContext(symbolTable, extensionBehavior, intermediate, shaderType, shaderSpec, compileOptions, true, infoSink, debugShaderPrecision); parseContext.fragmentPrecisionHigh = fragmentPrecisionHigh; SetGlobalParseContext(&parseContext); // We preserve symbols at the built-in level from compile-to-compile. // Start pushing the user-defined symbols at global level. TScopedSymbolTableLevel scopedSymbolLevel(&symbolTable); // Parse shader. bool success = (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) && (parseContext.treeRoot != NULL); shaderVersion = parseContext.getShaderVersion(); if (success && MapSpecToShaderVersion(shaderSpec) < shaderVersion) { infoSink.info.prefix(EPrefixError); infoSink.info << "unsupported shader version"; success = false; } TIntermNode *root = NULL; if (success) { mPragma = parseContext.pragma(); if (mPragma.stdgl.invariantAll) { symbolTable.setGlobalInvariant(); } root = parseContext.treeRoot; success = intermediate.postProcess(root); // Disallow expressions deemed too complex. if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY)) success = limitExpressionComplexity(root); if (success) success = detectCallDepth(root, infoSink, (compileOptions & SH_LIMIT_CALL_STACK_DEPTH) != 0); if (success && shaderVersion == 300 && shaderType == GL_FRAGMENT_SHADER) success = validateOutputs(root); if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING)) success = validateLimitations(root); if (success && (compileOptions & SH_TIMING_RESTRICTIONS)) success = enforceTimingRestrictions(root, (compileOptions & SH_DEPENDENCY_GRAPH) != 0); if (success && shaderSpec == SH_CSS_SHADERS_SPEC) rewriteCSSShader(root); // Unroll for-loop markup needs to happen after validateLimitations pass. if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX)) { ForLoopUnrollMarker marker(ForLoopUnrollMarker::kIntegerIndex); root->traverse(&marker); } if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX)) { ForLoopUnrollMarker marker(ForLoopUnrollMarker::kSamplerArrayIndex); root->traverse(&marker); if (marker.samplerArrayIndexIsFloatLoopIndex()) { infoSink.info.prefix(EPrefixError); infoSink.info << "sampler array index is float loop index"; success = false; } } // Built-in function emulation needs to happen after validateLimitations pass. if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS)) builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root); // Clamping uniform array bounds needs to happen after validateLimitations pass. if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS)) arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root); if (success && shaderType == GL_VERTEX_SHADER && (compileOptions & SH_INIT_GL_POSITION)) initializeGLPosition(root); if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT)) { UnfoldShortCircuitAST unfoldShortCircuit; root->traverse(&unfoldShortCircuit); unfoldShortCircuit.updateTree(); } if (success && (compileOptions & SH_VARIABLES)) { collectVariables(root); if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS) { success = enforcePackingRestrictions(); if (!success) { infoSink.info.prefix(EPrefixError); infoSink.info << "too many uniforms"; } } if (success && shaderType == GL_VERTEX_SHADER && (compileOptions & SH_INIT_VARYINGS_WITHOUT_STATIC_USE)) initializeVaryingsWithoutStaticUse(root); } if (success && (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS)) { ScalarizeVecAndMatConstructorArgs scalarizer( shaderType, fragmentPrecisionHigh); root->traverse(&scalarizer); } if (success && (compileOptions & SH_REGENERATE_STRUCT_NAMES)) { RegenerateStructNames gen(symbolTable, shaderVersion); root->traverse(&gen); } } SetGlobalParseContext(NULL); if (success) return root; return NULL; }
bool TCompiler::compile(const char* const shaderStrings[], size_t numStrings, int compileOptions) { TScopedPoolAllocator scopedAlloc(&allocator); clearResults(); if (numStrings == 0) return true; // If compiling for WebGL, validate loop and indexing as well. if (IsWebGLBasedSpec(shaderSpec)) compileOptions |= SH_VALIDATE_LOOP_INDEXING; // First string is path of source file if flag is set. The actual source follows. const char* sourcePath = NULL; size_t firstSource = 0; if (compileOptions & SH_SOURCE_PATH) { sourcePath = shaderStrings[0]; ++firstSource; } TIntermediate intermediate(infoSink); TParseContext parseContext(symbolTable, extensionBehavior, intermediate, shaderType, shaderSpec, compileOptions, true, sourcePath, infoSink); parseContext.fragmentPrecisionHigh = fragmentPrecisionHigh; SetGlobalParseContext(&parseContext); // We preserve symbols at the built-in level from compile-to-compile. // Start pushing the user-defined symbols at global level. TScopedSymbolTableLevel scopedSymbolLevel(&symbolTable); // Parse shader. bool success = (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) && (parseContext.treeRoot != NULL); shaderVersion = parseContext.getShaderVersion(); if (success) { TIntermNode* root = parseContext.treeRoot; success = intermediate.postProcess(root); // Disallow expressions deemed too complex. if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY)) success = limitExpressionComplexity(root); if (success) success = detectCallDepth(root, infoSink, (compileOptions & SH_LIMIT_CALL_STACK_DEPTH) != 0); if (success && shaderVersion == 300 && shaderType == GL_FRAGMENT_SHADER) success = validateOutputs(root); if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING)) success = validateLimitations(root); if (success && (compileOptions & SH_TIMING_RESTRICTIONS)) success = enforceTimingRestrictions(root, (compileOptions & SH_DEPENDENCY_GRAPH) != 0); if (success && shaderSpec == SH_CSS_SHADERS_SPEC) rewriteCSSShader(root); // Unroll for-loop markup needs to happen after validateLimitations pass. if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX)) { ForLoopUnrollMarker marker(ForLoopUnrollMarker::kIntegerIndex); root->traverse(&marker); } if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX)) { ForLoopUnrollMarker marker(ForLoopUnrollMarker::kSamplerArrayIndex); root->traverse(&marker); if (marker.samplerArrayIndexIsFloatLoopIndex()) { infoSink.info.prefix(EPrefixError); infoSink.info << "sampler array index is float loop index"; success = false; } } // Built-in function emulation needs to happen after validateLimitations pass. if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS)) builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root); // Clamping uniform array bounds needs to happen after validateLimitations pass. if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS)) arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root); if (success && shaderType == GL_VERTEX_SHADER && (compileOptions & SH_INIT_GL_POSITION)) initializeGLPosition(root); if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT)) { UnfoldShortCircuitAST unfoldShortCircuit; root->traverse(&unfoldShortCircuit); unfoldShortCircuit.updateTree(); } if (success && (compileOptions & SH_VARIABLES)) { collectVariables(root); if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS) { success = enforcePackingRestrictions(); if (!success) { infoSink.info.prefix(EPrefixError); infoSink.info << "too many uniforms"; } } if (success && shaderType == GL_VERTEX_SHADER && (compileOptions & SH_INIT_VARYINGS_WITHOUT_STATIC_USE)) initializeVaryingsWithoutStaticUse(root); } if (success && (compileOptions & SH_INTERMEDIATE_TREE)) intermediate.outputTree(root); if (success && (compileOptions & SH_OBJECT_CODE)) translate(root); } // Cleanup memory. intermediate.remove(parseContext.treeRoot); SetGlobalParseContext(NULL); return success; }
int C_DECL Hlsl2Glsl_Parse( const ShHandle handle, const char* shaderString, int options ) { if (!InitThread()) return 0; if (handle == 0) return 0; HlslCrossCompiler* compiler = handle; GlobalPoolAllocator.push(); compiler->infoSink.info.erase(); compiler->infoSink.debug.erase(); if (!shaderString) return 1; TIntermediate intermediate(compiler->infoSink); TSymbolTable symbolTable(SymbolTables[compiler->getLanguage()]); GenerateBuiltInSymbolTable(compiler->infoSink, &symbolTable, compiler->getLanguage()); TParseContext parseContext(symbolTable, intermediate, compiler->getLanguage(), compiler->infoSink); GlobalParseContext = &parseContext; setInitialState(); InitPreprocessor(); // // Parse the application's shaders. All the following symbol table // work will be throw-away, so push a new allocation scope that can // be thrown away, then push a scope for the current shader's globals. // bool success = true; symbolTable.push(); if (!symbolTable.atGlobalLevel()) parseContext.infoSink.info.message(EPrefixInternalError, "Wrong symbol table level"); int ret = PaParseString(const_cast<char*>(shaderString), parseContext); if (ret) success = false; if (success && parseContext.treeRoot) { TIntermAggregate* aggRoot = parseContext.treeRoot->getAsAggregate(); if (aggRoot && aggRoot->getOp() == EOpNull) aggRoot->setOperator(EOpSequence); if (options & ETranslateOpIntermediate) intermediate.outputTree(parseContext.treeRoot); compiler->TransformAST (parseContext.treeRoot); compiler->ProduceGLSL (parseContext.treeRoot, (options & ETranslateOpUsePrecision) ? true : false); } else if (!success) { parseContext.infoSink.info.prefix(EPrefixError); parseContext.infoSink.info << parseContext.numErrors << " compilation errors. No code generated.\n\n"; success = false; if (options & ETranslateOpIntermediate) intermediate.outputTree(parseContext.treeRoot); } intermediate.remove(parseContext.treeRoot); // // Ensure symbol table is returned to the built-in level, // throwing away all but the built-ins. // while (! symbolTable.atSharedBuiltInLevel()) symbolTable.pop(); FinalizePreprocessor(); // // Throw away all the temporary memory used by the compilation process. // GlobalPoolAllocator.pop(); return success ? 1 : 0; }