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