gfx/angle/src/compiler/Compiler.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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 //
     7 #include "compiler/BuiltInFunctionEmulator.h"
     8 #include "compiler/DetectCallDepth.h"
     9 #include "compiler/ForLoopUnroll.h"
    10 #include "compiler/Initialize.h"
    11 #include "compiler/InitializeParseContext.h"
    12 #include "compiler/MapLongVariableNames.h"
    13 #include "compiler/ParseHelper.h"
    14 #include "compiler/RenameFunction.h"
    15 #include "compiler/ShHandle.h"
    16 #include "compiler/ValidateLimitations.h"
    17 #include "compiler/VariablePacker.h"
    18 #include "compiler/depgraph/DependencyGraph.h"
    19 #include "compiler/depgraph/DependencyGraphOutput.h"
    20 #include "compiler/timing/RestrictFragmentShaderTiming.h"
    21 #include "compiler/timing/RestrictVertexShaderTiming.h"
    22 #include "third_party/compiler/ArrayBoundsClamper.h"
    24 bool isWebGLBasedSpec(ShShaderSpec spec)
    25 {
    26      return spec == SH_WEBGL_SPEC || spec == SH_CSS_SHADERS_SPEC;
    27 }
    29 namespace {
    30 class TScopedPoolAllocator {
    31 public:
    32     TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop)
    33         : mAllocator(allocator), mPushPopAllocator(pushPop) {
    34         if (mPushPopAllocator) mAllocator->push();
    35         SetGlobalPoolAllocator(mAllocator);
    36     }
    37     ~TScopedPoolAllocator() {
    38         SetGlobalPoolAllocator(NULL);
    39         if (mPushPopAllocator) mAllocator->pop();
    40     }
    42 private:
    43     TPoolAllocator* mAllocator;
    44     bool mPushPopAllocator;
    45 };
    46 }  // namespace
    48 TShHandleBase::TShHandleBase() {
    49     allocator.push();
    50     SetGlobalPoolAllocator(&allocator);
    51 }
    53 TShHandleBase::~TShHandleBase() {
    54     SetGlobalPoolAllocator(NULL);
    55     allocator.popAll();
    56 }
    58 TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec)
    59     : shaderType(type),
    60       shaderSpec(spec),
    61       maxUniformVectors(0),
    62       maxExpressionComplexity(0),
    63       maxCallStackDepth(0),
    64       fragmentPrecisionHigh(false),
    65       clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC),
    66       builtInFunctionEmulator(type)
    67 {
    68     longNameMap = LongNameMap::GetInstance();
    69 }
    71 TCompiler::~TCompiler()
    72 {
    73     ASSERT(longNameMap);
    74     longNameMap->Release();
    75 }
    77 bool TCompiler::Init(const ShBuiltInResources& resources)
    78 {
    79     maxUniformVectors = (shaderType == SH_VERTEX_SHADER) ?
    80         resources.MaxVertexUniformVectors :
    81         resources.MaxFragmentUniformVectors;
    82     maxExpressionComplexity = resources.MaxExpressionComplexity;
    83     maxCallStackDepth = resources.MaxCallStackDepth;
    84     TScopedPoolAllocator scopedAlloc(&allocator, false);
    86     // Generate built-in symbol table.
    87     if (!InitBuiltInSymbolTable(resources))
    88         return false;
    89     InitExtensionBehavior(resources, extensionBehavior);
    90     fragmentPrecisionHigh = resources.FragmentPrecisionHigh == 1;
    92     // ArrayIndexClampingStrategy's enum starts at 1, so 0 is 'default'.
    93     if (resources.ArrayIndexClampingStrategy) {
    94         clampingStrategy = resources.ArrayIndexClampingStrategy;
    95     }
    96     arrayBoundsClamper.SetClampingStrategy(clampingStrategy);
    98     hashFunction = resources.HashFunction;
   100     return true;
   101 }
   103 bool TCompiler::compile(const char* const shaderStrings[],
   104                         size_t numStrings,
   105                         int compileOptions)
   106 {
   107     TScopedPoolAllocator scopedAlloc(&allocator, true);
   108     clearResults();
   110     if (numStrings == 0)
   111         return true;
   113     // If compiling for WebGL, validate loop and indexing as well.
   114     if (isWebGLBasedSpec(shaderSpec))
   115         compileOptions |= SH_VALIDATE_LOOP_INDEXING;
   117     // First string is path of source file if flag is set. The actual source follows.
   118     const char* sourcePath = NULL;
   119     size_t firstSource = 0;
   120     if (compileOptions & SH_SOURCE_PATH)
   121     {
   122         sourcePath = shaderStrings[0];
   123         ++firstSource;
   124     }
   126     TIntermediate intermediate(infoSink);
   127     TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
   128                                shaderType, shaderSpec, compileOptions, true,
   129                                sourcePath, infoSink);
   130     parseContext.fragmentPrecisionHigh = fragmentPrecisionHigh;
   131     SetGlobalParseContext(&parseContext);
   133     // We preserve symbols at the built-in level from compile-to-compile.
   134     // Start pushing the user-defined symbols at global level.
   135     symbolTable.push();
   136     if (!symbolTable.atGlobalLevel()) {
   137         infoSink.info.prefix(EPrefixInternalError);
   138         infoSink.info << "Wrong symbol table level";
   139     }
   141     // Parse shader.
   142     bool success =
   143         (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) &&
   144         (parseContext.treeRoot != NULL);
   145     if (success) {
   146         TIntermNode* root = parseContext.treeRoot;
   147         success = intermediate.postProcess(root);
   149         if (success)
   150             success = detectCallDepth(root, infoSink, (compileOptions & SH_LIMIT_CALL_STACK_DEPTH) != 0);
   152         if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
   153             success = validateLimitations(root);
   155         if (success && (compileOptions & SH_TIMING_RESTRICTIONS))
   156             success = enforceTimingRestrictions(root, (compileOptions & SH_DEPENDENCY_GRAPH) != 0);
   158         if (success && shaderSpec == SH_CSS_SHADERS_SPEC)
   159             rewriteCSSShader(root);
   161         // Unroll for-loop markup needs to happen after validateLimitations pass.
   162         if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX))
   163             ForLoopUnroll::MarkForLoopsWithIntegerIndicesForUnrolling(root);
   165         // Built-in function emulation needs to happen after validateLimitations pass.
   166         if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS))
   167             builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root);
   169         // Clamping uniform array bounds needs to happen after validateLimitations pass.
   170         if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS))
   171             arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root);
   173         // Disallow expressions deemed too complex.
   174         if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY))
   175             success = limitExpressionComplexity(root);
   177         // Call mapLongVariableNames() before collectAttribsUniforms() so in
   178         // collectAttribsUniforms() we already have the mapped symbol names and
   179         // we could composite mapped and original variable names.
   180         // Also, if we hash all the names, then no need to do this for long names.
   181         if (success && (compileOptions & SH_MAP_LONG_VARIABLE_NAMES) && hashFunction == NULL)
   182             mapLongVariableNames(root);
   184         if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS)) {
   185             collectAttribsUniforms(root);
   186             if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS) {
   187                 success = enforcePackingRestrictions();
   188                 if (!success) {
   189                     infoSink.info.prefix(EPrefixError);
   190                     infoSink.info << "too many uniforms";
   191                 }
   192             }
   193         }
   195         if (success && (compileOptions & SH_INTERMEDIATE_TREE))
   196             intermediate.outputTree(root);
   198         if (success && (compileOptions & SH_OBJECT_CODE))
   199             translate(root);
   200     }
   202     // Cleanup memory.
   203     intermediate.remove(parseContext.treeRoot);
   204     // Ensure symbol table is returned to the built-in level,
   205     // throwing away all but the built-ins.
   206     while (!symbolTable.atBuiltInLevel())
   207         symbolTable.pop();
   209     return success;
   210 }
   212 bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
   213 {
   214     compileResources = resources;
   216     assert(symbolTable.isEmpty());
   217     symbolTable.push();
   219     TPublicType integer;
   220     integer.type = EbtInt;
   221     integer.size = 1;
   222     integer.matrix = false;
   223     integer.array = false;
   225     TPublicType floatingPoint;
   226     floatingPoint.type = EbtFloat;
   227     floatingPoint.size = 1;
   228     floatingPoint.matrix = false;
   229     floatingPoint.array = false;
   231     switch(shaderType)
   232     {
   233       case SH_FRAGMENT_SHADER:
   234         symbolTable.setDefaultPrecision(integer, EbpMedium);
   235         break;
   236       case SH_VERTEX_SHADER:
   237         symbolTable.setDefaultPrecision(integer, EbpHigh);
   238         symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
   239         break;
   240       default: assert(false && "Language not supported");
   241     }
   243     InsertBuiltInFunctions(shaderType, shaderSpec, resources, symbolTable);
   245     IdentifyBuiltIns(shaderType, shaderSpec, resources, symbolTable);
   247     return true;
   248 }
   250 void TCompiler::clearResults()
   251 {
   252     arrayBoundsClamper.Cleanup();
   253     infoSink.info.erase();
   254     infoSink.obj.erase();
   255     infoSink.debug.erase();
   257     attribs.clear();
   258     uniforms.clear();
   260     builtInFunctionEmulator.Cleanup();
   262     nameMap.clear();
   263 }
   265 bool TCompiler::detectCallDepth(TIntermNode* root, TInfoSink& infoSink, bool limitCallStackDepth)
   266 {
   267     DetectCallDepth detect(infoSink, limitCallStackDepth, maxCallStackDepth);
   268     root->traverse(&detect);
   269     switch (detect.detectCallDepth()) {
   270         case DetectCallDepth::kErrorNone:
   271             return true;
   272         case DetectCallDepth::kErrorMissingMain:
   273             infoSink.info.prefix(EPrefixError);
   274             infoSink.info << "Missing main()";
   275             return false;
   276         case DetectCallDepth::kErrorRecursion:
   277             infoSink.info.prefix(EPrefixError);
   278             infoSink.info << "Function recursion detected";
   279             return false;
   280         case DetectCallDepth::kErrorMaxDepthExceeded:
   281             infoSink.info.prefix(EPrefixError);
   282             infoSink.info << "Function call stack too deep";
   283             return false;
   284         default:
   285             UNREACHABLE();
   286             return false;
   287     }
   288 }
   290 void TCompiler::rewriteCSSShader(TIntermNode* root)
   291 {
   292     RenameFunction renamer("main(", "css_main(");
   293     root->traverse(&renamer);
   294 }
   296 bool TCompiler::validateLimitations(TIntermNode* root) {
   297     ValidateLimitations validate(shaderType, infoSink.info);
   298     root->traverse(&validate);
   299     return validate.numErrors() == 0;
   300 }
   302 bool TCompiler::enforceTimingRestrictions(TIntermNode* root, bool outputGraph)
   303 {
   304     if (shaderSpec != SH_WEBGL_SPEC) {
   305         infoSink.info << "Timing restrictions must be enforced under the WebGL spec.";
   306         return false;
   307     }
   309     if (shaderType == SH_FRAGMENT_SHADER) {
   310         TDependencyGraph graph(root);
   312         // Output any errors first.
   313         bool success = enforceFragmentShaderTimingRestrictions(graph);
   315         // Then, output the dependency graph.
   316         if (outputGraph) {
   317             TDependencyGraphOutput output(infoSink.info);
   318             output.outputAllSpanningTrees(graph);
   319         }
   321         return success;
   322     }
   323     else {
   324         return enforceVertexShaderTimingRestrictions(root);
   325     }
   326 }
   328 bool TCompiler::limitExpressionComplexity(TIntermNode* root)
   329 {
   330     TIntermTraverser traverser;
   331     root->traverse(&traverser);
   332     TDependencyGraph graph(root);
   334     for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls();
   335          iter != graph.endUserDefinedFunctionCalls();
   336          ++iter)
   337     {
   338         TGraphFunctionCall* samplerSymbol = *iter;
   339         TDependencyGraphTraverser graphTraverser;
   340         samplerSymbol->traverse(&graphTraverser);
   341     }
   343     if (traverser.getMaxDepth() > maxExpressionComplexity) {
   344         infoSink.info << "Expression too complex.";
   345         return false;
   346     }
   347     return true;
   348 }
   350 bool TCompiler::enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph)
   351 {
   352     RestrictFragmentShaderTiming restrictor(infoSink.info);
   353     restrictor.enforceRestrictions(graph);
   354     return restrictor.numErrors() == 0;
   355 }
   357 bool TCompiler::enforceVertexShaderTimingRestrictions(TIntermNode* root)
   358 {
   359     RestrictVertexShaderTiming restrictor(infoSink.info);
   360     restrictor.enforceRestrictions(root);
   361     return restrictor.numErrors() == 0;
   362 }
   364 void TCompiler::collectAttribsUniforms(TIntermNode* root)
   365 {
   366     CollectAttribsUniforms collect(attribs, uniforms, hashFunction);
   367     root->traverse(&collect);
   368 }
   370 bool TCompiler::enforcePackingRestrictions()
   371 {
   372     VariablePacker packer;
   373     return packer.CheckVariablesWithinPackingLimits(maxUniformVectors, uniforms);
   374 }
   376 void TCompiler::mapLongVariableNames(TIntermNode* root)
   377 {
   378     ASSERT(longNameMap);
   379     MapLongVariableNames map(longNameMap);
   380     root->traverse(&map);
   381 }
   383 int TCompiler::getMappedNameMaxLength() const
   384 {
   385     return MAX_SHORTENED_IDENTIFIER_SIZE + 1;
   386 }
   388 const TExtensionBehavior& TCompiler::getExtensionBehavior() const
   389 {
   390     return extensionBehavior;
   391 }
   393 const ShBuiltInResources& TCompiler::getResources() const
   394 {
   395     return compileResources;
   396 }
   398 const ArrayBoundsClamper& TCompiler::getArrayBoundsClamper() const
   399 {
   400     return arrayBoundsClamper;
   401 }
   403 ShArrayIndexClampingStrategy TCompiler::getArrayIndexClampingStrategy() const
   404 {
   405     return clampingStrategy;
   406 }
   408 const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
   409 {
   410     return builtInFunctionEmulator;
   411 }

mercurial