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