Home | History | Annotate | Download | only in compiler
      1 //
      2 // Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
      3 // Use of this source code is governed by a BSD-style license that can be
      4 // found in the LICENSE file.
      5 //
      6 
      7 #include "compiler/BuiltInFunctionEmulator.h"
      8 #include "compiler/DetectCallDepth.h"
      9 #include "compiler/ForLoopUnroll.h"
     10 #include "compiler/Initialize.h"
     11 #include "compiler/InitializeGLPosition.h"
     12 #include "compiler/InitializeParseContext.h"
     13 #include "compiler/MapLongVariableNames.h"
     14 #include "compiler/ParseContext.h"
     15 #include "compiler/RenameFunction.h"
     16 #include "compiler/ShHandle.h"
     17 #include "compiler/UnfoldShortCircuitAST.h"
     18 #include "compiler/ValidateLimitations.h"
     19 #include "compiler/VariablePacker.h"
     20 #include "compiler/depgraph/DependencyGraph.h"
     21 #include "compiler/depgraph/DependencyGraphOutput.h"
     22 #include "compiler/timing/RestrictFragmentShaderTiming.h"
     23 #include "compiler/timing/RestrictVertexShaderTiming.h"
     24 #include "third_party/compiler/ArrayBoundsClamper.h"
     25 
     26 bool isWebGLBasedSpec(ShShaderSpec spec)
     27 {
     28      return spec == SH_WEBGL_SPEC || spec == SH_CSS_SHADERS_SPEC;
     29 }
     30 
     31 namespace {
     32 class TScopedPoolAllocator {
     33 public:
     34     TScopedPoolAllocator(TPoolAllocator* allocator) : mAllocator(allocator) {
     35         mAllocator->push();
     36         SetGlobalPoolAllocator(mAllocator);
     37     }
     38     ~TScopedPoolAllocator() {
     39         SetGlobalPoolAllocator(NULL);
     40         mAllocator->pop();
     41     }
     42 
     43 private:
     44     TPoolAllocator* mAllocator;
     45 };
     46 
     47 class TScopedSymbolTableLevel {
     48 public:
     49     TScopedSymbolTableLevel(TSymbolTable* table) : mTable(table) {
     50         ASSERT(mTable->atBuiltInLevel());
     51         mTable->push();
     52     }
     53     ~TScopedSymbolTableLevel() {
     54         while (!mTable->atBuiltInLevel())
     55             mTable->pop();
     56     }
     57 
     58 private:
     59     TSymbolTable* mTable;
     60 };
     61 }  // namespace
     62 
     63 TShHandleBase::TShHandleBase() {
     64     allocator.push();
     65     SetGlobalPoolAllocator(&allocator);
     66 }
     67 
     68 TShHandleBase::~TShHandleBase() {
     69     SetGlobalPoolAllocator(NULL);
     70     allocator.popAll();
     71 }
     72 
     73 TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec)
     74     : shaderType(type),
     75       shaderSpec(spec),
     76       maxUniformVectors(0),
     77       maxExpressionComplexity(0),
     78       maxCallStackDepth(0),
     79       fragmentPrecisionHigh(false),
     80       clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC),
     81       builtInFunctionEmulator(type)
     82 {
     83     longNameMap = LongNameMap::GetInstance();
     84 }
     85 
     86 TCompiler::~TCompiler()
     87 {
     88     ASSERT(longNameMap);
     89     longNameMap->Release();
     90 }
     91 
     92 bool TCompiler::Init(const ShBuiltInResources& resources)
     93 {
     94     maxUniformVectors = (shaderType == SH_VERTEX_SHADER) ?
     95         resources.MaxVertexUniformVectors :
     96         resources.MaxFragmentUniformVectors;
     97     maxExpressionComplexity = resources.MaxExpressionComplexity;
     98     maxCallStackDepth = resources.MaxCallStackDepth;
     99 
    100     SetGlobalPoolAllocator(&allocator);
    101 
    102     // Generate built-in symbol table.
    103     if (!InitBuiltInSymbolTable(resources))
    104         return false;
    105     InitExtensionBehavior(resources, extensionBehavior);
    106     fragmentPrecisionHigh = resources.FragmentPrecisionHigh == 1;
    107 
    108     arrayBoundsClamper.SetClampingStrategy(resources.ArrayIndexClampingStrategy);
    109     clampingStrategy = resources.ArrayIndexClampingStrategy;
    110 
    111     hashFunction = resources.HashFunction;
    112 
    113     return true;
    114 }
    115 
    116 bool TCompiler::compile(const char* const shaderStrings[],
    117                         size_t numStrings,
    118                         int compileOptions)
    119 {
    120     TScopedPoolAllocator scopedAlloc(&allocator);
    121     clearResults();
    122 
    123     if (numStrings == 0)
    124         return true;
    125 
    126     // If compiling for WebGL, validate loop and indexing as well.
    127     if (isWebGLBasedSpec(shaderSpec))
    128         compileOptions |= SH_VALIDATE_LOOP_INDEXING;
    129 
    130     // First string is path of source file if flag is set. The actual source follows.
    131     const char* sourcePath = NULL;
    132     size_t firstSource = 0;
    133     if (compileOptions & SH_SOURCE_PATH)
    134     {
    135         sourcePath = shaderStrings[0];
    136         ++firstSource;
    137     }
    138 
    139     TIntermediate intermediate(infoSink);
    140     TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
    141                                shaderType, shaderSpec, compileOptions, true,
    142                                sourcePath, infoSink);
    143     parseContext.fragmentPrecisionHigh = fragmentPrecisionHigh;
    144     SetGlobalParseContext(&parseContext);
    145 
    146     // We preserve symbols at the built-in level from compile-to-compile.
    147     // Start pushing the user-defined symbols at global level.
    148     TScopedSymbolTableLevel scopedSymbolLevel(&symbolTable);
    149 
    150     // Parse shader.
    151     bool success =
    152         (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) &&
    153         (parseContext.treeRoot != NULL);
    154     if (success) {
    155         TIntermNode* root = parseContext.treeRoot;
    156         success = intermediate.postProcess(root);
    157 
    158         if (success)
    159             success = detectCallDepth(root, infoSink, (compileOptions & SH_LIMIT_CALL_STACK_DEPTH) != 0);
    160 
    161         if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
    162             success = validateLimitations(root);
    163 
    164         if (success && (compileOptions & SH_TIMING_RESTRICTIONS))
    165             success = enforceTimingRestrictions(root, (compileOptions & SH_DEPENDENCY_GRAPH) != 0);
    166 
    167         if (success && shaderSpec == SH_CSS_SHADERS_SPEC)
    168             rewriteCSSShader(root);
    169 
    170         // Unroll for-loop markup needs to happen after validateLimitations pass.
    171         if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX))
    172             ForLoopUnroll::MarkForLoopsWithIntegerIndicesForUnrolling(root);
    173 
    174         // Built-in function emulation needs to happen after validateLimitations pass.
    175         if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS))
    176             builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root);
    177 
    178         // Clamping uniform array bounds needs to happen after validateLimitations pass.
    179         if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS))
    180             arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root);
    181 
    182         // Disallow expressions deemed too complex.
    183         if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY))
    184             success = limitExpressionComplexity(root);
    185 
    186         // Call mapLongVariableNames() before collectAttribsUniforms() so in
    187         // collectAttribsUniforms() we already have the mapped symbol names and
    188         // we could composite mapped and original variable names.
    189         // Also, if we hash all the names, then no need to do this for long names.
    190         if (success && (compileOptions & SH_MAP_LONG_VARIABLE_NAMES) && hashFunction == NULL)
    191             mapLongVariableNames(root);
    192 
    193         if (success && shaderType == SH_VERTEX_SHADER && (compileOptions & SH_INIT_GL_POSITION)) {
    194             InitializeGLPosition initGLPosition;
    195             root->traverse(&initGLPosition);
    196         }
    197 
    198 	if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT)) {
    199             UnfoldShortCircuitAST unfoldShortCircuit;
    200             root->traverse(&unfoldShortCircuit);
    201             unfoldShortCircuit.updateTree();
    202 	}
    203 
    204         if (success && (compileOptions & SH_VARIABLES)) {
    205             collectVariables(root);
    206             if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS) {
    207                 success = enforcePackingRestrictions();
    208                 if (!success) {
    209                     infoSink.info.prefix(EPrefixError);
    210                     infoSink.info << "too many uniforms";
    211                 }
    212             }
    213         }
    214 
    215         if (success && (compileOptions & SH_INTERMEDIATE_TREE))
    216             intermediate.outputTree(root);
    217 
    218         if (success && (compileOptions & SH_OBJECT_CODE))
    219             translate(root);
    220     }
    221 
    222     // Cleanup memory.
    223     intermediate.remove(parseContext.treeRoot);
    224 
    225     return success;
    226 }
    227 
    228 bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
    229 {
    230     compileResources = resources;
    231 
    232     assert(symbolTable.isEmpty());
    233     symbolTable.push();
    234 
    235     TPublicType integer;
    236     integer.type = EbtInt;
    237     integer.size = 1;
    238     integer.matrix = false;
    239     integer.array = false;
    240 
    241     TPublicType floatingPoint;
    242     floatingPoint.type = EbtFloat;
    243     floatingPoint.size = 1;
    244     floatingPoint.matrix = false;
    245     floatingPoint.array = false;
    246 
    247     TPublicType sampler;
    248     sampler.size = 1;
    249     sampler.matrix = false;
    250     sampler.array = false;
    251 
    252     switch(shaderType)
    253     {
    254       case SH_FRAGMENT_SHADER:
    255         symbolTable.setDefaultPrecision(integer, EbpMedium);
    256         break;
    257       case SH_VERTEX_SHADER:
    258         symbolTable.setDefaultPrecision(integer, EbpHigh);
    259         symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
    260         break;
    261       default: assert(false && "Language not supported");
    262     }
    263     // We set defaults for all the sampler types, even those that are
    264     // only available if an extension exists.
    265     for (int samplerType = EbtGuardSamplerBegin + 1;
    266          samplerType < EbtGuardSamplerEnd; ++samplerType) {
    267         sampler.type = static_cast<TBasicType>(samplerType);
    268         symbolTable.setDefaultPrecision(sampler, EbpLow);
    269     }
    270 
    271     InsertBuiltInFunctions(shaderType, shaderSpec, resources, symbolTable);
    272 
    273     IdentifyBuiltIns(shaderType, shaderSpec, resources, symbolTable);
    274 
    275     return true;
    276 }
    277 
    278 void TCompiler::clearResults()
    279 {
    280     arrayBoundsClamper.Cleanup();
    281     infoSink.info.erase();
    282     infoSink.obj.erase();
    283     infoSink.debug.erase();
    284 
    285     attribs.clear();
    286     uniforms.clear();
    287     varyings.clear();
    288 
    289     builtInFunctionEmulator.Cleanup();
    290 
    291     nameMap.clear();
    292 }
    293 
    294 bool TCompiler::detectCallDepth(TIntermNode* root, TInfoSink& infoSink, bool limitCallStackDepth)
    295 {
    296     DetectCallDepth detect(infoSink, limitCallStackDepth, maxCallStackDepth);
    297     root->traverse(&detect);
    298     switch (detect.detectCallDepth()) {
    299         case DetectCallDepth::kErrorNone:
    300             return true;
    301         case DetectCallDepth::kErrorMissingMain:
    302             infoSink.info.prefix(EPrefixError);
    303             infoSink.info << "Missing main()";
    304             return false;
    305         case DetectCallDepth::kErrorRecursion:
    306             infoSink.info.prefix(EPrefixError);
    307             infoSink.info << "Function recursion detected";
    308             return false;
    309         case DetectCallDepth::kErrorMaxDepthExceeded:
    310             infoSink.info.prefix(EPrefixError);
    311             infoSink.info << "Function call stack too deep";
    312             return false;
    313         default:
    314             UNREACHABLE();
    315             return false;
    316     }
    317 }
    318 
    319 void TCompiler::rewriteCSSShader(TIntermNode* root)
    320 {
    321     RenameFunction renamer("main(", "css_main(");
    322     root->traverse(&renamer);
    323 }
    324 
    325 bool TCompiler::validateLimitations(TIntermNode* root) {
    326     ValidateLimitations validate(shaderType, infoSink.info);
    327     root->traverse(&validate);
    328     return validate.numErrors() == 0;
    329 }
    330 
    331 bool TCompiler::enforceTimingRestrictions(TIntermNode* root, bool outputGraph)
    332 {
    333     if (shaderSpec != SH_WEBGL_SPEC) {
    334         infoSink.info << "Timing restrictions must be enforced under the WebGL spec.";
    335         return false;
    336     }
    337 
    338     if (shaderType == SH_FRAGMENT_SHADER) {
    339         TDependencyGraph graph(root);
    340 
    341         // Output any errors first.
    342         bool success = enforceFragmentShaderTimingRestrictions(graph);
    343 
    344         // Then, output the dependency graph.
    345         if (outputGraph) {
    346             TDependencyGraphOutput output(infoSink.info);
    347             output.outputAllSpanningTrees(graph);
    348         }
    349 
    350         return success;
    351     }
    352     else {
    353         return enforceVertexShaderTimingRestrictions(root);
    354     }
    355 }
    356 
    357 bool TCompiler::limitExpressionComplexity(TIntermNode* root)
    358 {
    359     TIntermTraverser traverser;
    360     root->traverse(&traverser);
    361     TDependencyGraph graph(root);
    362 
    363     for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls();
    364          iter != graph.endUserDefinedFunctionCalls();
    365          ++iter)
    366     {
    367         TGraphFunctionCall* samplerSymbol = *iter;
    368         TDependencyGraphTraverser graphTraverser;
    369         samplerSymbol->traverse(&graphTraverser);
    370     }
    371 
    372     if (traverser.getMaxDepth() > maxExpressionComplexity) {
    373         infoSink.info << "Expression too complex.";
    374         return false;
    375     }
    376     return true;
    377 }
    378 
    379 bool TCompiler::enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph)
    380 {
    381     RestrictFragmentShaderTiming restrictor(infoSink.info);
    382     restrictor.enforceRestrictions(graph);
    383     return restrictor.numErrors() == 0;
    384 }
    385 
    386 bool TCompiler::enforceVertexShaderTimingRestrictions(TIntermNode* root)
    387 {
    388     RestrictVertexShaderTiming restrictor(infoSink.info);
    389     restrictor.enforceRestrictions(root);
    390     return restrictor.numErrors() == 0;
    391 }
    392 
    393 void TCompiler::collectVariables(TIntermNode* root)
    394 {
    395     CollectVariables collect(attribs, uniforms, varyings, hashFunction);
    396     root->traverse(&collect);
    397 }
    398 
    399 bool TCompiler::enforcePackingRestrictions()
    400 {
    401     VariablePacker packer;
    402     return packer.CheckVariablesWithinPackingLimits(maxUniformVectors, uniforms);
    403 }
    404 
    405 void TCompiler::mapLongVariableNames(TIntermNode* root)
    406 {
    407     ASSERT(longNameMap);
    408     MapLongVariableNames map(longNameMap);
    409     root->traverse(&map);
    410 }
    411 
    412 int TCompiler::getMappedNameMaxLength() const
    413 {
    414     return MAX_SHORTENED_IDENTIFIER_SIZE + 1;
    415 }
    416 
    417 const TExtensionBehavior& TCompiler::getExtensionBehavior() const
    418 {
    419     return extensionBehavior;
    420 }
    421 
    422 const ShBuiltInResources& TCompiler::getResources() const
    423 {
    424     return compileResources;
    425 }
    426 
    427 const ArrayBoundsClamper& TCompiler::getArrayBoundsClamper() const
    428 {
    429     return arrayBoundsClamper;
    430 }
    431 
    432 ShArrayIndexClampingStrategy TCompiler::getArrayIndexClampingStrategy() const
    433 {
    434     return clampingStrategy;
    435 }
    436 
    437 const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
    438 {
    439     return builtInFunctionEmulator;
    440 }
    441