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