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