1 //
2 // Copyright 2002 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/VersionGLSL.h"
8 
9 #include "angle_gl.h"
10 #include "compiler/translator/Symbol.h"
11 
12 namespace sh
13 {
14 
15 namespace
16 {
17 constexpr const ImmutableString kGlPointCoordString("gl_PointCoord");
18 }  // anonymous namespace
19 
ShaderOutputTypeToGLSLVersion(ShShaderOutput output)20 int ShaderOutputTypeToGLSLVersion(ShShaderOutput output)
21 {
22     switch (output)
23     {
24         case SH_GLSL_130_OUTPUT:
25             return GLSL_VERSION_130;
26         case SH_GLSL_140_OUTPUT:
27             return GLSL_VERSION_140;
28         case SH_GLSL_150_CORE_OUTPUT:
29             return GLSL_VERSION_150;
30         case SH_GLSL_330_CORE_OUTPUT:
31             return GLSL_VERSION_330;
32         case SH_GLSL_400_CORE_OUTPUT:
33             return GLSL_VERSION_400;
34         case SH_GLSL_410_CORE_OUTPUT:
35             return GLSL_VERSION_410;
36         case SH_GLSL_420_CORE_OUTPUT:
37             return GLSL_VERSION_420;
38         case SH_GLSL_430_CORE_OUTPUT:
39             return GLSL_VERSION_430;
40         case SH_GLSL_440_CORE_OUTPUT:
41             return GLSL_VERSION_440;
42         case SH_GLSL_450_CORE_OUTPUT:
43             return GLSL_VERSION_450;
44         case SH_GLSL_COMPATIBILITY_OUTPUT:
45             return GLSL_VERSION_110;
46         default:
47             UNREACHABLE();
48             return 0;
49     }
50 }
51 
52 // We need to scan for the following:
53 // 1. "invariant" keyword: This can occur in both - vertex and fragment shaders
54 //    but only at the global scope.
55 // 2. "gl_PointCoord" built-in variable: This can only occur in fragment shader
56 //    but inside any scope.
57 // 3. Call to a matrix constructor with another matrix as argument.
58 //    (These constructors were reserved in GLSL version 1.10.)
59 // 4. Arrays as "out" function parameters.
60 //    GLSL spec section 6.1.1: "When calling a function, expressions that do
61 //    not evaluate to l-values cannot be passed to parameters declared as
62 //    out or inout."
63 //    GLSL 1.1 section 5.8: "Other binary or unary expressions,
64 //    non-dereferenced arrays, function names, swizzles with repeated fields,
65 //    and constants cannot be l-values."
66 //    GLSL 1.2 relaxed the restriction on arrays, section 5.8: "Variables that
67 //    are built-in types, entire structures or arrays... are all l-values."
68 //
TVersionGLSL(sh::GLenum type,const TPragma & pragma,ShShaderOutput output)69 TVersionGLSL::TVersionGLSL(sh::GLenum type, const TPragma &pragma, ShShaderOutput output)
70     : TIntermTraverser(true, false, false)
71 {
72     mVersion = ShaderOutputTypeToGLSLVersion(output);
73     if (pragma.stdgl.invariantAll)
74     {
75         ensureVersionIsAtLeast(GLSL_VERSION_120);
76     }
77     if (type == GL_COMPUTE_SHADER)
78     {
79         ensureVersionIsAtLeast(GLSL_VERSION_430);
80     }
81 }
82 
visitSymbol(TIntermSymbol * node)83 void TVersionGLSL::visitSymbol(TIntermSymbol *node)
84 {
85     if (node->variable().symbolType() == SymbolType::BuiltIn &&
86         node->getName() == kGlPointCoordString)
87     {
88         ensureVersionIsAtLeast(GLSL_VERSION_120);
89     }
90 }
91 
visitDeclaration(Visit,TIntermDeclaration * node)92 bool TVersionGLSL::visitDeclaration(Visit, TIntermDeclaration *node)
93 {
94     const TIntermSequence &sequence = *(node->getSequence());
95     if (sequence.front()->getAsTyped()->getType().isInvariant())
96     {
97         ensureVersionIsAtLeast(GLSL_VERSION_120);
98     }
99     return true;
100 }
101 
visitGlobalQualifierDeclaration(Visit,TIntermGlobalQualifierDeclaration * node)102 bool TVersionGLSL::visitGlobalQualifierDeclaration(Visit, TIntermGlobalQualifierDeclaration *node)
103 {
104     if (node->isPrecise())
105     {
106         ensureVersionIsAtLeast(GLSL_VERSION_420);
107     }
108     else
109     {
110         ensureVersionIsAtLeast(GLSL_VERSION_120);
111     }
112     return true;
113 }
114 
visitFunctionPrototype(TIntermFunctionPrototype * node)115 void TVersionGLSL::visitFunctionPrototype(TIntermFunctionPrototype *node)
116 {
117     size_t paramCount = node->getFunction()->getParamCount();
118     for (size_t i = 0; i < paramCount; ++i)
119     {
120         const TVariable *param = node->getFunction()->getParam(i);
121         const TType &type      = param->getType();
122         if (type.isArray())
123         {
124             TQualifier qualifier = type.getQualifier();
125             if ((qualifier == EvqOut) || (qualifier == EvqInOut))
126             {
127                 ensureVersionIsAtLeast(GLSL_VERSION_120);
128                 break;
129             }
130         }
131     }
132 }
133 
visitAggregate(Visit,TIntermAggregate * node)134 bool TVersionGLSL::visitAggregate(Visit, TIntermAggregate *node)
135 {
136     if (node->getOp() == EOpConstruct && node->getType().isMatrix())
137     {
138         const TIntermSequence &sequence = *(node->getSequence());
139         if (sequence.size() == 1)
140         {
141             TIntermTyped *typed = sequence.front()->getAsTyped();
142             if (typed && typed->isMatrix())
143             {
144                 ensureVersionIsAtLeast(GLSL_VERSION_120);
145             }
146         }
147     }
148     return true;
149 }
150 
ensureVersionIsAtLeast(int version)151 void TVersionGLSL::ensureVersionIsAtLeast(int version)
152 {
153     mVersion = std::max(version, mVersion);
154 }
155 
156 }  // namespace sh
157