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/TranslatorGLSL.h"
8 
9 #include "angle_gl.h"
10 #include "compiler/translator/BuiltInFunctionEmulatorGLSL.h"
11 #include "compiler/translator/EmulatePrecision.h"
12 #include "compiler/translator/ExtensionGLSL.h"
13 #include "compiler/translator/OutputGLSL.h"
14 #include "compiler/translator/RewriteTexelFetchOffset.h"
15 #include "compiler/translator/RewriteUnaryMinusOperatorFloat.h"
16 #include "compiler/translator/VersionGLSL.h"
17 
18 namespace sh
19 {
20 
TranslatorGLSL(sh::GLenum type,ShShaderSpec spec,ShShaderOutput output)21 TranslatorGLSL::TranslatorGLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
22     : TCompiler(type, spec, output)
23 {
24 }
25 
initBuiltInFunctionEmulator(BuiltInFunctionEmulator * emu,ShCompileOptions compileOptions)26 void TranslatorGLSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu,
27                                                  ShCompileOptions compileOptions)
28 {
29     if (compileOptions & SH_EMULATE_ABS_INT_FUNCTION)
30     {
31         InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(emu, getShaderType());
32     }
33 
34     if (compileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION)
35     {
36         InitBuiltInIsnanFunctionEmulatorForGLSLWorkarounds(emu, getShaderVersion());
37     }
38 
39     if (compileOptions & SH_EMULATE_ATAN2_FLOAT_FUNCTION)
40     {
41         InitBuiltInAtanFunctionEmulatorForGLSLWorkarounds(emu);
42     }
43 
44     int targetGLSLVersion = ShaderOutputTypeToGLSLVersion(getOutputType());
45     InitBuiltInFunctionEmulatorForGLSLMissingFunctions(emu, getShaderType(), targetGLSLVersion);
46 }
47 
translate(TIntermBlock * root,ShCompileOptions compileOptions,PerformanceDiagnostics *)48 void TranslatorGLSL::translate(TIntermBlock *root,
49                                ShCompileOptions compileOptions,
50                                PerformanceDiagnostics * /*perfDiagnostics*/)
51 {
52     TInfoSinkBase &sink = getInfoSink().obj;
53 
54     // Write GLSL version.
55     writeVersion(root);
56 
57     // Write extension behaviour as needed
58     writeExtensionBehavior(root, compileOptions);
59 
60     // Write pragmas after extensions because some drivers consider pragmas
61     // like non-preprocessor tokens.
62     writePragma(compileOptions);
63 
64     // If flattening the global invariant pragma, write invariant declarations for built-in
65     // variables. It should be harmless to do this twice in the case that the shader also explicitly
66     // did this. However, it's important to emit invariant qualifiers only for those built-in
67     // variables that are actually used, to avoid affecting the behavior of the shader.
68     if ((compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) != 0 &&
69         getPragma().stdgl.invariantAll &&
70         !sh::RemoveInvariant(getShaderType(), getShaderVersion(), getOutputType(), compileOptions))
71     {
72         ASSERT(wereVariablesCollected());
73 
74         switch (getShaderType())
75         {
76             case GL_VERTEX_SHADER:
77                 sink << "invariant gl_Position;\n";
78 
79                 // gl_PointSize should be declared invariant in both ESSL 1.00 and 3.00 fragment
80                 // shaders if it's statically referenced.
81                 conditionallyOutputInvariantDeclaration("gl_PointSize");
82                 break;
83             case GL_FRAGMENT_SHADER:
84                 // The preprocessor will reject this pragma if it's used in ESSL 3.00 fragment
85                 // shaders, so we can use simple logic to determine whether to declare these
86                 // variables invariant.
87                 conditionallyOutputInvariantDeclaration("gl_FragCoord");
88                 conditionallyOutputInvariantDeclaration("gl_PointCoord");
89                 break;
90             default:
91                 // Currently not reached, but leave this in for future expansion.
92                 ASSERT(false);
93                 break;
94         }
95     }
96 
97     if ((compileOptions & SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH) != 0)
98     {
99         sh::RewriteTexelFetchOffset(root, getSymbolTable(), getShaderVersion());
100     }
101 
102     if ((compileOptions & SH_REWRITE_FLOAT_UNARY_MINUS_OPERATOR) != 0)
103     {
104         sh::RewriteUnaryMinusOperatorFloat(root);
105     }
106 
107     bool precisionEmulation =
108         getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision;
109 
110     if (precisionEmulation)
111     {
112         EmulatePrecision emulatePrecision(&getSymbolTable(), getShaderVersion());
113         root->traverse(&emulatePrecision);
114         emulatePrecision.updateTree();
115         emulatePrecision.writeEmulationHelpers(sink, getShaderVersion(), getOutputType());
116     }
117 
118     // Write emulated built-in functions if needed.
119     if (!getBuiltInFunctionEmulator().isOutputEmpty())
120     {
121         sink << "// BEGIN: Generated code for built-in function emulation\n\n";
122         sink << "#define emu_precision\n\n";
123         getBuiltInFunctionEmulator().outputEmulatedFunctions(sink);
124         sink << "// END: Generated code for built-in function emulation\n\n";
125     }
126 
127     // Write array bounds clamping emulation if needed.
128     getArrayBoundsClamper().OutputClampingFunctionDefinition(sink);
129 
130     // Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData
131     // if it's core profile shaders and they are used.
132     if (getShaderType() == GL_FRAGMENT_SHADER)
133     {
134         const bool mayHaveESSL1SecondaryOutputs =
135             IsExtensionEnabled(getExtensionBehavior(), TExtension::EXT_blend_func_extended) &&
136             getShaderVersion() == 100;
137         const bool declareGLFragmentOutputs = IsGLSL130OrNewer(getOutputType());
138 
139         bool hasGLFragColor          = false;
140         bool hasGLFragData           = false;
141         bool hasGLSecondaryFragColor = false;
142         bool hasGLSecondaryFragData  = false;
143 
144         for (const auto &outputVar : outputVariables)
145         {
146             if (declareGLFragmentOutputs)
147             {
148                 if (outputVar.name == "gl_FragColor")
149                 {
150                     ASSERT(!hasGLFragColor);
151                     hasGLFragColor = true;
152                     continue;
153                 }
154                 else if (outputVar.name == "gl_FragData")
155                 {
156                     ASSERT(!hasGLFragData);
157                     hasGLFragData = true;
158                     continue;
159                 }
160             }
161             if (mayHaveESSL1SecondaryOutputs)
162             {
163                 if (outputVar.name == "gl_SecondaryFragColorEXT")
164                 {
165                     ASSERT(!hasGLSecondaryFragColor);
166                     hasGLSecondaryFragColor = true;
167                     continue;
168                 }
169                 else if (outputVar.name == "gl_SecondaryFragDataEXT")
170                 {
171                     ASSERT(!hasGLSecondaryFragData);
172                     hasGLSecondaryFragData = true;
173                     continue;
174                 }
175             }
176         }
177         ASSERT(!((hasGLFragColor || hasGLSecondaryFragColor) &&
178                  (hasGLFragData || hasGLSecondaryFragData)));
179         if (hasGLFragColor)
180         {
181             sink << "out vec4 webgl_FragColor;\n";
182         }
183         if (hasGLFragData)
184         {
185             sink << "out vec4 webgl_FragData[gl_MaxDrawBuffers];\n";
186         }
187         if (hasGLSecondaryFragColor)
188         {
189             sink << "out vec4 angle_SecondaryFragColor;\n";
190         }
191         if (hasGLSecondaryFragData)
192         {
193             sink << "out vec4 angle_SecondaryFragData[" << getResources().MaxDualSourceDrawBuffers
194                  << "];\n";
195         }
196     }
197 
198     if (getShaderType() == GL_COMPUTE_SHADER && isComputeShaderLocalSizeDeclared())
199     {
200         const sh::WorkGroupSize &localSize = getComputeShaderLocalSize();
201         sink << "layout (local_size_x=" << localSize[0] << ", local_size_y=" << localSize[1]
202              << ", local_size_z=" << localSize[2] << ") in;\n";
203     }
204 
205     if (getShaderType() == GL_GEOMETRY_SHADER_OES)
206     {
207         WriteGeometryShaderLayoutQualifiers(
208             sink, getGeometryShaderInputPrimitiveType(), getGeometryShaderInvocations(),
209             getGeometryShaderOutputPrimitiveType(), getGeometryShaderMaxVertices());
210     }
211 
212     // Write translated shader.
213     TOutputGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(),
214                            &getSymbolTable(), getShaderType(), getShaderVersion(), getOutputType(),
215                            compileOptions);
216 
217     if (compileOptions & SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM)
218     {
219         TName uniformName(TString("ViewID_OVR"));
220         uniformName.setInternal(true);
221         sink << "uniform int " << outputGLSL.hashName(uniformName) << ";\n";
222     }
223 
224     root->traverse(&outputGLSL);
225 }
226 
shouldFlattenPragmaStdglInvariantAll()227 bool TranslatorGLSL::shouldFlattenPragmaStdglInvariantAll()
228 {
229     // Required when outputting to any GLSL version greater than 1.20, but since ANGLE doesn't
230     // translate to that version, return true for the next higher version.
231     return IsGLSL130OrNewer(getOutputType());
232 }
233 
shouldCollectVariables(ShCompileOptions compileOptions)234 bool TranslatorGLSL::shouldCollectVariables(ShCompileOptions compileOptions)
235 {
236     return (compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) ||
237            TCompiler::shouldCollectVariables(compileOptions);
238 }
239 
writeVersion(TIntermNode * root)240 void TranslatorGLSL::writeVersion(TIntermNode *root)
241 {
242     TVersionGLSL versionGLSL(getShaderType(), getPragma(), getOutputType());
243     root->traverse(&versionGLSL);
244     int version = versionGLSL.getVersion();
245     // We need to write version directive only if it is greater than 110.
246     // If there is no version directive in the shader, 110 is implied.
247     if (version > 110)
248     {
249         TInfoSinkBase &sink = getInfoSink().obj;
250         sink << "#version " << version << "\n";
251     }
252 }
253 
writeExtensionBehavior(TIntermNode * root,ShCompileOptions compileOptions)254 void TranslatorGLSL::writeExtensionBehavior(TIntermNode *root, ShCompileOptions compileOptions)
255 {
256     TInfoSinkBase &sink                   = getInfoSink().obj;
257     const TExtensionBehavior &extBehavior = getExtensionBehavior();
258     for (const auto &iter : extBehavior)
259     {
260         if (iter.second == EBhUndefined)
261         {
262             continue;
263         }
264 
265         if (getOutputType() == SH_GLSL_COMPATIBILITY_OUTPUT)
266         {
267             // For GLSL output, we don't need to emit most extensions explicitly,
268             // but some we need to translate in GL compatibility profile.
269             if (iter.first == TExtension::EXT_shader_texture_lod)
270             {
271                 sink << "#extension GL_ARB_shader_texture_lod : " << GetBehaviorString(iter.second)
272                      << "\n";
273             }
274 
275             if (iter.first == TExtension::EXT_draw_buffers)
276             {
277                 sink << "#extension GL_ARB_draw_buffers : " << GetBehaviorString(iter.second)
278                      << "\n";
279             }
280 
281             if (iter.first == TExtension::OES_geometry_shader)
282             {
283                 sink << "#extension GL_ARB_geometry_shader4 : " << GetBehaviorString(iter.second)
284                      << "\n";
285             }
286         }
287 
288         const bool isMultiview = (iter.first == TExtension::OVR_multiview);
289         if (isMultiview && getShaderType() == GL_VERTEX_SHADER &&
290             (compileOptions & SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER) != 0u)
291         {
292             // Emit the NV_viewport_array2 extension in a vertex shader if the
293             // SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER option is set and the OVR_multiview(2)
294             // extension is requested.
295             sink << "#extension GL_NV_viewport_array2 : require\n";
296         }
297     }
298 
299     // GLSL ES 3 explicit location qualifiers need to use an extension before GLSL 330
300     if (getShaderVersion() >= 300 && getOutputType() < SH_GLSL_330_CORE_OUTPUT &&
301         getShaderType() != GL_COMPUTE_SHADER)
302     {
303         sink << "#extension GL_ARB_explicit_attrib_location : require\n";
304     }
305 
306     // Need to enable gpu_shader5 to have index constant sampler array indexing
307     if (getOutputType() != SH_ESSL_OUTPUT && getOutputType() < SH_GLSL_400_CORE_OUTPUT &&
308         getShaderVersion() == 100)
309     {
310         // Don't use "require" on to avoid breaking WebGL 1 on drivers that silently
311         // support index constant sampler array indexing, but don't have the extension or
312         // on drivers that don't have the extension at all as it would break WebGL 1 for
313         // some users.
314         sink << "#extension GL_ARB_gpu_shader5 : enable\n";
315     }
316 
317     TExtensionGLSL extensionGLSL(getOutputType());
318     root->traverse(&extensionGLSL);
319 
320     for (const auto &ext : extensionGLSL.getEnabledExtensions())
321     {
322         sink << "#extension " << ext << " : enable\n";
323     }
324     for (const auto &ext : extensionGLSL.getRequiredExtensions())
325     {
326         sink << "#extension " << ext << " : require\n";
327     }
328 }
329 
conditionallyOutputInvariantDeclaration(const char * builtinVaryingName)330 void TranslatorGLSL::conditionallyOutputInvariantDeclaration(const char *builtinVaryingName)
331 {
332     if (isVaryingDefined(builtinVaryingName))
333     {
334         TInfoSinkBase &sink = getInfoSink().obj;
335         sink << "invariant " << builtinVaryingName << ";\n";
336     }
337 }
338 
339 }  // namespace sh
340