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