Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / angle / src / compiler / translator / Compiler.cpp
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/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"
24
25 bool isWebGLBasedSpec(ShShaderSpec spec)
26 {
27      return spec == SH_WEBGL_SPEC || spec == SH_CSS_SHADERS_SPEC;
28 }
29
30 namespace {
31 class TScopedPoolAllocator
32 {
33   public:
34     TScopedPoolAllocator(TPoolAllocator* allocator) : mAllocator(allocator)
35     {
36         mAllocator->push();
37         SetGlobalPoolAllocator(mAllocator);
38     }
39     ~TScopedPoolAllocator()
40     {
41         SetGlobalPoolAllocator(NULL);
42         mAllocator->pop();
43     }
44
45   private:
46     TPoolAllocator* mAllocator;
47 };
48
49 class TScopedSymbolTableLevel
50 {
51   public:
52     TScopedSymbolTableLevel(TSymbolTable* table) : mTable(table)
53     {
54         ASSERT(mTable->atBuiltInLevel());
55         mTable->push();
56     }
57     ~TScopedSymbolTableLevel()
58     {
59         while (!mTable->atBuiltInLevel())
60             mTable->pop();
61     }
62
63   private:
64     TSymbolTable* mTable;
65 };
66 }  // namespace
67
68 TShHandleBase::TShHandleBase()
69 {
70     allocator.push();
71     SetGlobalPoolAllocator(&allocator);
72 }
73
74 TShHandleBase::~TShHandleBase()
75 {
76     SetGlobalPoolAllocator(NULL);
77     allocator.popAll();
78 }
79
80 TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec)
81     : shaderType(type),
82       shaderSpec(spec),
83       maxUniformVectors(0),
84       maxExpressionComplexity(0),
85       maxCallStackDepth(0),
86       fragmentPrecisionHigh(false),
87       clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC),
88       builtInFunctionEmulator(type)
89 {
90 }
91
92 TCompiler::~TCompiler()
93 {
94 }
95
96 bool TCompiler::Init(const ShBuiltInResources& resources)
97 {
98     maxUniformVectors = (shaderType == SH_VERTEX_SHADER) ?
99         resources.MaxVertexUniformVectors :
100         resources.MaxFragmentUniformVectors;
101     maxExpressionComplexity = resources.MaxExpressionComplexity;
102     maxCallStackDepth = resources.MaxCallStackDepth;
103
104     SetGlobalPoolAllocator(&allocator);
105
106     // Generate built-in symbol table.
107     if (!InitBuiltInSymbolTable(resources))
108         return false;
109     InitExtensionBehavior(resources, extensionBehavior);
110     fragmentPrecisionHigh = resources.FragmentPrecisionHigh == 1;
111
112     arrayBoundsClamper.SetClampingStrategy(resources.ArrayIndexClampingStrategy);
113     clampingStrategy = resources.ArrayIndexClampingStrategy;
114
115     hashFunction = resources.HashFunction;
116
117     return true;
118 }
119
120 bool TCompiler::compile(const char* const shaderStrings[],
121                         size_t numStrings,
122                         int compileOptions)
123 {
124     TScopedPoolAllocator scopedAlloc(&allocator);
125     clearResults();
126
127     if (numStrings == 0)
128         return true;
129
130     // If compiling for WebGL, validate loop and indexing as well.
131     if (isWebGLBasedSpec(shaderSpec))
132         compileOptions |= SH_VALIDATE_LOOP_INDEXING;
133
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)
138     {
139         sourcePath = shaderStrings[0];
140         ++firstSource;
141     }
142
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);
149
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);
153
154     // Parse shader.
155     bool success =
156         (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) &&
157         (parseContext.treeRoot != NULL);
158     if (success)
159     {
160         TIntermNode* root = parseContext.treeRoot;
161         success = intermediate.postProcess(root);
162
163         // Disallow expressions deemed too complex.
164         if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY))
165             success = limitExpressionComplexity(root);
166
167         if (success)
168             success = detectCallDepth(root, infoSink, (compileOptions & SH_LIMIT_CALL_STACK_DEPTH) != 0);
169
170         if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
171             success = validateLimitations(root);
172
173         if (success && (compileOptions & SH_TIMING_RESTRICTIONS))
174             success = enforceTimingRestrictions(root, (compileOptions & SH_DEPENDENCY_GRAPH) != 0);
175
176         if (success && shaderSpec == SH_CSS_SHADERS_SPEC)
177             rewriteCSSShader(root);
178
179         // Unroll for-loop markup needs to happen after validateLimitations pass.
180         if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX))
181         {
182             ForLoopUnrollMarker marker(ForLoopUnrollMarker::kIntegerIndex);
183             root->traverse(&marker);
184         }
185         if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX))
186         {
187             ForLoopUnrollMarker marker(ForLoopUnrollMarker::kSamplerArrayIndex);
188             root->traverse(&marker);
189             if (marker.samplerArrayIndexIsFloatLoopIndex())
190             {
191                 infoSink.info.prefix(EPrefixError);
192                 infoSink.info << "sampler array index is float loop index";
193                 success = false;
194             }
195         }
196
197         // Built-in function emulation needs to happen after validateLimitations pass.
198         if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS))
199             builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root);
200
201         // Clamping uniform array bounds needs to happen after validateLimitations pass.
202         if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS))
203             arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root);
204
205         if (success && shaderType == SH_VERTEX_SHADER && (compileOptions & SH_INIT_GL_POSITION))
206             initializeGLPosition(root);
207
208         if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT))
209         {
210             UnfoldShortCircuitAST unfoldShortCircuit;
211             root->traverse(&unfoldShortCircuit);
212             unfoldShortCircuit.updateTree();
213         }
214
215         if (success && (compileOptions & SH_VARIABLES))
216         {
217             collectVariables(root);
218             if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS)
219             {
220                 success = enforcePackingRestrictions();
221                 if (!success)
222                 {
223                     infoSink.info.prefix(EPrefixError);
224                     infoSink.info << "too many uniforms";
225                 }
226             }
227             if (success && shaderType == SH_VERTEX_SHADER &&
228                 (compileOptions & SH_INIT_VARYINGS_WITHOUT_STATIC_USE))
229                 initializeVaryingsWithoutStaticUse(root);
230         }
231
232         if (success && (compileOptions & SH_INTERMEDIATE_TREE))
233             intermediate.outputTree(root);
234
235         if (success && (compileOptions & SH_OBJECT_CODE))
236             translate(root);
237     }
238
239     // Cleanup memory.
240     intermediate.remove(parseContext.treeRoot);
241
242     return success;
243 }
244
245 bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
246 {
247     compileResources = resources;
248
249     assert(symbolTable.isEmpty());
250     symbolTable.push();
251
252     TPublicType integer;
253     integer.type = EbtInt;
254     integer.size = 1;
255     integer.matrix = false;
256     integer.array = false;
257
258     TPublicType floatingPoint;
259     floatingPoint.type = EbtFloat;
260     floatingPoint.size = 1;
261     floatingPoint.matrix = false;
262     floatingPoint.array = false;
263
264     TPublicType sampler;
265     sampler.size = 1;
266     sampler.matrix = false;
267     sampler.array = false;
268
269     switch(shaderType)
270     {
271       case SH_FRAGMENT_SHADER:
272         symbolTable.setDefaultPrecision(integer, EbpMedium);
273         break;
274       case SH_VERTEX_SHADER:
275         symbolTable.setDefaultPrecision(integer, EbpHigh);
276         symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
277         break;
278       default:
279         assert(false && "Language not supported");
280     }
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)
285     {
286         sampler.type = static_cast<TBasicType>(samplerType);
287         symbolTable.setDefaultPrecision(sampler, EbpLow);
288     }
289
290     InsertBuiltInFunctions(shaderType, shaderSpec, resources, symbolTable);
291
292     IdentifyBuiltIns(shaderType, shaderSpec, resources, symbolTable);
293
294     return true;
295 }
296
297 void TCompiler::clearResults()
298 {
299     arrayBoundsClamper.Cleanup();
300     infoSink.info.erase();
301     infoSink.obj.erase();
302     infoSink.debug.erase();
303
304     attribs.clear();
305     uniforms.clear();
306     varyings.clear();
307
308     builtInFunctionEmulator.Cleanup();
309
310     nameMap.clear();
311 }
312
313 bool TCompiler::detectCallDepth(TIntermNode* root, TInfoSink& infoSink, bool limitCallStackDepth)
314 {
315     DetectCallDepth detect(infoSink, limitCallStackDepth, maxCallStackDepth);
316     root->traverse(&detect);
317     switch (detect.detectCallDepth())
318     {
319       case DetectCallDepth::kErrorNone:
320         return true;
321       case DetectCallDepth::kErrorMissingMain:
322         infoSink.info.prefix(EPrefixError);
323         infoSink.info << "Missing main()";
324         return false;
325       case DetectCallDepth::kErrorRecursion:
326         infoSink.info.prefix(EPrefixError);
327         infoSink.info << "Function recursion detected";
328         return false;
329       case DetectCallDepth::kErrorMaxDepthExceeded:
330         infoSink.info.prefix(EPrefixError);
331         infoSink.info << "Function call stack too deep";
332         return false;
333       default:
334         UNREACHABLE();
335         return false;
336     }
337 }
338
339 void TCompiler::rewriteCSSShader(TIntermNode* root)
340 {
341     RenameFunction renamer("main(", "css_main(");
342     root->traverse(&renamer);
343 }
344
345 bool TCompiler::validateLimitations(TIntermNode* root)
346 {
347     ValidateLimitations validate(shaderType, infoSink.info);
348     root->traverse(&validate);
349     return validate.numErrors() == 0;
350 }
351
352 bool TCompiler::enforceTimingRestrictions(TIntermNode* root, bool outputGraph)
353 {
354     if (shaderSpec != SH_WEBGL_SPEC)
355     {
356         infoSink.info << "Timing restrictions must be enforced under the WebGL spec.";
357         return false;
358     }
359
360     if (shaderType == SH_FRAGMENT_SHADER)
361     {
362         TDependencyGraph graph(root);
363
364         // Output any errors first.
365         bool success = enforceFragmentShaderTimingRestrictions(graph);
366         
367         // Then, output the dependency graph.
368         if (outputGraph)
369         {
370             TDependencyGraphOutput output(infoSink.info);
371             output.outputAllSpanningTrees(graph);
372         }
373         
374         return success;
375     }
376     else
377     {
378         return enforceVertexShaderTimingRestrictions(root);
379     }
380 }
381
382 bool TCompiler::limitExpressionComplexity(TIntermNode* root)
383 {
384     TMaxDepthTraverser traverser(maxExpressionComplexity+1);
385     root->traverse(&traverser);
386
387     if (traverser.getMaxDepth() > maxExpressionComplexity)
388     {
389         infoSink.info << "Expression too complex.";
390         return false;
391     }
392
393     TDependencyGraph graph(root);
394
395     for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls();
396          iter != graph.endUserDefinedFunctionCalls();
397          ++iter)
398     {
399         TGraphFunctionCall* samplerSymbol = *iter;
400         TDependencyGraphTraverser graphTraverser;
401         samplerSymbol->traverse(&graphTraverser);
402     }
403
404     return true;
405 }
406
407 bool TCompiler::enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph)
408 {
409     RestrictFragmentShaderTiming restrictor(infoSink.info);
410     restrictor.enforceRestrictions(graph);
411     return restrictor.numErrors() == 0;
412 }
413
414 bool TCompiler::enforceVertexShaderTimingRestrictions(TIntermNode* root)
415 {
416     RestrictVertexShaderTiming restrictor(infoSink.info);
417     restrictor.enforceRestrictions(root);
418     return restrictor.numErrors() == 0;
419 }
420
421 void TCompiler::collectVariables(TIntermNode* root)
422 {
423     CollectVariables collect(attribs, uniforms, varyings, hashFunction);
424     root->traverse(&collect);
425 }
426
427 bool TCompiler::enforcePackingRestrictions()
428 {
429     VariablePacker packer;
430     return packer.CheckVariablesWithinPackingLimits(maxUniformVectors, uniforms);
431 }
432
433 void TCompiler::initializeGLPosition(TIntermNode* root)
434 {
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);
441 }
442
443 void TCompiler::initializeVaryingsWithoutStaticUse(TIntermNode* root)
444 {
445     InitializeVariables::InitVariableInfoList variables;
446     for (size_t ii = 0; ii < varyings.size(); ++ii)
447     {
448         const TVariableInfo& varying = varyings[ii];
449         if (varying.staticUse)
450             continue;
451         unsigned char size = 0;
452         bool matrix = false;
453         switch (varying.type)
454         {
455           case SH_FLOAT:
456             size = 1;
457             break;
458           case SH_FLOAT_VEC2:
459             size = 2;
460             break;
461           case SH_FLOAT_VEC3:
462             size = 3;
463             break;
464           case SH_FLOAT_VEC4:
465             size = 4;
466             break;
467           case SH_FLOAT_MAT2:
468             size = 2;
469             matrix = true;
470             break;
471           case SH_FLOAT_MAT3:
472             size = 3;
473             matrix = true;
474             break;
475           case SH_FLOAT_MAT4:
476             size = 4;
477             matrix = true;
478             break;
479           default:
480             ASSERT(false);
481         }
482         TType type(EbtFloat, EbpUndefined, EvqVaryingOut, size, matrix, varying.isArray);
483         TString name = varying.name.c_str();
484         if (varying.isArray)
485         {
486             type.setArraySize(varying.size);
487             name = name.substr(0, name.find_first_of('['));
488         }
489
490         InitializeVariables::InitVariableInfo var(name, type);
491         variables.push_back(var);
492     }
493     InitializeVariables initializer(variables);
494     root->traverse(&initializer);
495 }
496
497 const TExtensionBehavior& TCompiler::getExtensionBehavior() const
498 {
499     return extensionBehavior;
500 }
501
502 const ShBuiltInResources& TCompiler::getResources() const
503 {
504     return compileResources;
505 }
506
507 const ArrayBoundsClamper& TCompiler::getArrayBoundsClamper() const
508 {
509     return arrayBoundsClamper;
510 }
511
512 ShArrayIndexClampingStrategy TCompiler::getArrayIndexClampingStrategy() const
513 {
514     return clampingStrategy;
515 }
516
517 const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
518 {
519     return builtInFunctionEmulator;
520 }