Home | History | Annotate | Download | only in translator
      1 //
      2 // Copyright (c) 2002-2014 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/translator/BuiltInFunctionEmulator.h"
      8 #include "compiler/translator/Compiler.h"
      9 #include "compiler/translator/DetectCallDepth.h"
     10 #include "compiler/translator/ForLoopUnroll.h"
     11 #include "compiler/translator/Initialize.h"
     12 #include "compiler/translator/InitializeParseContext.h"
     13 #include "compiler/translator/InitializeVariables.h"
     14 #include "compiler/translator/ParseContext.h"
     15 #include "compiler/translator/RegenerateStructNames.h"
     16 #include "compiler/translator/RenameFunction.h"
     17 #include "compiler/translator/ScalarizeVecAndMatConstructorArgs.h"
     18 #include "compiler/translator/UnfoldShortCircuitAST.h"
     19 #include "compiler/translator/ValidateLimitations.h"
     20 #include "compiler/translator/ValidateOutputs.h"
     21 #include "compiler/translator/VariablePacker.h"
     22 #include "compiler/translator/depgraph/DependencyGraph.h"
     23 #include "compiler/translator/depgraph/DependencyGraphOutput.h"
     24 #include "compiler/translator/timing/RestrictFragmentShaderTiming.h"
     25 #include "compiler/translator/timing/RestrictVertexShaderTiming.h"
     26 #include "third_party/compiler/ArrayBoundsClamper.h"
     27 #include "angle_gl.h"
     28 #include "common/utilities.h"
     29 
     30 bool IsWebGLBasedSpec(ShShaderSpec spec)
     31 {
     32      return spec == SH_WEBGL_SPEC || spec == SH_CSS_SHADERS_SPEC;
     33 }
     34 
     35 size_t GetGlobalMaxTokenSize(ShShaderSpec spec)
     36 {
     37     // WebGL defines a max token legnth of 256, while ES2 leaves max token
     38     // size undefined. ES3 defines a max size of 1024 characters.
     39     if (IsWebGLBasedSpec(spec))
     40     {
     41         return 256;
     42     }
     43     else
     44     {
     45         return 1024;
     46     }
     47 }
     48 
     49 namespace {
     50 class TScopedPoolAllocator
     51 {
     52   public:
     53     TScopedPoolAllocator(TPoolAllocator* allocator) : mAllocator(allocator)
     54     {
     55         mAllocator->push();
     56         SetGlobalPoolAllocator(mAllocator);
     57     }
     58     ~TScopedPoolAllocator()
     59     {
     60         SetGlobalPoolAllocator(NULL);
     61         mAllocator->pop();
     62     }
     63 
     64   private:
     65     TPoolAllocator* mAllocator;
     66 };
     67 
     68 class TScopedSymbolTableLevel
     69 {
     70   public:
     71     TScopedSymbolTableLevel(TSymbolTable* table) : mTable(table)
     72     {
     73         ASSERT(mTable->atBuiltInLevel());
     74         mTable->push();
     75     }
     76     ~TScopedSymbolTableLevel()
     77     {
     78         while (!mTable->atBuiltInLevel())
     79             mTable->pop();
     80     }
     81 
     82   private:
     83     TSymbolTable* mTable;
     84 };
     85 }  // namespace
     86 
     87 TShHandleBase::TShHandleBase()
     88 {
     89     allocator.push();
     90     SetGlobalPoolAllocator(&allocator);
     91 }
     92 
     93 TShHandleBase::~TShHandleBase()
     94 {
     95     SetGlobalPoolAllocator(NULL);
     96     allocator.popAll();
     97 }
     98 
     99 TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
    100     : shaderType(type),
    101       shaderSpec(spec),
    102       outputType(output),
    103       maxUniformVectors(0),
    104       maxExpressionComplexity(0),
    105       maxCallStackDepth(0),
    106       fragmentPrecisionHigh(false),
    107       clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC),
    108       builtInFunctionEmulator(type)
    109 {
    110 }
    111 
    112 TCompiler::~TCompiler()
    113 {
    114 }
    115 
    116 bool TCompiler::Init(const ShBuiltInResources& resources)
    117 {
    118     shaderVersion = 100;
    119     maxUniformVectors = (shaderType == GL_VERTEX_SHADER) ?
    120         resources.MaxVertexUniformVectors :
    121         resources.MaxFragmentUniformVectors;
    122     maxExpressionComplexity = resources.MaxExpressionComplexity;
    123     maxCallStackDepth = resources.MaxCallStackDepth;
    124 
    125     SetGlobalPoolAllocator(&allocator);
    126 
    127     // Generate built-in symbol table.
    128     if (!InitBuiltInSymbolTable(resources))
    129         return false;
    130     InitExtensionBehavior(resources, extensionBehavior);
    131     fragmentPrecisionHigh = resources.FragmentPrecisionHigh == 1;
    132 
    133     arrayBoundsClamper.SetClampingStrategy(resources.ArrayIndexClampingStrategy);
    134     clampingStrategy = resources.ArrayIndexClampingStrategy;
    135 
    136     hashFunction = resources.HashFunction;
    137 
    138     return true;
    139 }
    140 
    141 bool TCompiler::compile(const char* const shaderStrings[],
    142                         size_t numStrings,
    143                         int compileOptions)
    144 {
    145     TScopedPoolAllocator scopedAlloc(&allocator);
    146     clearResults();
    147 
    148     if (numStrings == 0)
    149         return true;
    150 
    151     // If compiling for WebGL, validate loop and indexing as well.
    152     if (IsWebGLBasedSpec(shaderSpec))
    153         compileOptions |= SH_VALIDATE_LOOP_INDEXING;
    154 
    155     // First string is path of source file if flag is set. The actual source follows.
    156     const char* sourcePath = NULL;
    157     size_t firstSource = 0;
    158     if (compileOptions & SH_SOURCE_PATH)
    159     {
    160         sourcePath = shaderStrings[0];
    161         ++firstSource;
    162     }
    163 
    164     TIntermediate intermediate(infoSink);
    165     TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
    166                                shaderType, shaderSpec, compileOptions, true,
    167                                sourcePath, infoSink);
    168     parseContext.fragmentPrecisionHigh = fragmentPrecisionHigh;
    169     SetGlobalParseContext(&parseContext);
    170 
    171     // We preserve symbols at the built-in level from compile-to-compile.
    172     // Start pushing the user-defined symbols at global level.
    173     TScopedSymbolTableLevel scopedSymbolLevel(&symbolTable);
    174 
    175     // Parse shader.
    176     bool success =
    177         (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) &&
    178         (parseContext.treeRoot != NULL);
    179 
    180     shaderVersion = parseContext.getShaderVersion();
    181 
    182     if (success)
    183     {
    184         TIntermNode* root = parseContext.treeRoot;
    185         success = intermediate.postProcess(root);
    186 
    187         // Disallow expressions deemed too complex.
    188         if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY))
    189             success = limitExpressionComplexity(root);
    190 
    191         if (success)
    192             success = detectCallDepth(root, infoSink, (compileOptions & SH_LIMIT_CALL_STACK_DEPTH) != 0);
    193 
    194         if (success && shaderVersion == 300 && shaderType == GL_FRAGMENT_SHADER)
    195             success = validateOutputs(root);
    196 
    197         if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
    198             success = validateLimitations(root);
    199 
    200         if (success && (compileOptions & SH_TIMING_RESTRICTIONS))
    201             success = enforceTimingRestrictions(root, (compileOptions & SH_DEPENDENCY_GRAPH) != 0);
    202 
    203         if (success && shaderSpec == SH_CSS_SHADERS_SPEC)
    204             rewriteCSSShader(root);
    205 
    206         // Unroll for-loop markup needs to happen after validateLimitations pass.
    207         if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX))
    208         {
    209             ForLoopUnrollMarker marker(ForLoopUnrollMarker::kIntegerIndex);
    210             root->traverse(&marker);
    211         }
    212         if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX))
    213         {
    214             ForLoopUnrollMarker marker(ForLoopUnrollMarker::kSamplerArrayIndex);
    215             root->traverse(&marker);
    216             if (marker.samplerArrayIndexIsFloatLoopIndex())
    217             {
    218                 infoSink.info.prefix(EPrefixError);
    219                 infoSink.info << "sampler array index is float loop index";
    220                 success = false;
    221             }
    222         }
    223 
    224         // Built-in function emulation needs to happen after validateLimitations pass.
    225         if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS))
    226             builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root);
    227 
    228         // Clamping uniform array bounds needs to happen after validateLimitations pass.
    229         if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS))
    230             arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root);
    231 
    232         if (success && shaderType == GL_VERTEX_SHADER && (compileOptions & SH_INIT_GL_POSITION))
    233             initializeGLPosition(root);
    234 
    235         if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT))
    236         {
    237             UnfoldShortCircuitAST unfoldShortCircuit;
    238             root->traverse(&unfoldShortCircuit);
    239             unfoldShortCircuit.updateTree();
    240         }
    241 
    242         if (success && (compileOptions & SH_VARIABLES))
    243         {
    244             collectVariables(root);
    245             if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS)
    246             {
    247                 success = enforcePackingRestrictions();
    248                 if (!success)
    249                 {
    250                     infoSink.info.prefix(EPrefixError);
    251                     infoSink.info << "too many uniforms";
    252                 }
    253             }
    254             if (success && shaderType == GL_VERTEX_SHADER &&
    255                 (compileOptions & SH_INIT_VARYINGS_WITHOUT_STATIC_USE))
    256                 initializeVaryingsWithoutStaticUse(root);
    257         }
    258 
    259         if (success && (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS))
    260         {
    261             ScalarizeVecAndMatConstructorArgs scalarizer(
    262                 shaderType, fragmentPrecisionHigh);
    263             root->traverse(&scalarizer);
    264         }
    265 
    266         if (success && (compileOptions & SH_REGENERATE_STRUCT_NAMES))
    267         {
    268             RegenerateStructNames gen(symbolTable, shaderVersion);
    269             root->traverse(&gen);
    270         }
    271 
    272         if (success && (compileOptions & SH_INTERMEDIATE_TREE))
    273             intermediate.outputTree(root);
    274 
    275         if (success && (compileOptions & SH_OBJECT_CODE))
    276             translate(root);
    277     }
    278 
    279     // Cleanup memory.
    280     intermediate.remove(parseContext.treeRoot);
    281     SetGlobalParseContext(NULL);
    282     return success;
    283 }
    284 
    285 bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
    286 {
    287     compileResources = resources;
    288     setResourceString();
    289 
    290     assert(symbolTable.isEmpty());
    291     symbolTable.push();   // COMMON_BUILTINS
    292     symbolTable.push();   // ESSL1_BUILTINS
    293     symbolTable.push();   // ESSL3_BUILTINS
    294 
    295     TPublicType integer;
    296     integer.type = EbtInt;
    297     integer.primarySize = 1;
    298     integer.secondarySize = 1;
    299     integer.array = false;
    300 
    301     TPublicType floatingPoint;
    302     floatingPoint.type = EbtFloat;
    303     floatingPoint.primarySize = 1;
    304     floatingPoint.secondarySize = 1;
    305     floatingPoint.array = false;
    306 
    307     TPublicType sampler;
    308     sampler.primarySize = 1;
    309     sampler.secondarySize = 1;
    310     sampler.array = false;
    311 
    312     switch(shaderType)
    313     {
    314       case GL_FRAGMENT_SHADER:
    315         symbolTable.setDefaultPrecision(integer, EbpMedium);
    316         break;
    317       case GL_VERTEX_SHADER:
    318         symbolTable.setDefaultPrecision(integer, EbpHigh);
    319         symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
    320         break;
    321       default:
    322         assert(false && "Language not supported");
    323     }
    324     // We set defaults for all the sampler types, even those that are
    325     // only available if an extension exists.
    326     for (int samplerType = EbtGuardSamplerBegin + 1;
    327          samplerType < EbtGuardSamplerEnd; ++samplerType)
    328     {
    329         sampler.type = static_cast<TBasicType>(samplerType);
    330         symbolTable.setDefaultPrecision(sampler, EbpLow);
    331     }
    332 
    333     InsertBuiltInFunctions(shaderType, shaderSpec, resources, symbolTable);
    334 
    335     IdentifyBuiltIns(shaderType, shaderSpec, resources, symbolTable);
    336 
    337     return true;
    338 }
    339 
    340 void TCompiler::setResourceString()
    341 {
    342     std::ostringstream strstream;
    343     strstream << ":MaxVertexAttribs:" << compileResources.MaxVertexAttribs
    344               << ":MaxVertexUniformVectors:" << compileResources.MaxVertexUniformVectors
    345               << ":MaxVaryingVectors:" << compileResources.MaxVaryingVectors
    346               << ":MaxVertexTextureImageUnits:" << compileResources.MaxVertexTextureImageUnits
    347               << ":MaxCombinedTextureImageUnits:" << compileResources.MaxCombinedTextureImageUnits
    348               << ":MaxTextureImageUnits:" << compileResources.MaxTextureImageUnits
    349               << ":MaxFragmentUniformVectors:" << compileResources.MaxFragmentUniformVectors
    350               << ":MaxDrawBuffers:" << compileResources.MaxDrawBuffers
    351               << ":OES_standard_derivatives:" << compileResources.OES_standard_derivatives
    352               << ":OES_EGL_image_external:" << compileResources.OES_EGL_image_external
    353               << ":ARB_texture_rectangle:" << compileResources.ARB_texture_rectangle
    354               << ":EXT_draw_buffers:" << compileResources.EXT_draw_buffers
    355               << ":FragmentPrecisionHigh:" << compileResources.FragmentPrecisionHigh
    356               << ":MaxExpressionComplexity:" << compileResources.MaxExpressionComplexity
    357               << ":MaxCallStackDepth:" << compileResources.MaxCallStackDepth
    358               << ":EXT_frag_depth:" << compileResources.EXT_frag_depth
    359               << ":EXT_shader_texture_lod:" << compileResources.EXT_shader_texture_lod
    360               << ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors
    361               << ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors
    362               << ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset
    363               << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset;
    364 
    365     builtInResourcesString = strstream.str();
    366 }
    367 
    368 void TCompiler::clearResults()
    369 {
    370     arrayBoundsClamper.Cleanup();
    371     infoSink.info.erase();
    372     infoSink.obj.erase();
    373     infoSink.debug.erase();
    374 
    375     attributes.clear();
    376     outputVariables.clear();
    377     uniforms.clear();
    378     expandedUniforms.clear();
    379     varyings.clear();
    380     expandedVaryings.clear();
    381     interfaceBlocks.clear();
    382 
    383     builtInFunctionEmulator.Cleanup();
    384 
    385     nameMap.clear();
    386 }
    387 
    388 bool TCompiler::detectCallDepth(TIntermNode* root, TInfoSink& infoSink, bool limitCallStackDepth)
    389 {
    390     DetectCallDepth detect(infoSink, limitCallStackDepth, maxCallStackDepth);
    391     root->traverse(&detect);
    392     switch (detect.detectCallDepth())
    393     {
    394       case DetectCallDepth::kErrorNone:
    395         return true;
    396       case DetectCallDepth::kErrorMissingMain:
    397         infoSink.info.prefix(EPrefixError);
    398         infoSink.info << "Missing main()";
    399         return false;
    400       case DetectCallDepth::kErrorRecursion:
    401         infoSink.info.prefix(EPrefixError);
    402         infoSink.info << "Function recursion detected";
    403         return false;
    404       case DetectCallDepth::kErrorMaxDepthExceeded:
    405         infoSink.info.prefix(EPrefixError);
    406         infoSink.info << "Function call stack too deep";
    407         return false;
    408       default:
    409         UNREACHABLE();
    410         return false;
    411     }
    412 }
    413 
    414 bool TCompiler::validateOutputs(TIntermNode* root)
    415 {
    416     ValidateOutputs validateOutputs(infoSink.info, compileResources.MaxDrawBuffers);
    417     root->traverse(&validateOutputs);
    418     return (validateOutputs.numErrors() == 0);
    419 }
    420 
    421 void TCompiler::rewriteCSSShader(TIntermNode* root)
    422 {
    423     RenameFunction renamer("main(", "css_main(");
    424     root->traverse(&renamer);
    425 }
    426 
    427 bool TCompiler::validateLimitations(TIntermNode* root)
    428 {
    429     ValidateLimitations validate(shaderType, infoSink.info);
    430     root->traverse(&validate);
    431     return validate.numErrors() == 0;
    432 }
    433 
    434 bool TCompiler::enforceTimingRestrictions(TIntermNode* root, bool outputGraph)
    435 {
    436     if (shaderSpec != SH_WEBGL_SPEC)
    437     {
    438         infoSink.info << "Timing restrictions must be enforced under the WebGL spec.";
    439         return false;
    440     }
    441 
    442     if (shaderType == GL_FRAGMENT_SHADER)
    443     {
    444         TDependencyGraph graph(root);
    445 
    446         // Output any errors first.
    447         bool success = enforceFragmentShaderTimingRestrictions(graph);
    448 
    449         // Then, output the dependency graph.
    450         if (outputGraph)
    451         {
    452             TDependencyGraphOutput output(infoSink.info);
    453             output.outputAllSpanningTrees(graph);
    454         }
    455 
    456         return success;
    457     }
    458     else
    459     {
    460         return enforceVertexShaderTimingRestrictions(root);
    461     }
    462 }
    463 
    464 bool TCompiler::limitExpressionComplexity(TIntermNode* root)
    465 {
    466     TMaxDepthTraverser traverser(maxExpressionComplexity+1);
    467     root->traverse(&traverser);
    468 
    469     if (traverser.getMaxDepth() > maxExpressionComplexity)
    470     {
    471         infoSink.info << "Expression too complex.";
    472         return false;
    473     }
    474 
    475     TDependencyGraph graph(root);
    476 
    477     for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls();
    478          iter != graph.endUserDefinedFunctionCalls();
    479          ++iter)
    480     {
    481         TGraphFunctionCall* samplerSymbol = *iter;
    482         TDependencyGraphTraverser graphTraverser;
    483         samplerSymbol->traverse(&graphTraverser);
    484     }
    485 
    486     return true;
    487 }
    488 
    489 bool TCompiler::enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph)
    490 {
    491     RestrictFragmentShaderTiming restrictor(infoSink.info);
    492     restrictor.enforceRestrictions(graph);
    493     return restrictor.numErrors() == 0;
    494 }
    495 
    496 bool TCompiler::enforceVertexShaderTimingRestrictions(TIntermNode* root)
    497 {
    498     RestrictVertexShaderTiming restrictor(infoSink.info);
    499     restrictor.enforceRestrictions(root);
    500     return restrictor.numErrors() == 0;
    501 }
    502 
    503 void TCompiler::collectVariables(TIntermNode* root)
    504 {
    505     sh::CollectVariables collect(&attributes,
    506                                  &outputVariables,
    507                                  &uniforms,
    508                                  &varyings,
    509                                  &interfaceBlocks,
    510                                  hashFunction);
    511     root->traverse(&collect);
    512 
    513     // For backwards compatiblity with ShGetVariableInfo, expand struct
    514     // uniforms and varyings into separate variables for each field.
    515     sh::ExpandVariables(uniforms, &expandedUniforms);
    516     sh::ExpandVariables(varyings, &expandedVaryings);
    517 }
    518 
    519 bool TCompiler::enforcePackingRestrictions()
    520 {
    521     VariablePacker packer;
    522     return packer.CheckVariablesWithinPackingLimits(maxUniformVectors, expandedUniforms);
    523 }
    524 
    525 void TCompiler::initializeGLPosition(TIntermNode* root)
    526 {
    527     InitializeVariables::InitVariableInfoList variables;
    528     InitializeVariables::InitVariableInfo var(
    529         "gl_Position", TType(EbtFloat, EbpUndefined, EvqPosition, 4));
    530     variables.push_back(var);
    531     InitializeVariables initializer(variables);
    532     root->traverse(&initializer);
    533 }
    534 
    535 void TCompiler::initializeVaryingsWithoutStaticUse(TIntermNode* root)
    536 {
    537     InitializeVariables::InitVariableInfoList variables;
    538     for (size_t ii = 0; ii < varyings.size(); ++ii)
    539     {
    540         const sh::Varying& varying = varyings[ii];
    541         if (varying.staticUse)
    542             continue;
    543         unsigned char primarySize = static_cast<unsigned char>(gl::VariableColumnCount(varying.type));
    544         unsigned char secondarySize = static_cast<unsigned char>(gl::VariableRowCount(varying.type));
    545         TType type(EbtFloat, EbpUndefined, EvqVaryingOut, primarySize, secondarySize, varying.isArray());
    546         TString name = varying.name.c_str();
    547         if (varying.isArray())
    548         {
    549             type.setArraySize(varying.arraySize);
    550             name = name.substr(0, name.find_first_of('['));
    551         }
    552 
    553         InitializeVariables::InitVariableInfo var(name, type);
    554         variables.push_back(var);
    555     }
    556     InitializeVariables initializer(variables);
    557     root->traverse(&initializer);
    558 }
    559 
    560 const TExtensionBehavior& TCompiler::getExtensionBehavior() const
    561 {
    562     return extensionBehavior;
    563 }
    564 
    565 const ShBuiltInResources& TCompiler::getResources() const
    566 {
    567     return compileResources;
    568 }
    569 
    570 const ArrayBoundsClamper& TCompiler::getArrayBoundsClamper() const
    571 {
    572     return arrayBoundsClamper;
    573 }
    574 
    575 ShArrayIndexClampingStrategy TCompiler::getArrayIndexClampingStrategy() const
    576 {
    577     return clampingStrategy;
    578 }
    579 
    580 const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
    581 {
    582     return builtInFunctionEmulator;
    583 }
    584