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.
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"
28 #include "common/utilities.h"
30 bool IsWebGLBasedSpec(ShShaderSpec spec)
32 return (spec == SH_WEBGL_SPEC ||
33 spec == SH_CSS_SHADERS_SPEC ||
34 spec == SH_WEBGL2_SPEC);
37 size_t GetGlobalMaxTokenSize(ShShaderSpec spec)
39 // WebGL defines a max token legnth of 256, while ES2 leaves max token
40 // size undefined. ES3 defines a max size of 1024 characters.
44 case SH_CSS_SHADERS_SPEC:
53 class TScopedPoolAllocator
56 TScopedPoolAllocator(TPoolAllocator* allocator) : mAllocator(allocator)
59 SetGlobalPoolAllocator(mAllocator);
61 ~TScopedPoolAllocator()
63 SetGlobalPoolAllocator(NULL);
68 TPoolAllocator* mAllocator;
71 class TScopedSymbolTableLevel
74 TScopedSymbolTableLevel(TSymbolTable* table) : mTable(table)
76 ASSERT(mTable->atBuiltInLevel());
79 ~TScopedSymbolTableLevel()
81 while (!mTable->atBuiltInLevel())
89 int MapSpecToShaderVersion(ShShaderSpec spec)
95 case SH_CSS_SHADERS_SPEC:
108 TShHandleBase::TShHandleBase()
111 SetGlobalPoolAllocator(&allocator);
114 TShHandleBase::~TShHandleBase()
116 SetGlobalPoolAllocator(NULL);
120 TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
124 maxUniformVectors(0),
125 maxExpressionComplexity(0),
126 maxCallStackDepth(0),
127 fragmentPrecisionHigh(false),
128 clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC),
129 builtInFunctionEmulator(type)
133 TCompiler::~TCompiler()
137 bool TCompiler::Init(const ShBuiltInResources& resources)
140 maxUniformVectors = (shaderType == GL_VERTEX_SHADER) ?
141 resources.MaxVertexUniformVectors :
142 resources.MaxFragmentUniformVectors;
143 maxExpressionComplexity = resources.MaxExpressionComplexity;
144 maxCallStackDepth = resources.MaxCallStackDepth;
146 SetGlobalPoolAllocator(&allocator);
148 // Generate built-in symbol table.
149 if (!InitBuiltInSymbolTable(resources))
151 InitExtensionBehavior(resources, extensionBehavior);
152 fragmentPrecisionHigh = resources.FragmentPrecisionHigh == 1;
154 arrayBoundsClamper.SetClampingStrategy(resources.ArrayIndexClampingStrategy);
155 clampingStrategy = resources.ArrayIndexClampingStrategy;
157 hashFunction = resources.HashFunction;
162 bool TCompiler::compile(const char* const shaderStrings[],
166 TScopedPoolAllocator scopedAlloc(&allocator);
172 // If compiling for WebGL, validate loop and indexing as well.
173 if (IsWebGLBasedSpec(shaderSpec))
174 compileOptions |= SH_VALIDATE_LOOP_INDEXING;
176 // First string is path of source file if flag is set. The actual source follows.
177 const char* sourcePath = NULL;
178 size_t firstSource = 0;
179 if (compileOptions & SH_SOURCE_PATH)
181 sourcePath = shaderStrings[0];
185 TIntermediate intermediate(infoSink);
186 TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
187 shaderType, shaderSpec, compileOptions, true,
188 sourcePath, infoSink);
189 parseContext.fragmentPrecisionHigh = fragmentPrecisionHigh;
190 SetGlobalParseContext(&parseContext);
192 // We preserve symbols at the built-in level from compile-to-compile.
193 // Start pushing the user-defined symbols at global level.
194 TScopedSymbolTableLevel scopedSymbolLevel(&symbolTable);
198 (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) &&
199 (parseContext.treeRoot != NULL);
201 shaderVersion = parseContext.getShaderVersion();
202 if (success && MapSpecToShaderVersion(shaderSpec) < shaderVersion)
204 infoSink.info.prefix(EPrefixError);
205 infoSink.info << "unsupported shader version";
211 mPragma = parseContext.pragma();
212 if (mPragma.stdgl.invariantAll)
214 symbolTable.setGlobalInvariant();
217 TIntermNode* root = parseContext.treeRoot;
218 success = intermediate.postProcess(root);
220 // Disallow expressions deemed too complex.
221 if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY))
222 success = limitExpressionComplexity(root);
225 success = detectCallDepth(root, infoSink, (compileOptions & SH_LIMIT_CALL_STACK_DEPTH) != 0);
227 if (success && shaderVersion == 300 && shaderType == GL_FRAGMENT_SHADER)
228 success = validateOutputs(root);
230 if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
231 success = validateLimitations(root);
233 if (success && (compileOptions & SH_TIMING_RESTRICTIONS))
234 success = enforceTimingRestrictions(root, (compileOptions & SH_DEPENDENCY_GRAPH) != 0);
236 if (success && shaderSpec == SH_CSS_SHADERS_SPEC)
237 rewriteCSSShader(root);
239 // Unroll for-loop markup needs to happen after validateLimitations pass.
240 if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX))
242 ForLoopUnrollMarker marker(ForLoopUnrollMarker::kIntegerIndex);
243 root->traverse(&marker);
245 if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX))
247 ForLoopUnrollMarker marker(ForLoopUnrollMarker::kSamplerArrayIndex);
248 root->traverse(&marker);
249 if (marker.samplerArrayIndexIsFloatLoopIndex())
251 infoSink.info.prefix(EPrefixError);
252 infoSink.info << "sampler array index is float loop index";
257 // Built-in function emulation needs to happen after validateLimitations pass.
258 if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS))
259 builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root);
261 // Clamping uniform array bounds needs to happen after validateLimitations pass.
262 if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS))
263 arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root);
265 if (success && shaderType == GL_VERTEX_SHADER && (compileOptions & SH_INIT_GL_POSITION))
266 initializeGLPosition(root);
268 if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT))
270 UnfoldShortCircuitAST unfoldShortCircuit;
271 root->traverse(&unfoldShortCircuit);
272 unfoldShortCircuit.updateTree();
275 if (success && (compileOptions & SH_VARIABLES))
277 collectVariables(root);
278 if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS)
280 success = enforcePackingRestrictions();
283 infoSink.info.prefix(EPrefixError);
284 infoSink.info << "too many uniforms";
287 if (success && shaderType == GL_VERTEX_SHADER &&
288 (compileOptions & SH_INIT_VARYINGS_WITHOUT_STATIC_USE))
289 initializeVaryingsWithoutStaticUse(root);
292 if (success && (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS))
294 ScalarizeVecAndMatConstructorArgs scalarizer(
295 shaderType, fragmentPrecisionHigh);
296 root->traverse(&scalarizer);
299 if (success && (compileOptions & SH_REGENERATE_STRUCT_NAMES))
301 RegenerateStructNames gen(symbolTable, shaderVersion);
302 root->traverse(&gen);
305 if (success && (compileOptions & SH_INTERMEDIATE_TREE))
306 intermediate.outputTree(root);
308 if (success && (compileOptions & SH_OBJECT_CODE))
313 intermediate.remove(parseContext.treeRoot);
314 SetGlobalParseContext(NULL);
318 bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
320 compileResources = resources;
323 assert(symbolTable.isEmpty());
324 symbolTable.push(); // COMMON_BUILTINS
325 symbolTable.push(); // ESSL1_BUILTINS
326 symbolTable.push(); // ESSL3_BUILTINS
329 integer.type = EbtInt;
330 integer.primarySize = 1;
331 integer.secondarySize = 1;
332 integer.array = false;
334 TPublicType floatingPoint;
335 floatingPoint.type = EbtFloat;
336 floatingPoint.primarySize = 1;
337 floatingPoint.secondarySize = 1;
338 floatingPoint.array = false;
341 sampler.primarySize = 1;
342 sampler.secondarySize = 1;
343 sampler.array = false;
347 case GL_FRAGMENT_SHADER:
348 symbolTable.setDefaultPrecision(integer, EbpMedium);
350 case GL_VERTEX_SHADER:
351 symbolTable.setDefaultPrecision(integer, EbpHigh);
352 symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
355 assert(false && "Language not supported");
357 // We set defaults for all the sampler types, even those that are
358 // only available if an extension exists.
359 for (int samplerType = EbtGuardSamplerBegin + 1;
360 samplerType < EbtGuardSamplerEnd; ++samplerType)
362 sampler.type = static_cast<TBasicType>(samplerType);
363 symbolTable.setDefaultPrecision(sampler, EbpLow);
366 InsertBuiltInFunctions(shaderType, shaderSpec, resources, symbolTable);
368 IdentifyBuiltIns(shaderType, shaderSpec, resources, symbolTable);
373 void TCompiler::setResourceString()
375 std::ostringstream strstream;
376 strstream << ":MaxVertexAttribs:" << compileResources.MaxVertexAttribs
377 << ":MaxVertexUniformVectors:" << compileResources.MaxVertexUniformVectors
378 << ":MaxVaryingVectors:" << compileResources.MaxVaryingVectors
379 << ":MaxVertexTextureImageUnits:" << compileResources.MaxVertexTextureImageUnits
380 << ":MaxCombinedTextureImageUnits:" << compileResources.MaxCombinedTextureImageUnits
381 << ":MaxTextureImageUnits:" << compileResources.MaxTextureImageUnits
382 << ":MaxFragmentUniformVectors:" << compileResources.MaxFragmentUniformVectors
383 << ":MaxDrawBuffers:" << compileResources.MaxDrawBuffers
384 << ":OES_standard_derivatives:" << compileResources.OES_standard_derivatives
385 << ":OES_EGL_image_external:" << compileResources.OES_EGL_image_external
386 << ":ARB_texture_rectangle:" << compileResources.ARB_texture_rectangle
387 << ":EXT_draw_buffers:" << compileResources.EXT_draw_buffers
388 << ":FragmentPrecisionHigh:" << compileResources.FragmentPrecisionHigh
389 << ":MaxExpressionComplexity:" << compileResources.MaxExpressionComplexity
390 << ":MaxCallStackDepth:" << compileResources.MaxCallStackDepth
391 << ":EXT_frag_depth:" << compileResources.EXT_frag_depth
392 << ":EXT_shader_texture_lod:" << compileResources.EXT_shader_texture_lod
393 << ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors
394 << ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors
395 << ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset
396 << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset
397 << ":NV_draw_buffers:" << compileResources.NV_draw_buffers;
399 builtInResourcesString = strstream.str();
402 void TCompiler::clearResults()
404 arrayBoundsClamper.Cleanup();
405 infoSink.info.erase();
406 infoSink.obj.erase();
407 infoSink.debug.erase();
410 outputVariables.clear();
412 expandedUniforms.clear();
414 interfaceBlocks.clear();
416 builtInFunctionEmulator.Cleanup();
421 bool TCompiler::detectCallDepth(TIntermNode* root, TInfoSink& infoSink, bool limitCallStackDepth)
423 DetectCallDepth detect(infoSink, limitCallStackDepth, maxCallStackDepth);
424 root->traverse(&detect);
425 switch (detect.detectCallDepth())
427 case DetectCallDepth::kErrorNone:
429 case DetectCallDepth::kErrorMissingMain:
430 infoSink.info.prefix(EPrefixError);
431 infoSink.info << "Missing main()";
433 case DetectCallDepth::kErrorRecursion:
434 infoSink.info.prefix(EPrefixError);
435 infoSink.info << "Function recursion detected";
437 case DetectCallDepth::kErrorMaxDepthExceeded:
438 infoSink.info.prefix(EPrefixError);
439 infoSink.info << "Function call stack too deep";
447 bool TCompiler::validateOutputs(TIntermNode* root)
449 ValidateOutputs validateOutputs(infoSink.info, compileResources.MaxDrawBuffers);
450 root->traverse(&validateOutputs);
451 return (validateOutputs.numErrors() == 0);
454 void TCompiler::rewriteCSSShader(TIntermNode* root)
456 RenameFunction renamer("main(", "css_main(");
457 root->traverse(&renamer);
460 bool TCompiler::validateLimitations(TIntermNode* root)
462 ValidateLimitations validate(shaderType, infoSink.info);
463 root->traverse(&validate);
464 return validate.numErrors() == 0;
467 bool TCompiler::enforceTimingRestrictions(TIntermNode* root, bool outputGraph)
469 if (shaderSpec != SH_WEBGL_SPEC)
471 infoSink.info << "Timing restrictions must be enforced under the WebGL spec.";
475 if (shaderType == GL_FRAGMENT_SHADER)
477 TDependencyGraph graph(root);
479 // Output any errors first.
480 bool success = enforceFragmentShaderTimingRestrictions(graph);
482 // Then, output the dependency graph.
485 TDependencyGraphOutput output(infoSink.info);
486 output.outputAllSpanningTrees(graph);
493 return enforceVertexShaderTimingRestrictions(root);
497 bool TCompiler::limitExpressionComplexity(TIntermNode* root)
499 TMaxDepthTraverser traverser(maxExpressionComplexity+1);
500 root->traverse(&traverser);
502 if (traverser.getMaxDepth() > maxExpressionComplexity)
504 infoSink.info << "Expression too complex.";
508 TDependencyGraph graph(root);
510 for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls();
511 iter != graph.endUserDefinedFunctionCalls();
514 TGraphFunctionCall* samplerSymbol = *iter;
515 TDependencyGraphTraverser graphTraverser;
516 samplerSymbol->traverse(&graphTraverser);
522 bool TCompiler::enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph)
524 RestrictFragmentShaderTiming restrictor(infoSink.info);
525 restrictor.enforceRestrictions(graph);
526 return restrictor.numErrors() == 0;
529 bool TCompiler::enforceVertexShaderTimingRestrictions(TIntermNode* root)
531 RestrictVertexShaderTiming restrictor(infoSink.info);
532 restrictor.enforceRestrictions(root);
533 return restrictor.numErrors() == 0;
536 void TCompiler::collectVariables(TIntermNode* root)
538 sh::CollectVariables collect(&attributes,
545 root->traverse(&collect);
547 // This is for enforcePackingRestriction().
548 sh::ExpandUniforms(uniforms, &expandedUniforms);
551 bool TCompiler::enforcePackingRestrictions()
553 VariablePacker packer;
554 return packer.CheckVariablesWithinPackingLimits(maxUniformVectors, expandedUniforms);
557 void TCompiler::initializeGLPosition(TIntermNode* root)
559 InitializeVariables::InitVariableInfoList variables;
560 InitializeVariables::InitVariableInfo var(
561 "gl_Position", TType(EbtFloat, EbpUndefined, EvqPosition, 4));
562 variables.push_back(var);
563 InitializeVariables initializer(variables);
564 root->traverse(&initializer);
567 void TCompiler::initializeVaryingsWithoutStaticUse(TIntermNode* root)
569 InitializeVariables::InitVariableInfoList variables;
570 for (size_t ii = 0; ii < varyings.size(); ++ii)
572 const sh::Varying& varying = varyings[ii];
573 if (varying.staticUse)
575 unsigned char primarySize = static_cast<unsigned char>(gl::VariableColumnCount(varying.type));
576 unsigned char secondarySize = static_cast<unsigned char>(gl::VariableRowCount(varying.type));
577 TType type(EbtFloat, EbpUndefined, EvqVaryingOut, primarySize, secondarySize, varying.isArray());
578 TString name = varying.name.c_str();
579 if (varying.isArray())
581 type.setArraySize(varying.arraySize);
582 name = name.substr(0, name.find_first_of('['));
585 InitializeVariables::InitVariableInfo var(name, type);
586 variables.push_back(var);
588 InitializeVariables initializer(variables);
589 root->traverse(&initializer);
592 const TExtensionBehavior& TCompiler::getExtensionBehavior() const
594 return extensionBehavior;
597 const ShBuiltInResources& TCompiler::getResources() const
599 return compileResources;
602 const ArrayBoundsClamper& TCompiler::getArrayBoundsClamper() const
604 return arrayBoundsClamper;
607 ShArrayIndexClampingStrategy TCompiler::getArrayIndexClampingStrategy() const
609 return clampingStrategy;
612 const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
614 return builtInFunctionEmulator;
617 void TCompiler::writePragma()
619 TInfoSinkBase &sink = infoSink.obj;
620 if (mPragma.stdgl.invariantAll)
621 sink << "#pragma STDGL invariant(all)\n";