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/TranslatorESSL.h"
8
9 #include "angle_gl.h"
10 #include "common/utilities.h"
11 #include "compiler/translator/StaticType.h"
12 #include "compiler/translator/glsl/BuiltInFunctionEmulatorGLSL.h"
13 #include "compiler/translator/glsl/OutputESSL.h"
14 #include "compiler/translator/tree_ops/DeclarePerVertexBlocks.h"
15 #include "compiler/translator/tree_ops/RecordConstantPrecision.h"
16 #include "compiler/translator/tree_util/FindSymbolNode.h"
17 #include "compiler/translator/tree_util/ReplaceClipCullDistanceVariable.h"
18 #include "compiler/translator/tree_util/RunAtTheEndOfShader.h"
19 #include "compiler/translator/util.h"
20
21 namespace sh
22 {
23
24 namespace
25 {
26
EmulateClipOrigin(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable)27 bool EmulateClipOrigin(TCompiler *compiler, TIntermBlock *root, TSymbolTable *symbolTable)
28 {
29 // Skip the operation if gl_Position is not used.
30 const TIntermSymbol *positionSymbol = FindSymbolNode(root, ImmutableString("gl_Position"));
31 if (!positionSymbol)
32 {
33 return true;
34 }
35
36 const TType *type = StaticType::Get<EbtFloat, EbpHigh, EvqUniform, 1, 1>();
37 const TVariable *clipOrigin = new TVariable(symbolTable, ImmutableString("angle_ClipOrigin"),
38 type, SymbolType::AngleInternal);
39
40 DeclareGlobalVariable(root, clipOrigin);
41
42 // gl_Position.y *= angle_clipOrigin;
43 TIntermSwizzle *positionY =
44 new TIntermSwizzle(new TIntermSymbol(&positionSymbol->variable()), {1});
45 TIntermBinary *applyOrigin =
46 new TIntermBinary(EOpMulAssign, positionY, new TIntermSymbol(clipOrigin));
47
48 return RunAtTheEndOfShader(compiler, root, applyOrigin, symbolTable);
49 }
50
51 } // namespace
52
TranslatorESSL(sh::GLenum type,ShShaderSpec spec)53 TranslatorESSL::TranslatorESSL(sh::GLenum type, ShShaderSpec spec)
54 : TCompiler(type, spec, SH_ESSL_OUTPUT)
55 {}
56
initBuiltInFunctionEmulator(BuiltInFunctionEmulator * emu,const ShCompileOptions & compileOptions)57 void TranslatorESSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu,
58 const ShCompileOptions &compileOptions)
59 {
60 if (compileOptions.emulateAtan2FloatFunction)
61 {
62 InitBuiltInAtanFunctionEmulatorForGLSLWorkarounds(emu);
63 }
64 }
65
translate(TIntermBlock * root,const ShCompileOptions & compileOptions,PerformanceDiagnostics *)66 bool TranslatorESSL::translate(TIntermBlock *root,
67 const ShCompileOptions &compileOptions,
68 PerformanceDiagnostics * /*perfDiagnostics*/)
69 {
70 TInfoSinkBase &sink = getInfoSink().obj;
71
72 int shaderVer = getShaderVersion(); // Frontend shader version.
73 if (shaderVer == 300)
74 {
75 // Although all these extensions are defined for ESSL 3.00,
76 // some drivers may support the required functionality only
77 // with ESSL 3.10.
78 const bool hasExtensionsThatMayRequireES31 =
79 getResources().EXT_clip_cull_distance || getResources().ANGLE_clip_cull_distance ||
80 getResources().NV_shader_noperspective_interpolation ||
81 getResources().OES_shader_multisample_interpolation ||
82 getResources().ANGLE_texture_multisample;
83
84 // When PLS is implemented with shader images,
85 // ESSL 3.10 output is required.
86 const bool usesShaderImagesForPLS =
87 hasPixelLocalStorageUniforms() &&
88 compileOptions.pls.type == ShPixelLocalStorageType::ImageLoadStore;
89
90 if (hasExtensionsThatMayRequireES31 || usesShaderImagesForPLS)
91 {
92 shaderVer = 310;
93 }
94 }
95 if (shaderVer > 100)
96 {
97 sink << "#version " << shaderVer << " es\n";
98 }
99
100 // Write built-in extension behaviors.
101 writeExtensionBehavior(compileOptions);
102
103 // Write pragmas after extensions because some drivers consider pragmas
104 // like non-preprocessor tokens.
105 WritePragma(sink, compileOptions, getPragma());
106
107 if (!RecordConstantPrecision(this, root, &getSymbolTable()))
108 {
109 return false;
110 }
111
112 // Write emulated built-in functions if needed.
113 if (!getBuiltInFunctionEmulator().isOutputEmpty())
114 {
115 sink << "// BEGIN: Generated code for built-in function emulation\n\n";
116 if (getShaderType() == GL_FRAGMENT_SHADER)
117 {
118 sink << "#if defined(GL_FRAGMENT_PRECISION_HIGH)\n"
119 << "#define emu_precision highp\n"
120 << "#else\n"
121 << "#define emu_precision mediump\n"
122 << "#endif\n\n";
123 }
124 else
125 {
126 sink << "#define emu_precision highp\n";
127 }
128
129 getBuiltInFunctionEmulator().outputEmulatedFunctions(sink);
130 sink << "// END: Generated code for built-in function emulation\n\n";
131 }
132
133 if (getShaderType() == GL_VERTEX_SHADER)
134 {
135 // Emulate GL_CLIP_DISTANCEi_EXT state if needed
136 if (mMetadataFlags[MetadataFlags::HasClipDistance] &&
137 compileOptions.emulateClipDistanceState)
138 {
139 constexpr const ImmutableString kClipDistanceEnabledName("angle_ClipDistanceEnabled");
140
141 const TType *type = StaticType::Get<EbtUInt, EbpLow, EvqUniform, 1, 1>();
142 const TVariable *clipDistanceEnabled = new TVariable(
143 &getSymbolTable(), kClipDistanceEnabledName, type, SymbolType::AngleInternal);
144 const TIntermSymbol *clipDistanceEnabledSymbol = new TIntermSymbol(clipDistanceEnabled);
145
146 // AngleInternal variables don't get collected
147 ShaderVariable uniform;
148 uniform.name = kClipDistanceEnabledName.data();
149 uniform.mappedName = kClipDistanceEnabledName.data();
150 uniform.type = GLVariableType(*type);
151 uniform.precision = GLVariablePrecision(*type);
152 uniform.staticUse = true;
153 uniform.active = true;
154 uniform.binding = type->getLayoutQualifier().binding;
155 uniform.location = type->getLayoutQualifier().location;
156 uniform.offset = type->getLayoutQualifier().offset;
157 uniform.rasterOrdered = type->getLayoutQualifier().rasterOrdered;
158 uniform.readonly = type->getMemoryQualifier().readonly;
159 uniform.writeonly = type->getMemoryQualifier().writeonly;
160 mUniforms.push_back(uniform);
161
162 DeclareGlobalVariable(root, clipDistanceEnabled);
163 if (!ZeroDisabledClipDistanceAssignments(this, root, &getSymbolTable(), getShaderType(),
164 clipDistanceEnabledSymbol))
165 return false;
166
167 // The previous operation always redeclares gl_ClipDistance
168 if (!DeclarePerVertexBlocks(this, root, &getSymbolTable(), nullptr, nullptr))
169 return false;
170 }
171 else if (areClipDistanceOrCullDistanceUsed() &&
172 (IsExtensionEnabled(getExtensionBehavior(), TExtension::EXT_clip_cull_distance) ||
173 IsExtensionEnabled(getExtensionBehavior(), TExtension::ANGLE_clip_cull_distance)))
174 {
175 // When clip distance state emulation is not needed,
176 // the redeclared extension built-ins still should be moved to gl_PerVertex
177 if (!DeclarePerVertexBlocks(this, root, &getSymbolTable(), nullptr, nullptr))
178 return false;
179 }
180
181 if (compileOptions.emulateClipOrigin)
182 {
183 if (!EmulateClipOrigin(this, root, &getSymbolTable()))
184 {
185 return false;
186 }
187 }
188 }
189
190 if (getShaderType() == GL_FRAGMENT_SHADER)
191 {
192 EmitEarlyFragmentTestsGLSL(*this, sink);
193 WriteFragmentShaderLayoutQualifiers(sink, getAdvancedBlendEquations());
194 }
195
196 if (getShaderType() == GL_COMPUTE_SHADER)
197 {
198 EmitWorkGroupSizeGLSL(*this, sink);
199 }
200
201 if (getShaderType() == GL_GEOMETRY_SHADER_EXT)
202 {
203 WriteGeometryShaderLayoutQualifiers(
204 sink, getGeometryShaderInputPrimitiveType(), getGeometryShaderInvocations(),
205 getGeometryShaderOutputPrimitiveType(), getGeometryShaderMaxVertices());
206 }
207
208 // Write translated shader.
209 TOutputESSL outputESSL(this, sink, compileOptions);
210
211 root->traverse(&outputESSL);
212
213 return true;
214 }
215
shouldFlattenPragmaStdglInvariantAll()216 bool TranslatorESSL::shouldFlattenPragmaStdglInvariantAll()
217 {
218 // If following the spec to the letter, we should not flatten this pragma.
219 // However, the spec's wording means that the pragma applies only to outputs.
220 // This contradicts the spirit of using the pragma,
221 // because if the pragma is used in a vertex shader,
222 // the only way to be able to link it to a fragment shader
223 // is to manually qualify each of fragment shader's inputs as invariant.
224 // Which defeats the purpose of this pragma - temporarily make all varyings
225 // invariant for debugging.
226 // Thus, we should be non-conformant to spec's letter here and flatten.
227 return true;
228 }
229
writeExtensionBehavior(const ShCompileOptions & compileOptions)230 void TranslatorESSL::writeExtensionBehavior(const ShCompileOptions &compileOptions)
231 {
232 TInfoSinkBase &sink = getInfoSink().obj;
233 const TExtensionBehavior &extBehavior = getExtensionBehavior();
234 for (TExtensionBehavior::const_iterator iter = extBehavior.begin(); iter != extBehavior.end();
235 ++iter)
236 {
237 if (iter->second != EBhUndefined)
238 {
239 const bool isMultiview = (iter->first == TExtension::OVR_multiview) ||
240 (iter->first == TExtension::OVR_multiview2);
241 if (getResources().NV_shader_framebuffer_fetch &&
242 iter->first == TExtension::EXT_shader_framebuffer_fetch)
243 {
244 sink << "#extension GL_NV_shader_framebuffer_fetch : "
245 << GetBehaviorString(iter->second) << "\n";
246 }
247 else if (getResources().NV_draw_buffers && iter->first == TExtension::EXT_draw_buffers)
248 {
249 sink << "#extension GL_NV_draw_buffers : " << GetBehaviorString(iter->second)
250 << "\n";
251 }
252 else if (isMultiview)
253 {
254 // Only either OVR_multiview OR OVR_multiview2 should be emitted.
255 if ((iter->first != TExtension::OVR_multiview) ||
256 !IsExtensionEnabled(extBehavior, TExtension::OVR_multiview2))
257 {
258 EmitMultiviewGLSL(*this, compileOptions, iter->first, iter->second, sink);
259 }
260 }
261 else if (iter->first == TExtension::EXT_geometry_shader ||
262 iter->first == TExtension::OES_geometry_shader)
263 {
264 sink << "#ifdef GL_EXT_geometry_shader\n"
265 << "#extension GL_EXT_geometry_shader : " << GetBehaviorString(iter->second)
266 << "\n"
267 << "#elif defined GL_OES_geometry_shader\n"
268 << "#extension GL_OES_geometry_shader : " << GetBehaviorString(iter->second)
269 << "\n";
270 if (iter->second == EBhRequire)
271 {
272 sink << "#else\n"
273 << "#error \"No geometry shader extensions available.\" // Only generate "
274 "this if the extension is \"required\"\n";
275 }
276 sink << "#endif\n";
277 }
278 else if (iter->first == TExtension::ANGLE_multi_draw)
279 {
280 // Don't emit anything. This extension is emulated
281 ASSERT(compileOptions.emulateGLDrawID);
282 continue;
283 }
284 else if (iter->first == TExtension::ANGLE_base_vertex_base_instance_shader_builtin)
285 {
286 // Don't emit anything. This extension is emulated
287 ASSERT(compileOptions.emulateGLBaseVertexBaseInstance);
288 continue;
289 }
290 else if (iter->first == TExtension::EXT_clip_cull_distance ||
291 iter->first == TExtension::ANGLE_clip_cull_distance)
292 {
293 sink << "#extension GL_EXT_clip_cull_distance : " << GetBehaviorString(iter->second)
294 << "\n";
295 if (areClipDistanceOrCullDistanceUsed())
296 {
297 sink << "#extension GL_EXT_shader_io_blocks : "
298 << GetBehaviorString(iter->second) << "\n";
299 }
300 }
301 else if (iter->first == TExtension::ANGLE_shader_pixel_local_storage)
302 {
303 if (compileOptions.pls.type == ShPixelLocalStorageType::FramebufferFetch)
304 {
305 // Just enable the extension. Appropriate warnings will be generated by the
306 // frontend compiler for GL_ANGLE_shader_pixel_local_storage, if desired.
307 sink << "#extension GL_EXT_shader_framebuffer_fetch : enable\n";
308 }
309 continue;
310 }
311 else if (iter->first == TExtension::EXT_shader_framebuffer_fetch)
312 {
313 sink << "#extension GL_EXT_shader_framebuffer_fetch : "
314 << GetBehaviorString(iter->second) << "\n";
315 continue;
316 }
317 else if (iter->first == TExtension::EXT_shader_framebuffer_fetch_non_coherent)
318 {
319 sink << "#extension GL_EXT_shader_framebuffer_fetch_non_coherent : "
320 << GetBehaviorString(iter->second) << "\n";
321 continue;
322 }
323 else if (iter->first == TExtension::ANGLE_texture_multisample)
324 {
325 // Don't emit anything. This functionality is core in ESSL 3.10.
326 continue;
327 }
328 else if (iter->first == TExtension::WEBGL_video_texture)
329 {
330 // Don't emit anything. This extension is emulated
331 // TODO(crbug.com/776222): support external image.
332 continue;
333 }
334 else
335 {
336 sink << "#extension " << GetExtensionNameString(iter->first) << " : "
337 << GetBehaviorString(iter->second) << "\n";
338 }
339 }
340 }
341 }
342
343 } // namespace sh
344