1 //
2 // Copyright (c) 2002-2013 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/EmulatePrecision.h"
12 #include "compiler/translator/ExtensionGLSL.h"
13 #include "compiler/translator/OutputGLSL.h"
14 #include "compiler/translator/RewriteTexelFetchOffset.h"
15 #include "compiler/translator/RewriteUnaryMinusOperatorFloat.h"
16 #include "compiler/translator/VersionGLSL.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 }
25
initBuiltInFunctionEmulator(BuiltInFunctionEmulator * emu,ShCompileOptions compileOptions)26 void TranslatorGLSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu,
27 ShCompileOptions compileOptions)
28 {
29 if (compileOptions & SH_EMULATE_ABS_INT_FUNCTION)
30 {
31 InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(emu, getShaderType());
32 }
33
34 if (compileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION)
35 {
36 InitBuiltInIsnanFunctionEmulatorForGLSLWorkarounds(emu, getShaderVersion());
37 }
38
39 if (compileOptions & SH_EMULATE_ATAN2_FLOAT_FUNCTION)
40 {
41 InitBuiltInAtanFunctionEmulatorForGLSLWorkarounds(emu);
42 }
43
44 int targetGLSLVersion = ShaderOutputTypeToGLSLVersion(getOutputType());
45 InitBuiltInFunctionEmulatorForGLSLMissingFunctions(emu, getShaderType(), targetGLSLVersion);
46 }
47
translate(TIntermBlock * root,ShCompileOptions compileOptions,PerformanceDiagnostics *)48 void TranslatorGLSL::translate(TIntermBlock *root,
49 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(compileOptions);
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 & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) != 0 &&
69 getPragma().stdgl.invariantAll &&
70 !sh::RemoveInvariant(getShaderType(), getShaderVersion(), getOutputType(), compileOptions))
71 {
72 ASSERT(wereVariablesCollected());
73
74 switch (getShaderType())
75 {
76 case GL_VERTEX_SHADER:
77 sink << "invariant gl_Position;\n";
78
79 // gl_PointSize should be declared invariant in both ESSL 1.00 and 3.00 fragment
80 // shaders if it's statically referenced.
81 conditionallyOutputInvariantDeclaration("gl_PointSize");
82 break;
83 case GL_FRAGMENT_SHADER:
84 // The preprocessor will reject this pragma if it's used in ESSL 3.00 fragment
85 // shaders, so we can use simple logic to determine whether to declare these
86 // variables invariant.
87 conditionallyOutputInvariantDeclaration("gl_FragCoord");
88 conditionallyOutputInvariantDeclaration("gl_PointCoord");
89 break;
90 default:
91 // Currently not reached, but leave this in for future expansion.
92 ASSERT(false);
93 break;
94 }
95 }
96
97 if ((compileOptions & SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH) != 0)
98 {
99 sh::RewriteTexelFetchOffset(root, getSymbolTable(), getShaderVersion());
100 }
101
102 if ((compileOptions & SH_REWRITE_FLOAT_UNARY_MINUS_OPERATOR) != 0)
103 {
104 sh::RewriteUnaryMinusOperatorFloat(root);
105 }
106
107 bool precisionEmulation =
108 getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision;
109
110 if (precisionEmulation)
111 {
112 EmulatePrecision emulatePrecision(&getSymbolTable(), getShaderVersion());
113 root->traverse(&emulatePrecision);
114 emulatePrecision.updateTree();
115 emulatePrecision.writeEmulationHelpers(sink, getShaderVersion(), getOutputType());
116 }
117
118 // Write emulated built-in functions if needed.
119 if (!getBuiltInFunctionEmulator().isOutputEmpty())
120 {
121 sink << "// BEGIN: Generated code for built-in function emulation\n\n";
122 sink << "#define emu_precision\n\n";
123 getBuiltInFunctionEmulator().outputEmulatedFunctions(sink);
124 sink << "// END: Generated code for built-in function emulation\n\n";
125 }
126
127 // Write array bounds clamping emulation if needed.
128 getArrayBoundsClamper().OutputClampingFunctionDefinition(sink);
129
130 // Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData
131 // if it's core profile shaders and they are used.
132 if (getShaderType() == GL_FRAGMENT_SHADER)
133 {
134 const bool mayHaveESSL1SecondaryOutputs =
135 IsExtensionEnabled(getExtensionBehavior(), TExtension::EXT_blend_func_extended) &&
136 getShaderVersion() == 100;
137 const bool declareGLFragmentOutputs = IsGLSL130OrNewer(getOutputType());
138
139 bool hasGLFragColor = false;
140 bool hasGLFragData = false;
141 bool hasGLSecondaryFragColor = false;
142 bool hasGLSecondaryFragData = false;
143
144 for (const auto &outputVar : outputVariables)
145 {
146 if (declareGLFragmentOutputs)
147 {
148 if (outputVar.name == "gl_FragColor")
149 {
150 ASSERT(!hasGLFragColor);
151 hasGLFragColor = true;
152 continue;
153 }
154 else if (outputVar.name == "gl_FragData")
155 {
156 ASSERT(!hasGLFragData);
157 hasGLFragData = true;
158 continue;
159 }
160 }
161 if (mayHaveESSL1SecondaryOutputs)
162 {
163 if (outputVar.name == "gl_SecondaryFragColorEXT")
164 {
165 ASSERT(!hasGLSecondaryFragColor);
166 hasGLSecondaryFragColor = true;
167 continue;
168 }
169 else if (outputVar.name == "gl_SecondaryFragDataEXT")
170 {
171 ASSERT(!hasGLSecondaryFragData);
172 hasGLSecondaryFragData = true;
173 continue;
174 }
175 }
176 }
177 ASSERT(!((hasGLFragColor || hasGLSecondaryFragColor) &&
178 (hasGLFragData || hasGLSecondaryFragData)));
179 if (hasGLFragColor)
180 {
181 sink << "out vec4 webgl_FragColor;\n";
182 }
183 if (hasGLFragData)
184 {
185 sink << "out vec4 webgl_FragData[gl_MaxDrawBuffers];\n";
186 }
187 if (hasGLSecondaryFragColor)
188 {
189 sink << "out vec4 angle_SecondaryFragColor;\n";
190 }
191 if (hasGLSecondaryFragData)
192 {
193 sink << "out vec4 angle_SecondaryFragData[" << getResources().MaxDualSourceDrawBuffers
194 << "];\n";
195 }
196 }
197
198 if (getShaderType() == GL_COMPUTE_SHADER && isComputeShaderLocalSizeDeclared())
199 {
200 const sh::WorkGroupSize &localSize = getComputeShaderLocalSize();
201 sink << "layout (local_size_x=" << localSize[0] << ", local_size_y=" << localSize[1]
202 << ", local_size_z=" << localSize[2] << ") in;\n";
203 }
204
205 if (getShaderType() == GL_GEOMETRY_SHADER_OES)
206 {
207 WriteGeometryShaderLayoutQualifiers(
208 sink, getGeometryShaderInputPrimitiveType(), getGeometryShaderInvocations(),
209 getGeometryShaderOutputPrimitiveType(), getGeometryShaderMaxVertices());
210 }
211
212 // Write translated shader.
213 TOutputGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(),
214 &getSymbolTable(), getShaderType(), getShaderVersion(), getOutputType(),
215 compileOptions);
216
217 if (compileOptions & SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM)
218 {
219 TName uniformName(TString("ViewID_OVR"));
220 uniformName.setInternal(true);
221 sink << "uniform int " << outputGLSL.hashName(uniformName) << ";\n";
222 }
223
224 root->traverse(&outputGLSL);
225 }
226
shouldFlattenPragmaStdglInvariantAll()227 bool TranslatorGLSL::shouldFlattenPragmaStdglInvariantAll()
228 {
229 // Required when outputting to any GLSL version greater than 1.20, but since ANGLE doesn't
230 // translate to that version, return true for the next higher version.
231 return IsGLSL130OrNewer(getOutputType());
232 }
233
shouldCollectVariables(ShCompileOptions compileOptions)234 bool TranslatorGLSL::shouldCollectVariables(ShCompileOptions compileOptions)
235 {
236 return (compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) ||
237 TCompiler::shouldCollectVariables(compileOptions);
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,ShCompileOptions compileOptions)254 void TranslatorGLSL::writeExtensionBehavior(TIntermNode *root, ShCompileOptions compileOptions)
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::OES_geometry_shader)
282 {
283 sink << "#extension GL_ARB_geometry_shader4 : " << GetBehaviorString(iter.second)
284 << "\n";
285 }
286 }
287
288 const bool isMultiview = (iter.first == TExtension::OVR_multiview);
289 if (isMultiview && getShaderType() == GL_VERTEX_SHADER &&
290 (compileOptions & SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER) != 0u)
291 {
292 // Emit the NV_viewport_array2 extension in a vertex shader if the
293 // SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER option is set and the OVR_multiview(2)
294 // extension is requested.
295 sink << "#extension GL_NV_viewport_array2 : require\n";
296 }
297 }
298
299 // GLSL ES 3 explicit location qualifiers need to use an extension before GLSL 330
300 if (getShaderVersion() >= 300 && getOutputType() < SH_GLSL_330_CORE_OUTPUT &&
301 getShaderType() != GL_COMPUTE_SHADER)
302 {
303 sink << "#extension GL_ARB_explicit_attrib_location : require\n";
304 }
305
306 // Need to enable gpu_shader5 to have index constant sampler array indexing
307 if (getOutputType() != SH_ESSL_OUTPUT && getOutputType() < SH_GLSL_400_CORE_OUTPUT &&
308 getShaderVersion() == 100)
309 {
310 // Don't use "require" on to avoid breaking WebGL 1 on drivers that silently
311 // support index constant sampler array indexing, but don't have the extension or
312 // on drivers that don't have the extension at all as it would break WebGL 1 for
313 // some users.
314 sink << "#extension GL_ARB_gpu_shader5 : enable\n";
315 }
316
317 TExtensionGLSL extensionGLSL(getOutputType());
318 root->traverse(&extensionGLSL);
319
320 for (const auto &ext : extensionGLSL.getEnabledExtensions())
321 {
322 sink << "#extension " << ext << " : enable\n";
323 }
324 for (const auto &ext : extensionGLSL.getRequiredExtensions())
325 {
326 sink << "#extension " << ext << " : require\n";
327 }
328 }
329
conditionallyOutputInvariantDeclaration(const char * builtinVaryingName)330 void TranslatorGLSL::conditionallyOutputInvariantDeclaration(const char *builtinVaryingName)
331 {
332 if (isVaryingDefined(builtinVaryingName))
333 {
334 TInfoSinkBase &sink = getInfoSink().obj;
335 sink << "invariant " << builtinVaryingName << ";\n";
336 }
337 }
338
339 } // namespace sh
340