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/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)
29 {
30 InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(emu, getShaderType());
31 }
32
33 if (compileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION)
34 {
35 InitBuiltInIsnanFunctionEmulatorForGLSLWorkarounds(emu, getShaderVersion());
36 }
37
38 if (compileOptions & SH_EMULATE_ATAN2_FLOAT_FUNCTION)
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(compileOptions);
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 // Write array bounds clamping emulation if needed.
134 getArrayBoundsClamper().OutputClampingFunctionDefinition(sink);
135
136 // Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData
137 // if it's core profile shaders and they are used.
138 if (getShaderType() == GL_FRAGMENT_SHADER)
139 {
140 const bool mayHaveESSL1SecondaryOutputs =
141 IsExtensionEnabled(getExtensionBehavior(), TExtension::EXT_blend_func_extended) &&
142 getShaderVersion() == 100;
143 const bool declareGLFragmentOutputs = IsGLSL130OrNewer(getOutputType());
144
145 bool hasGLFragColor = false;
146 bool hasGLFragData = false;
147 bool hasGLSecondaryFragColor = false;
148 bool hasGLSecondaryFragData = false;
149
150 for (const auto &outputVar : mOutputVariables)
151 {
152 if (declareGLFragmentOutputs)
153 {
154 if (outputVar.name == "gl_FragColor")
155 {
156 ASSERT(!hasGLFragColor);
157 hasGLFragColor = true;
158 continue;
159 }
160 else if (outputVar.name == "gl_FragData")
161 {
162 ASSERT(!hasGLFragData);
163 hasGLFragData = true;
164 continue;
165 }
166 }
167 if (mayHaveESSL1SecondaryOutputs)
168 {
169 if (outputVar.name == "gl_SecondaryFragColorEXT")
170 {
171 ASSERT(!hasGLSecondaryFragColor);
172 hasGLSecondaryFragColor = true;
173 continue;
174 }
175 else if (outputVar.name == "gl_SecondaryFragDataEXT")
176 {
177 ASSERT(!hasGLSecondaryFragData);
178 hasGLSecondaryFragData = true;
179 continue;
180 }
181 }
182 }
183 ASSERT(!((hasGLFragColor || hasGLSecondaryFragColor) &&
184 (hasGLFragData || hasGLSecondaryFragData)));
185 if (hasGLFragColor)
186 {
187 sink << "out vec4 webgl_FragColor;\n";
188 }
189 if (hasGLFragData)
190 {
191 sink << "out vec4 webgl_FragData[gl_MaxDrawBuffers];\n";
192 }
193 if (hasGLSecondaryFragColor)
194 {
195 sink << "out vec4 angle_SecondaryFragColor;\n";
196 }
197 if (hasGLSecondaryFragData)
198 {
199 sink << "out vec4 angle_SecondaryFragData[" << getResources().MaxDualSourceDrawBuffers
200 << "];\n";
201 }
202
203 EmitEarlyFragmentTestsGLSL(*this, sink);
204 }
205
206 if (getShaderType() == GL_COMPUTE_SHADER)
207 {
208 EmitWorkGroupSizeGLSL(*this, sink);
209 }
210
211 if (getShaderType() == GL_GEOMETRY_SHADER_EXT)
212 {
213 WriteGeometryShaderLayoutQualifiers(
214 sink, getGeometryShaderInputPrimitiveType(), getGeometryShaderInvocations(),
215 getGeometryShaderOutputPrimitiveType(), getGeometryShaderMaxVertices());
216 }
217
218 // Write translated shader.
219 TOutputGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(),
220 &getSymbolTable(), getShaderType(), getShaderVersion(), getOutputType(),
221 compileOptions);
222
223 root->traverse(&outputGLSL);
224
225 return true;
226 }
227
shouldFlattenPragmaStdglInvariantAll()228 bool TranslatorGLSL::shouldFlattenPragmaStdglInvariantAll()
229 {
230 // Required when outputting to any GLSL version greater than 1.20, but since ANGLE doesn't
231 // translate to that version, return true for the next higher version.
232 return IsGLSL130OrNewer(getOutputType());
233 }
234
shouldCollectVariables(ShCompileOptions compileOptions)235 bool TranslatorGLSL::shouldCollectVariables(ShCompileOptions compileOptions)
236 {
237 return (compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) ||
238 TCompiler::shouldCollectVariables(compileOptions);
239 }
240
writeVersion(TIntermNode * root)241 void TranslatorGLSL::writeVersion(TIntermNode *root)
242 {
243 TVersionGLSL versionGLSL(getShaderType(), getPragma(), getOutputType());
244 root->traverse(&versionGLSL);
245 int version = versionGLSL.getVersion();
246 // We need to write version directive only if it is greater than 110.
247 // If there is no version directive in the shader, 110 is implied.
248 if (version > 110)
249 {
250 TInfoSinkBase &sink = getInfoSink().obj;
251 sink << "#version " << version << "\n";
252 }
253 }
254
writeExtensionBehavior(TIntermNode * root,ShCompileOptions compileOptions)255 void TranslatorGLSL::writeExtensionBehavior(TIntermNode *root, ShCompileOptions compileOptions)
256 {
257 bool usesTextureCubeMapArray = false;
258 bool usesTextureBuffer = false;
259
260 TInfoSinkBase &sink = getInfoSink().obj;
261 const TExtensionBehavior &extBehavior = getExtensionBehavior();
262 for (const auto &iter : extBehavior)
263 {
264 if (iter.second == EBhUndefined)
265 {
266 continue;
267 }
268
269 if (getOutputType() == SH_GLSL_COMPATIBILITY_OUTPUT)
270 {
271 // For GLSL output, we don't need to emit most extensions explicitly,
272 // but some we need to translate in GL compatibility profile.
273 if (iter.first == TExtension::EXT_shader_texture_lod)
274 {
275 sink << "#extension GL_ARB_shader_texture_lod : " << GetBehaviorString(iter.second)
276 << "\n";
277 }
278
279 if (iter.first == TExtension::EXT_draw_buffers)
280 {
281 sink << "#extension GL_ARB_draw_buffers : " << GetBehaviorString(iter.second)
282 << "\n";
283 }
284
285 if (iter.first == TExtension::EXT_geometry_shader)
286 {
287 sink << "#extension GL_ARB_geometry_shader4 : " << GetBehaviorString(iter.second)
288 << "\n";
289 }
290 }
291
292 const bool isMultiview =
293 (iter.first == TExtension::OVR_multiview) || (iter.first == TExtension::OVR_multiview2);
294 if (isMultiview)
295 {
296 // Only either OVR_multiview or OVR_multiview2 should be emitted.
297 if ((iter.first != TExtension::OVR_multiview) ||
298 !IsExtensionEnabled(extBehavior, TExtension::OVR_multiview2))
299 {
300 EmitMultiviewGLSL(*this, compileOptions, iter.first, iter.second, sink);
301 }
302 }
303
304 // Support ANGLE_texture_multisample extension on GLSL300
305 if (getShaderVersion() >= 300 && iter.first == TExtension::ANGLE_texture_multisample &&
306 getOutputType() < SH_GLSL_330_CORE_OUTPUT)
307 {
308 sink << "#extension GL_ARB_texture_multisample : " << GetBehaviorString(iter.second)
309 << "\n";
310 }
311
312 if ((iter.first == TExtension::OES_texture_cube_map_array ||
313 iter.first == TExtension::EXT_texture_cube_map_array) &&
314 (iter.second == EBhRequire || iter.second == EBhEnable))
315 {
316 usesTextureCubeMapArray = true;
317 }
318
319 if ((iter.first == TExtension::OES_texture_buffer ||
320 iter.first == TExtension::EXT_texture_buffer) &&
321 (iter.second == EBhRequire || iter.second == EBhEnable))
322 {
323 usesTextureBuffer = true;
324 }
325 }
326
327 // GLSL ES 3 explicit location qualifiers need to use an extension before GLSL 330
328 if (getShaderVersion() >= 300 && getOutputType() < SH_GLSL_330_CORE_OUTPUT &&
329 getShaderType() != GL_COMPUTE_SHADER)
330 {
331 sink << "#extension GL_ARB_explicit_attrib_location : require\n";
332 }
333
334 // Need to enable gpu_shader5 to have index constant sampler array indexing
335 if (getOutputType() != SH_ESSL_OUTPUT && getOutputType() < SH_GLSL_400_CORE_OUTPUT &&
336 getShaderVersion() == 100)
337 {
338 // Don't use "require" on to avoid breaking WebGL 1 on drivers that silently
339 // support index constant sampler array indexing, but don't have the extension or
340 // on drivers that don't have the extension at all as it would break WebGL 1 for
341 // some users.
342 sink << "#extension GL_ARB_gpu_shader5 : enable\n";
343 sink << "#extension GL_EXT_gpu_shader5 : enable\n";
344 }
345
346 if (usesTextureCubeMapArray)
347 {
348 if (getOutputType() >= SH_GLSL_COMPATIBILITY_OUTPUT &&
349 getOutputType() < SH_GLSL_400_CORE_OUTPUT)
350 {
351 sink << "#extension GL_ARB_texture_cube_map_array : enable\n";
352 }
353 else if (getOutputType() == SH_ESSL_OUTPUT && getShaderVersion() < 320)
354 {
355 sink << "#extension GL_OES_texture_cube_map_array : enable\n";
356 sink << "#extension GL_EXT_texture_cube_map_array : enable\n";
357 }
358 }
359
360 if (usesTextureBuffer)
361 {
362 if (getOutputType() >= SH_GLSL_COMPATIBILITY_OUTPUT &&
363 getOutputType() < SH_GLSL_400_CORE_OUTPUT)
364 {
365 sink << "#extension GL_ARB_texture_buffer_objects : enable\n";
366 }
367 else if (getOutputType() == SH_ESSL_OUTPUT && getShaderVersion() < 320)
368 {
369 sink << "#extension GL_OES_texture_buffer : enable\n";
370 sink << "#extension GL_EXT_texture_buffer : enable\n";
371 }
372 }
373
374 TExtensionGLSL extensionGLSL(getOutputType());
375 root->traverse(&extensionGLSL);
376
377 for (const auto &ext : extensionGLSL.getEnabledExtensions())
378 {
379 sink << "#extension " << ext << " : enable\n";
380 }
381 for (const auto &ext : extensionGLSL.getRequiredExtensions())
382 {
383 sink << "#extension " << ext << " : require\n";
384 }
385 }
386
conditionallyOutputInvariantDeclaration(const char * builtinVaryingName)387 void TranslatorGLSL::conditionallyOutputInvariantDeclaration(const char *builtinVaryingName)
388 {
389 if (isVaryingDefined(builtinVaryingName))
390 {
391 TInfoSinkBase &sink = getInfoSink().obj;
392 sink << "invariant " << builtinVaryingName << ";\n";
393 }
394 }
395
396 } // namespace sh
397