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.
7 #include "compiler/translator/BuiltInFunctionEmulator.h"
8 #include "compiler/translator/DetectCallDepth.h"
9 #include "compiler/translator/ForLoopUnroll.h"
10 #include "compiler/translator/Initialize.h"
11 #include "compiler/translator/InitializeParseContext.h"
12 #include "compiler/translator/InitializeVariables.h"
13 #include "compiler/translator/ParseContext.h"
14 #include "compiler/translator/RenameFunction.h"
15 #include "compiler/translator/ShHandle.h"
16 #include "compiler/translator/UnfoldShortCircuitAST.h"
17 #include "compiler/translator/ValidateLimitations.h"
18 #include "compiler/translator/VariablePacker.h"
19 #include "compiler/translator/depgraph/DependencyGraph.h"
20 #include "compiler/translator/depgraph/DependencyGraphOutput.h"
21 #include "compiler/translator/timing/RestrictFragmentShaderTiming.h"
22 #include "compiler/translator/timing/RestrictVertexShaderTiming.h"
23 #include "third_party/compiler/ArrayBoundsClamper.h"
25 bool isWebGLBasedSpec(ShShaderSpec spec)
27 return spec == SH_WEBGL_SPEC || spec == SH_CSS_SHADERS_SPEC;
31 class TScopedPoolAllocator
34 TScopedPoolAllocator(TPoolAllocator* allocator) : mAllocator(allocator)
37 SetGlobalPoolAllocator(mAllocator);
39 ~TScopedPoolAllocator()
41 SetGlobalPoolAllocator(NULL);
46 TPoolAllocator* mAllocator;
49 class TScopedSymbolTableLevel
52 TScopedSymbolTableLevel(TSymbolTable* table) : mTable(table)
54 ASSERT(mTable->atBuiltInLevel());
57 ~TScopedSymbolTableLevel()
59 while (!mTable->atBuiltInLevel())
68 TShHandleBase::TShHandleBase()
71 SetGlobalPoolAllocator(&allocator);
74 TShHandleBase::~TShHandleBase()
76 SetGlobalPoolAllocator(NULL);
80 TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec)
84 maxExpressionComplexity(0),
86 fragmentPrecisionHigh(false),
87 clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC),
88 builtInFunctionEmulator(type)
92 TCompiler::~TCompiler()
96 bool TCompiler::Init(const ShBuiltInResources& resources)
98 maxUniformVectors = (shaderType == SH_VERTEX_SHADER) ?
99 resources.MaxVertexUniformVectors :
100 resources.MaxFragmentUniformVectors;
101 maxExpressionComplexity = resources.MaxExpressionComplexity;
102 maxCallStackDepth = resources.MaxCallStackDepth;
104 SetGlobalPoolAllocator(&allocator);
106 // Generate built-in symbol table.
107 if (!InitBuiltInSymbolTable(resources))
109 InitExtensionBehavior(resources, extensionBehavior);
110 fragmentPrecisionHigh = resources.FragmentPrecisionHigh == 1;
112 arrayBoundsClamper.SetClampingStrategy(resources.ArrayIndexClampingStrategy);
113 clampingStrategy = resources.ArrayIndexClampingStrategy;
115 hashFunction = resources.HashFunction;
120 bool TCompiler::compile(const char* const shaderStrings[],
124 TScopedPoolAllocator scopedAlloc(&allocator);
130 // If compiling for WebGL, validate loop and indexing as well.
131 if (isWebGLBasedSpec(shaderSpec))
132 compileOptions |= SH_VALIDATE_LOOP_INDEXING;
134 // First string is path of source file if flag is set. The actual source follows.
135 const char* sourcePath = NULL;
136 size_t firstSource = 0;
137 if (compileOptions & SH_SOURCE_PATH)
139 sourcePath = shaderStrings[0];
143 TIntermediate intermediate(infoSink);
144 TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
145 shaderType, shaderSpec, compileOptions, true,
146 sourcePath, infoSink);
147 parseContext.fragmentPrecisionHigh = fragmentPrecisionHigh;
148 SetGlobalParseContext(&parseContext);
150 // We preserve symbols at the built-in level from compile-to-compile.
151 // Start pushing the user-defined symbols at global level.
152 TScopedSymbolTableLevel scopedSymbolLevel(&symbolTable);
156 (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) &&
157 (parseContext.treeRoot != NULL);
160 TIntermNode* root = parseContext.treeRoot;
161 success = intermediate.postProcess(root);
163 // Disallow expressions deemed too complex.
164 if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY))
165 success = limitExpressionComplexity(root);
168 success = detectCallDepth(root, infoSink, (compileOptions & SH_LIMIT_CALL_STACK_DEPTH) != 0);
170 if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
171 success = validateLimitations(root);
173 if (success && (compileOptions & SH_TIMING_RESTRICTIONS))
174 success = enforceTimingRestrictions(root, (compileOptions & SH_DEPENDENCY_GRAPH) != 0);
176 if (success && shaderSpec == SH_CSS_SHADERS_SPEC)
177 rewriteCSSShader(root);
179 // Unroll for-loop markup needs to happen after validateLimitations pass.
180 if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX))
182 ForLoopUnrollMarker marker(ForLoopUnrollMarker::kIntegerIndex);
183 root->traverse(&marker);
185 if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX))
187 ForLoopUnrollMarker marker(ForLoopUnrollMarker::kSamplerArrayIndex);
188 root->traverse(&marker);
189 if (marker.samplerArrayIndexIsFloatLoopIndex())
191 infoSink.info.prefix(EPrefixError);
192 infoSink.info << "sampler array index is float loop index";
197 // Built-in function emulation needs to happen after validateLimitations pass.
198 if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS))
199 builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root);
201 // Clamping uniform array bounds needs to happen after validateLimitations pass.
202 if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS))
203 arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root);
205 if (success && shaderType == SH_VERTEX_SHADER && (compileOptions & SH_INIT_GL_POSITION))
206 initializeGLPosition(root);
208 if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT))
210 UnfoldShortCircuitAST unfoldShortCircuit;
211 root->traverse(&unfoldShortCircuit);
212 unfoldShortCircuit.updateTree();
215 if (success && (compileOptions & SH_VARIABLES))
217 collectVariables(root);
218 if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS)
220 success = enforcePackingRestrictions();
223 infoSink.info.prefix(EPrefixError);
224 infoSink.info << "too many uniforms";
227 if (success && shaderType == SH_VERTEX_SHADER &&
228 (compileOptions & SH_INIT_VARYINGS_WITHOUT_STATIC_USE))
229 initializeVaryingsWithoutStaticUse(root);
232 if (success && (compileOptions & SH_INTERMEDIATE_TREE))
233 intermediate.outputTree(root);
235 if (success && (compileOptions & SH_OBJECT_CODE))
240 intermediate.remove(parseContext.treeRoot);
245 bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
247 compileResources = resources;
249 assert(symbolTable.isEmpty());
253 integer.type = EbtInt;
255 integer.matrix = false;
256 integer.array = false;
258 TPublicType floatingPoint;
259 floatingPoint.type = EbtFloat;
260 floatingPoint.size = 1;
261 floatingPoint.matrix = false;
262 floatingPoint.array = false;
266 sampler.matrix = false;
267 sampler.array = false;
271 case SH_FRAGMENT_SHADER:
272 symbolTable.setDefaultPrecision(integer, EbpMedium);
274 case SH_VERTEX_SHADER:
275 symbolTable.setDefaultPrecision(integer, EbpHigh);
276 symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
279 assert(false && "Language not supported");
281 // We set defaults for all the sampler types, even those that are
282 // only available if an extension exists.
283 for (int samplerType = EbtGuardSamplerBegin + 1;
284 samplerType < EbtGuardSamplerEnd; ++samplerType)
286 sampler.type = static_cast<TBasicType>(samplerType);
287 symbolTable.setDefaultPrecision(sampler, EbpLow);
290 InsertBuiltInFunctions(shaderType, shaderSpec, resources, symbolTable);
292 IdentifyBuiltIns(shaderType, shaderSpec, resources, symbolTable);
297 void TCompiler::clearResults()
299 arrayBoundsClamper.Cleanup();
300 infoSink.info.erase();
301 infoSink.obj.erase();
302 infoSink.debug.erase();
308 builtInFunctionEmulator.Cleanup();
313 bool TCompiler::detectCallDepth(TIntermNode* root, TInfoSink& infoSink, bool limitCallStackDepth)
315 DetectCallDepth detect(infoSink, limitCallStackDepth, maxCallStackDepth);
316 root->traverse(&detect);
317 switch (detect.detectCallDepth())
319 case DetectCallDepth::kErrorNone:
321 case DetectCallDepth::kErrorMissingMain:
322 infoSink.info.prefix(EPrefixError);
323 infoSink.info << "Missing main()";
325 case DetectCallDepth::kErrorRecursion:
326 infoSink.info.prefix(EPrefixError);
327 infoSink.info << "Function recursion detected";
329 case DetectCallDepth::kErrorMaxDepthExceeded:
330 infoSink.info.prefix(EPrefixError);
331 infoSink.info << "Function call stack too deep";
339 void TCompiler::rewriteCSSShader(TIntermNode* root)
341 RenameFunction renamer("main(", "css_main(");
342 root->traverse(&renamer);
345 bool TCompiler::validateLimitations(TIntermNode* root)
347 ValidateLimitations validate(shaderType, infoSink.info);
348 root->traverse(&validate);
349 return validate.numErrors() == 0;
352 bool TCompiler::enforceTimingRestrictions(TIntermNode* root, bool outputGraph)
354 if (shaderSpec != SH_WEBGL_SPEC)
356 infoSink.info << "Timing restrictions must be enforced under the WebGL spec.";
360 if (shaderType == SH_FRAGMENT_SHADER)
362 TDependencyGraph graph(root);
364 // Output any errors first.
365 bool success = enforceFragmentShaderTimingRestrictions(graph);
367 // Then, output the dependency graph.
370 TDependencyGraphOutput output(infoSink.info);
371 output.outputAllSpanningTrees(graph);
378 return enforceVertexShaderTimingRestrictions(root);
382 bool TCompiler::limitExpressionComplexity(TIntermNode* root)
384 TMaxDepthTraverser traverser(maxExpressionComplexity+1);
385 root->traverse(&traverser);
387 if (traverser.getMaxDepth() > maxExpressionComplexity)
389 infoSink.info << "Expression too complex.";
393 TDependencyGraph graph(root);
395 for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls();
396 iter != graph.endUserDefinedFunctionCalls();
399 TGraphFunctionCall* samplerSymbol = *iter;
400 TDependencyGraphTraverser graphTraverser;
401 samplerSymbol->traverse(&graphTraverser);
407 bool TCompiler::enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph)
409 RestrictFragmentShaderTiming restrictor(infoSink.info);
410 restrictor.enforceRestrictions(graph);
411 return restrictor.numErrors() == 0;
414 bool TCompiler::enforceVertexShaderTimingRestrictions(TIntermNode* root)
416 RestrictVertexShaderTiming restrictor(infoSink.info);
417 restrictor.enforceRestrictions(root);
418 return restrictor.numErrors() == 0;
421 void TCompiler::collectVariables(TIntermNode* root)
423 CollectVariables collect(attribs, uniforms, varyings, hashFunction);
424 root->traverse(&collect);
427 bool TCompiler::enforcePackingRestrictions()
429 VariablePacker packer;
430 return packer.CheckVariablesWithinPackingLimits(maxUniformVectors, uniforms);
433 void TCompiler::initializeGLPosition(TIntermNode* root)
435 InitializeVariables::InitVariableInfoList variables;
436 InitializeVariables::InitVariableInfo var(
437 "gl_Position", TType(EbtFloat, EbpUndefined, EvqPosition, 4));
438 variables.push_back(var);
439 InitializeVariables initializer(variables);
440 root->traverse(&initializer);
443 void TCompiler::initializeVaryingsWithoutStaticUse(TIntermNode* root)
445 InitializeVariables::InitVariableInfoList variables;
446 for (size_t ii = 0; ii < varyings.size(); ++ii)
448 const TVariableInfo& varying = varyings[ii];
449 if (varying.staticUse)
451 unsigned char size = 0;
453 switch (varying.type)
482 TType type(EbtFloat, EbpUndefined, EvqVaryingOut, size, matrix, varying.isArray);
483 TString name = varying.name.c_str();
486 type.setArraySize(varying.size);
487 name = name.substr(0, name.find_first_of('['));
490 InitializeVariables::InitVariableInfo var(name, type);
491 variables.push_back(var);
493 InitializeVariables initializer(variables);
494 root->traverse(&initializer);
497 const TExtensionBehavior& TCompiler::getExtensionBehavior() const
499 return extensionBehavior;
502 const ShBuiltInResources& TCompiler::getResources() const
504 return compileResources;
507 const ArrayBoundsClamper& TCompiler::getArrayBoundsClamper() const
509 return arrayBoundsClamper;
512 ShArrayIndexClampingStrategy TCompiler::getArrayIndexClampingStrategy() const
514 return clampingStrategy;
517 const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
519 return builtInFunctionEmulator;