Line data Source code
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/VersionGLSL.h"
16 :
17 : namespace sh
18 : {
19 :
20 0 : TranslatorGLSL::TranslatorGLSL(sh::GLenum type,
21 : ShShaderSpec spec,
22 0 : ShShaderOutput output)
23 0 : : TCompiler(type, spec, output) {
24 0 : }
25 :
26 0 : void TranslatorGLSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu,
27 : ShCompileOptions compileOptions)
28 : {
29 0 : if (compileOptions & SH_EMULATE_ABS_INT_FUNCTION)
30 : {
31 0 : InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(emu, getShaderType());
32 : }
33 :
34 0 : if (compileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION)
35 : {
36 0 : InitBuiltInIsnanFunctionEmulatorForGLSLWorkarounds(emu, getShaderVersion());
37 : }
38 :
39 0 : int targetGLSLVersion = ShaderOutputTypeToGLSLVersion(getOutputType());
40 0 : InitBuiltInFunctionEmulatorForGLSLMissingFunctions(emu, getShaderType(), targetGLSLVersion);
41 0 : }
42 :
43 0 : void TranslatorGLSL::translate(TIntermNode *root, ShCompileOptions compileOptions)
44 : {
45 0 : TInfoSinkBase& sink = getInfoSink().obj;
46 :
47 : // Write GLSL version.
48 0 : writeVersion(root);
49 :
50 : // Write extension behaviour as needed
51 0 : writeExtensionBehavior(root);
52 :
53 : // Write pragmas after extensions because some drivers consider pragmas
54 : // like non-preprocessor tokens.
55 0 : writePragma(compileOptions);
56 :
57 : // If flattening the global invariant pragma, write invariant declarations for built-in
58 : // variables. It should be harmless to do this twice in the case that the shader also explicitly
59 : // did this. However, it's important to emit invariant qualifiers only for those built-in
60 : // variables that are actually used, to avoid affecting the behavior of the shader.
61 0 : if ((compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) != 0 &&
62 0 : getPragma().stdgl.invariantAll &&
63 0 : !sh::RemoveInvariant(getShaderType(), getShaderVersion(), getOutputType(), compileOptions))
64 : {
65 0 : ASSERT(wereVariablesCollected());
66 :
67 0 : switch (getShaderType())
68 : {
69 : case GL_VERTEX_SHADER:
70 0 : sink << "invariant gl_Position;\n";
71 :
72 : // gl_PointSize should be declared invariant in both ESSL 1.00 and 3.00 fragment
73 : // shaders if it's statically referenced.
74 0 : conditionallyOutputInvariantDeclaration("gl_PointSize");
75 0 : break;
76 : case GL_FRAGMENT_SHADER:
77 : // The preprocessor will reject this pragma if it's used in ESSL 3.00 fragment
78 : // shaders, so we can use simple logic to determine whether to declare these
79 : // variables invariant.
80 0 : conditionallyOutputInvariantDeclaration("gl_FragCoord");
81 0 : conditionallyOutputInvariantDeclaration("gl_PointCoord");
82 0 : break;
83 : default:
84 : // Currently not reached, but leave this in for future expansion.
85 0 : ASSERT(false);
86 : break;
87 : }
88 : }
89 :
90 0 : if ((compileOptions & SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH) != 0)
91 : {
92 0 : sh::RewriteTexelFetchOffset(root, getSymbolTable(), getShaderVersion());
93 : }
94 :
95 0 : bool precisionEmulation = getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision;
96 :
97 0 : if (precisionEmulation)
98 : {
99 0 : EmulatePrecision emulatePrecision(getSymbolTable(), getShaderVersion());
100 0 : root->traverse(&emulatePrecision);
101 0 : emulatePrecision.updateTree();
102 0 : emulatePrecision.writeEmulationHelpers(sink, getShaderVersion(), getOutputType());
103 : }
104 :
105 : // Write emulated built-in functions if needed.
106 0 : if (!getBuiltInFunctionEmulator().IsOutputEmpty())
107 : {
108 0 : sink << "// BEGIN: Generated code for built-in function emulation\n\n";
109 0 : sink << "#define webgl_emu_precision\n\n";
110 0 : getBuiltInFunctionEmulator().OutputEmulatedFunctions(sink);
111 0 : sink << "// END: Generated code for built-in function emulation\n\n";
112 : }
113 :
114 : // Write array bounds clamping emulation if needed.
115 0 : getArrayBoundsClamper().OutputClampingFunctionDefinition(sink);
116 :
117 : // Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData
118 : // if it's core profile shaders and they are used.
119 0 : if (getShaderType() == GL_FRAGMENT_SHADER)
120 : {
121 : const bool mayHaveESSL1SecondaryOutputs =
122 0 : IsExtensionEnabled(getExtensionBehavior(), "GL_EXT_blend_func_extended") &&
123 0 : getShaderVersion() == 100;
124 0 : const bool declareGLFragmentOutputs = IsGLSL130OrNewer(getOutputType());
125 :
126 0 : bool hasGLFragColor = false;
127 0 : bool hasGLFragData = false;
128 0 : bool hasGLSecondaryFragColor = false;
129 0 : bool hasGLSecondaryFragData = false;
130 :
131 0 : for (const auto &outputVar : outputVariables)
132 : {
133 0 : if (declareGLFragmentOutputs)
134 : {
135 0 : if (outputVar.name == "gl_FragColor")
136 : {
137 0 : ASSERT(!hasGLFragColor);
138 0 : hasGLFragColor = true;
139 0 : continue;
140 : }
141 0 : else if (outputVar.name == "gl_FragData")
142 : {
143 0 : ASSERT(!hasGLFragData);
144 0 : hasGLFragData = true;
145 0 : continue;
146 : }
147 : }
148 0 : if (mayHaveESSL1SecondaryOutputs)
149 : {
150 0 : if (outputVar.name == "gl_SecondaryFragColorEXT")
151 : {
152 0 : ASSERT(!hasGLSecondaryFragColor);
153 0 : hasGLSecondaryFragColor = true;
154 0 : continue;
155 : }
156 0 : else if (outputVar.name == "gl_SecondaryFragDataEXT")
157 : {
158 0 : ASSERT(!hasGLSecondaryFragData);
159 0 : hasGLSecondaryFragData = true;
160 0 : continue;
161 : }
162 : }
163 : }
164 0 : ASSERT(!((hasGLFragColor || hasGLSecondaryFragColor) &&
165 : (hasGLFragData || hasGLSecondaryFragData)));
166 0 : if (hasGLFragColor)
167 : {
168 0 : sink << "out vec4 webgl_FragColor;\n";
169 : }
170 0 : if (hasGLFragData)
171 : {
172 0 : sink << "out vec4 webgl_FragData[gl_MaxDrawBuffers];\n";
173 : }
174 0 : if (hasGLSecondaryFragColor)
175 : {
176 0 : sink << "out vec4 angle_SecondaryFragColor;\n";
177 : }
178 0 : if (hasGLSecondaryFragData)
179 : {
180 0 : sink << "out vec4 angle_SecondaryFragData[" << getResources().MaxDualSourceDrawBuffers
181 0 : << "];\n";
182 : }
183 : }
184 :
185 0 : if (getShaderType() == GL_COMPUTE_SHADER && isComputeShaderLocalSizeDeclared())
186 : {
187 0 : const sh::WorkGroupSize &localSize = getComputeShaderLocalSize();
188 0 : sink << "layout (local_size_x=" << localSize[0] << ", local_size_y=" << localSize[1]
189 0 : << ", local_size_z=" << localSize[2] << ") in;\n";
190 : }
191 :
192 : // Write translated shader.
193 : TOutputGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(),
194 : getSymbolTable(), getShaderType(), getShaderVersion(), getOutputType(),
195 0 : compileOptions);
196 0 : root->traverse(&outputGLSL);
197 0 : }
198 :
199 0 : bool TranslatorGLSL::shouldFlattenPragmaStdglInvariantAll()
200 : {
201 : // Required when outputting to any GLSL version greater than 1.20, but since ANGLE doesn't
202 : // translate to that version, return true for the next higher version.
203 0 : return IsGLSL130OrNewer(getOutputType());
204 : }
205 :
206 0 : bool TranslatorGLSL::shouldCollectVariables(ShCompileOptions compileOptions)
207 : {
208 0 : return (compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) ||
209 0 : TCompiler::shouldCollectVariables(compileOptions);
210 : }
211 :
212 0 : void TranslatorGLSL::writeVersion(TIntermNode *root)
213 : {
214 0 : TVersionGLSL versionGLSL(getShaderType(), getPragma(), getOutputType());
215 0 : root->traverse(&versionGLSL);
216 0 : int version = versionGLSL.getVersion();
217 : // We need to write version directive only if it is greater than 110.
218 : // If there is no version directive in the shader, 110 is implied.
219 0 : if (version > 110)
220 : {
221 0 : TInfoSinkBase& sink = getInfoSink().obj;
222 0 : sink << "#version " << version << "\n";
223 : }
224 0 : }
225 :
226 0 : void TranslatorGLSL::writeExtensionBehavior(TIntermNode *root)
227 : {
228 0 : TInfoSinkBase& sink = getInfoSink().obj;
229 0 : const TExtensionBehavior& extBehavior = getExtensionBehavior();
230 0 : for (const auto &iter : extBehavior)
231 : {
232 0 : if (iter.second == EBhUndefined)
233 : {
234 0 : continue;
235 : }
236 :
237 0 : if (getOutputType() == SH_GLSL_COMPATIBILITY_OUTPUT)
238 : {
239 : // For GLSL output, we don't need to emit most extensions explicitly,
240 : // but some we need to translate in GL compatibility profile.
241 0 : if (iter.first == "GL_EXT_shader_texture_lod")
242 : {
243 0 : sink << "#extension GL_ARB_shader_texture_lod : " << getBehaviorString(iter.second)
244 0 : << "\n";
245 : }
246 :
247 0 : if (iter.first == "GL_EXT_draw_buffers")
248 : {
249 0 : sink << "#extension GL_ARB_draw_buffers : " << getBehaviorString(iter.second)
250 0 : << "\n";
251 : }
252 : }
253 : }
254 :
255 : // GLSL ES 3 explicit location qualifiers need to use an extension before GLSL 330
256 0 : if (getShaderVersion() >= 300 && getOutputType() < SH_GLSL_330_CORE_OUTPUT &&
257 0 : getShaderType() != GL_COMPUTE_SHADER)
258 : {
259 0 : sink << "#extension GL_ARB_explicit_attrib_location : require\n";
260 : }
261 :
262 : // Need to enable gpu_shader5 to have index constant sampler array indexing
263 0 : if (getOutputType() != SH_ESSL_OUTPUT && getOutputType() < SH_GLSL_400_CORE_OUTPUT &&
264 0 : getShaderVersion() == 100)
265 : {
266 : // Don't use "require" on to avoid breaking WebGL 1 on drivers that silently
267 : // support index constant sampler array indexing, but don't have the extension or
268 : // on drivers that don't have the extension at all as it would break WebGL 1 for
269 : // some users.
270 0 : sink << "#extension GL_ARB_gpu_shader5 : enable\n";
271 : }
272 :
273 0 : TExtensionGLSL extensionGLSL(getOutputType());
274 0 : root->traverse(&extensionGLSL);
275 :
276 0 : for (const auto &ext : extensionGLSL.getEnabledExtensions())
277 : {
278 0 : sink << "#extension " << ext << " : enable\n";
279 : }
280 0 : for (const auto &ext : extensionGLSL.getRequiredExtensions())
281 : {
282 0 : sink << "#extension " << ext << " : require\n";
283 : }
284 0 : }
285 :
286 0 : void TranslatorGLSL::conditionallyOutputInvariantDeclaration(const char *builtinVaryingName)
287 : {
288 0 : if (isVaryingDefined(builtinVaryingName))
289 : {
290 0 : TInfoSinkBase &sink = getInfoSink().obj;
291 0 : sink << "invariant " << builtinVaryingName << ";\n";
292 : }
293 0 : }
294 :
295 : } // namespace sh
|