bool TCompiler::compile(const char* const shaderStrings[], size_t numStrings, int compileOptions) { if (numStrings == 0) return true; TScopedPoolAllocator scopedAlloc(&allocator); TIntermNode *root = compileTreeImpl(shaderStrings, numStrings, compileOptions); if (root) { if (compileOptions & SH_INTERMEDIATE_TREE) TIntermediate::outputTree(root, infoSink.info); if (compileOptions & SH_OBJECT_CODE) translate(root, compileOptions); // The IntermNode tree doesn't need to be deleted here, since the // memory will be freed in a big chunk by the PoolAllocator. return true; } return false; }
bool TCompiler::Init(const ShBuiltInResources& resources) { maxUniformVectors = (shaderType == SH_VERTEX_SHADER) ? resources.MaxVertexUniformVectors : resources.MaxFragmentUniformVectors; TScopedPoolAllocator scopedAlloc(&allocator, false); // Generate built-in symbol table. if (!InitBuiltInSymbolTable(resources)) return false; InitExtensionBehavior(resources, extensionBehavior); fragmentPrecisionHigh = resources.FragmentPrecisionHigh == 1; // ArrayIndexClampingStrategy's enum starts at 1, so 0 is 'default'. if (resources.ArrayIndexClampingStrategy) { clampingStrategy = resources.ArrayIndexClampingStrategy; } arrayBoundsClamper.SetClampingStrategy(clampingStrategy); hashFunction = resources.HashFunction; return true; }
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; }
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 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; }
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) { mPragma = parseContext.pragma(); if (mPragma.stdgl.invariantAll) { symbolTable.setGlobalInvariant(); } 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_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); } 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; }