• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/TranslatorGLSL.h"
8 
9 #include "angle_gl.h"
10 #include "compiler/translator/BuiltInFunctionEmulatorGLSL.h"
11 #include "compiler/translator/ExtensionGLSL.h"
12 #include "compiler/translator/OutputGLSL.h"
13 #include "compiler/translator/VersionGLSL.h"
14 #include "compiler/translator/tree_ops/RewriteRowMajorMatrices.h"
15 #include "compiler/translator/tree_ops/RewriteTexelFetchOffset.h"
16 #include "compiler/translator/tree_ops/gl/mac/RewriteUnaryMinusOperatorFloat.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 
initBuiltInFunctionEmulator(BuiltInFunctionEmulator * emu,ShCompileOptions compileOptions)25 void TranslatorGLSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu,
26                                                  ShCompileOptions compileOptions)
27 {
28     if ((compileOptions & SH_EMULATE_ABS_INT_FUNCTION) != 0)
29     {
30         InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(emu, getShaderType());
31     }
32 
33     if ((compileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0)
34     {
35         InitBuiltInIsnanFunctionEmulatorForGLSLWorkarounds(emu, getShaderVersion());
36     }
37 
38     if ((compileOptions & SH_EMULATE_ATAN2_FLOAT_FUNCTION) != 0)
39     {
40         InitBuiltInAtanFunctionEmulatorForGLSLWorkarounds(emu);
41     }
42 
43     int targetGLSLVersion = ShaderOutputTypeToGLSLVersion(getOutputType());
44     InitBuiltInFunctionEmulatorForGLSLMissingFunctions(emu, getShaderType(), targetGLSLVersion);
45 }
46 
translate(TIntermBlock * root,ShCompileOptions compileOptions,PerformanceDiagnostics *)47 bool TranslatorGLSL::translate(TIntermBlock *root,
48                                ShCompileOptions compileOptions,
49                                PerformanceDiagnostics * /*perfDiagnostics*/)
50 {
51     TInfoSinkBase &sink = getInfoSink().obj;
52 
53     // Write GLSL version.
54     writeVersion(root);
55 
56     // Write extension behaviour as needed
57     writeExtensionBehavior(root, compileOptions);
58 
59     // Write pragmas after extensions because some drivers consider pragmas
60     // like non-preprocessor tokens.
61     WritePragma(sink, compileOptions, getPragma());
62 
63     // If flattening the global invariant pragma, write invariant declarations for built-in
64     // variables. It should be harmless to do this twice in the case that the shader also explicitly
65     // did this. However, it's important to emit invariant qualifiers only for those built-in
66     // variables that are actually used, to avoid affecting the behavior of the shader.
67     if ((compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) != 0 &&
68         getPragma().stdgl.invariantAll &&
69         !sh::RemoveInvariant(getShaderType(), getShaderVersion(), getOutputType(), compileOptions))
70     {
71         ASSERT(wereVariablesCollected());
72 
73         switch (getShaderType())
74         {
75             case GL_VERTEX_SHADER:
76                 sink << "invariant gl_Position;\n";
77 
78                 // gl_PointSize should be declared invariant in both ESSL 1.00 and 3.00 fragment
79                 // shaders if it's statically referenced.
80                 conditionallyOutputInvariantDeclaration("gl_PointSize");
81                 break;
82             case GL_FRAGMENT_SHADER:
83                 // The preprocessor will reject this pragma if it's used in ESSL 3.00 fragment
84                 // shaders, so we can use simple logic to determine whether to declare these
85                 // variables invariant.
86                 conditionallyOutputInvariantDeclaration("gl_FragCoord");
87                 conditionallyOutputInvariantDeclaration("gl_PointCoord");
88                 break;
89             default:
90                 // Currently not reached, but leave this in for future expansion.
91                 ASSERT(false);
92                 break;
93         }
94     }
95 
96     if ((compileOptions & SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH) != 0)
97     {
98         if (!sh::RewriteTexelFetchOffset(this, root, getSymbolTable(), getShaderVersion()))
99         {
100             return false;
101         }
102     }
103 
104     if ((compileOptions & SH_REWRITE_FLOAT_UNARY_MINUS_OPERATOR) != 0)
105     {
106         if (!sh::RewriteUnaryMinusOperatorFloat(this, root))
107         {
108             return false;
109         }
110     }
111 
112     if ((compileOptions & SH_REWRITE_ROW_MAJOR_MATRICES) != 0 && getShaderVersion() >= 300)
113     {
114         if (!RewriteRowMajorMatrices(this, root, &getSymbolTable()))
115         {
116             return false;
117         }
118     }
119 
120     bool precisionEmulation = false;
121     if (!emulatePrecisionIfNeeded(root, sink, &precisionEmulation, getOutputType()))
122         return false;
123 
124     // Write emulated built-in functions if needed.
125     if (!getBuiltInFunctionEmulator().isOutputEmpty())
126     {
127         sink << "// BEGIN: Generated code for built-in function emulation\n\n";
128         sink << "#define emu_precision\n\n";
129         getBuiltInFunctionEmulator().outputEmulatedFunctions(sink);
130         sink << "// END: Generated code for built-in function emulation\n\n";
131     }
132 
133     // Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData
134     // if it's core profile shaders and they are used.
135     if (getShaderType() == GL_FRAGMENT_SHADER)
136     {
137         const bool mayHaveESSL1SecondaryOutputs =
138             IsExtensionEnabled(getExtensionBehavior(), TExtension::EXT_blend_func_extended) &&
139             getShaderVersion() == 100;
140         const bool declareGLFragmentOutputs = IsGLSL130OrNewer(getOutputType());
141 
142         bool hasGLFragColor          = false;
143         bool hasGLFragData           = false;
144         bool hasGLSecondaryFragColor = false;
145         bool hasGLSecondaryFragData  = false;
146 
147         for (const auto &outputVar : mOutputVariables)
148         {
149             if (declareGLFragmentOutputs)
150             {
151                 if (outputVar.name == "gl_FragColor")
152                 {
153                     ASSERT(!hasGLFragColor);
154                     hasGLFragColor = true;
155                     continue;
156                 }
157                 else if (outputVar.name == "gl_FragData")
158                 {
159                     ASSERT(!hasGLFragData);
160                     hasGLFragData = true;
161                     continue;
162                 }
163             }
164             if (mayHaveESSL1SecondaryOutputs)
165             {
166                 if (outputVar.name == "gl_SecondaryFragColorEXT")
167                 {
168                     ASSERT(!hasGLSecondaryFragColor);
169                     hasGLSecondaryFragColor = true;
170                     continue;
171                 }
172                 else if (outputVar.name == "gl_SecondaryFragDataEXT")
173                 {
174                     ASSERT(!hasGLSecondaryFragData);
175                     hasGLSecondaryFragData = true;
176                     continue;
177                 }
178             }
179         }
180         ASSERT(!((hasGLFragColor || hasGLSecondaryFragColor) &&
181                  (hasGLFragData || hasGLSecondaryFragData)));
182         if (hasGLFragColor)
183         {
184             sink << "out vec4 webgl_FragColor;\n";
185         }
186         if (hasGLFragData)
187         {
188             sink << "out vec4 webgl_FragData[gl_MaxDrawBuffers];\n";
189         }
190         if (hasGLSecondaryFragColor)
191         {
192             sink << "out vec4 webgl_SecondaryFragColor;\n";
193         }
194         if (hasGLSecondaryFragData)
195         {
196             sink << "out vec4 webgl_SecondaryFragData[" << getResources().MaxDualSourceDrawBuffers
197                  << "];\n";
198         }
199 
200         EmitEarlyFragmentTestsGLSL(*this, sink);
201     }
202 
203     if (getShaderType() == GL_COMPUTE_SHADER)
204     {
205         EmitWorkGroupSizeGLSL(*this, sink);
206     }
207 
208     if (getShaderType() == GL_GEOMETRY_SHADER_EXT)
209     {
210         WriteGeometryShaderLayoutQualifiers(
211             sink, getGeometryShaderInputPrimitiveType(), getGeometryShaderInvocations(),
212             getGeometryShaderOutputPrimitiveType(), getGeometryShaderMaxVertices());
213     }
214 
215     // Write translated shader.
216     TOutputGLSL outputGLSL(sink, getHashFunction(), getNameMap(), &getSymbolTable(),
217                            getShaderType(), getShaderVersion(), getOutputType(), compileOptions);
218 
219     root->traverse(&outputGLSL);
220 
221     return true;
222 }
223 
shouldFlattenPragmaStdglInvariantAll()224 bool TranslatorGLSL::shouldFlattenPragmaStdglInvariantAll()
225 {
226     // Required when outputting to any GLSL version greater than 1.20, but since ANGLE doesn't
227     // translate to that version, return true for the next higher version.
228     return IsGLSL130OrNewer(getOutputType());
229 }
230 
shouldCollectVariables(ShCompileOptions compileOptions)231 bool TranslatorGLSL::shouldCollectVariables(ShCompileOptions compileOptions)
232 {
233     return (compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) != 0 ||
234            TCompiler::shouldCollectVariables(compileOptions);
235 }
236 
writeVersion(TIntermNode * root)237 void TranslatorGLSL::writeVersion(TIntermNode *root)
238 {
239     TVersionGLSL versionGLSL(getShaderType(), getPragma(), getOutputType());
240     root->traverse(&versionGLSL);
241     int version = versionGLSL.getVersion();
242     // We need to write version directive only if it is greater than 110.
243     // If there is no version directive in the shader, 110 is implied.
244     if (version > 110)
245     {
246         TInfoSinkBase &sink = getInfoSink().obj;
247         sink << "#version " << version << "\n";
248     }
249 }
250 
writeExtensionBehavior(TIntermNode * root,ShCompileOptions compileOptions)251 void TranslatorGLSL::writeExtensionBehavior(TIntermNode *root, ShCompileOptions compileOptions)
252 {
253     bool usesTextureCubeMapArray = false;
254     bool usesTextureBuffer       = false;
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::EXT_geometry_shader ||
282                 iter.first == TExtension::OES_geometry_shader)
283             {
284                 sink << "#extension GL_ARB_geometry_shader4 : " << GetBehaviorString(iter.second)
285                      << "\n";
286             }
287         }
288 
289         const bool isMultiview =
290             (iter.first == TExtension::OVR_multiview) || (iter.first == TExtension::OVR_multiview2);
291         if (isMultiview)
292         {
293             // Only either OVR_multiview or OVR_multiview2 should be emitted.
294             if ((iter.first != TExtension::OVR_multiview) ||
295                 !IsExtensionEnabled(extBehavior, TExtension::OVR_multiview2))
296             {
297                 EmitMultiviewGLSL(*this, compileOptions, iter.first, iter.second, sink);
298             }
299         }
300 
301         // Support ANGLE_texture_multisample extension on GLSL300
302         if (getShaderVersion() >= 300 && iter.first == TExtension::ANGLE_texture_multisample &&
303             getOutputType() < SH_GLSL_330_CORE_OUTPUT)
304         {
305             sink << "#extension GL_ARB_texture_multisample : " << GetBehaviorString(iter.second)
306                  << "\n";
307         }
308 
309         if ((iter.first == TExtension::OES_texture_cube_map_array ||
310              iter.first == TExtension::EXT_texture_cube_map_array) &&
311             (iter.second == EBhRequire || iter.second == EBhEnable))
312         {
313             usesTextureCubeMapArray = true;
314         }
315 
316         if ((iter.first == TExtension::OES_texture_buffer ||
317              iter.first == TExtension::EXT_texture_buffer) &&
318             (iter.second == EBhRequire || iter.second == EBhEnable))
319         {
320             usesTextureBuffer = true;
321         }
322     }
323 
324     // GLSL ES 3 explicit location qualifiers need to use an extension before GLSL 330
325     if (getShaderVersion() >= 300 && getOutputType() < SH_GLSL_330_CORE_OUTPUT &&
326         getShaderType() != GL_COMPUTE_SHADER)
327     {
328         sink << "#extension GL_ARB_explicit_attrib_location : require\n";
329     }
330 
331     // Need to enable gpu_shader5 to have index constant sampler array indexing
332     if (getOutputType() != SH_ESSL_OUTPUT && getOutputType() < SH_GLSL_400_CORE_OUTPUT &&
333         getShaderVersion() == 100)
334     {
335         // Don't use "require" on to avoid breaking WebGL 1 on drivers that silently
336         // support index constant sampler array indexing, but don't have the extension or
337         // on drivers that don't have the extension at all as it would break WebGL 1 for
338         // some users.
339         sink << "#extension GL_ARB_gpu_shader5 : enable\n";
340         sink << "#extension GL_EXT_gpu_shader5 : enable\n";
341     }
342 
343     if (usesTextureCubeMapArray)
344     {
345         if (getOutputType() >= SH_GLSL_COMPATIBILITY_OUTPUT &&
346             getOutputType() < SH_GLSL_400_CORE_OUTPUT)
347         {
348             sink << "#extension GL_ARB_texture_cube_map_array : enable\n";
349         }
350         else if (getOutputType() == SH_ESSL_OUTPUT && getShaderVersion() < 320)
351         {
352             sink << "#extension GL_OES_texture_cube_map_array : enable\n";
353             sink << "#extension GL_EXT_texture_cube_map_array : enable\n";
354         }
355     }
356 
357     if (usesTextureBuffer)
358     {
359         if (getOutputType() >= SH_GLSL_COMPATIBILITY_OUTPUT &&
360             getOutputType() < SH_GLSL_400_CORE_OUTPUT)
361         {
362             sink << "#extension GL_ARB_texture_buffer_objects : enable\n";
363         }
364         else if (getOutputType() == SH_ESSL_OUTPUT && getShaderVersion() < 320)
365         {
366             sink << "#extension GL_OES_texture_buffer : enable\n";
367             sink << "#extension GL_EXT_texture_buffer : enable\n";
368         }
369     }
370 
371     TExtensionGLSL extensionGLSL(getOutputType());
372     root->traverse(&extensionGLSL);
373 
374     for (const auto &ext : extensionGLSL.getEnabledExtensions())
375     {
376         sink << "#extension " << ext << " : enable\n";
377     }
378     for (const auto &ext : extensionGLSL.getRequiredExtensions())
379     {
380         sink << "#extension " << ext << " : require\n";
381     }
382 }
383 
conditionallyOutputInvariantDeclaration(const char * builtinVaryingName)384 void TranslatorGLSL::conditionallyOutputInvariantDeclaration(const char *builtinVaryingName)
385 {
386     if (isVaryingDefined(builtinVaryingName))
387     {
388         TInfoSinkBase &sink = getInfoSink().obj;
389         sink << "invariant " << builtinVaryingName << ";\n";
390     }
391 }
392 
393 }  // namespace sh
394