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 > 100 &&
74 (getResources().EXT_clip_cull_distance || getResources().ANGLE_clip_cull_distance ||
75 getResources().NV_shader_noperspective_interpolation ||
76 getResources().OES_shader_multisample_interpolation)) ||
77 (hasPixelLocalStorageUniforms() &&
78 compileOptions.pls.type == ShPixelLocalStorageType::ImageLoadStore))
79 {
80 // The backend translator emits interface blocks or shader image code.
81 // Use a minimum version of 310.
82 shaderVer = std::max(shaderVer, 310);
83 }
84 if (shaderVer > 100)
85 {
86 sink << "#version " << shaderVer << " es\n";
87 }
88
89 // Write built-in extension behaviors.
90 writeExtensionBehavior(compileOptions);
91
92 // Write pragmas after extensions because some drivers consider pragmas
93 // like non-preprocessor tokens.
94 WritePragma(sink, compileOptions, getPragma());
95
96 if (!RecordConstantPrecision(this, root, &getSymbolTable()))
97 {
98 return false;
99 }
100
101 // Write emulated built-in functions if needed.
102 if (!getBuiltInFunctionEmulator().isOutputEmpty())
103 {
104 sink << "// BEGIN: Generated code for built-in function emulation\n\n";
105 if (getShaderType() == GL_FRAGMENT_SHADER)
106 {
107 sink << "#if defined(GL_FRAGMENT_PRECISION_HIGH)\n"
108 << "#define emu_precision highp\n"
109 << "#else\n"
110 << "#define emu_precision mediump\n"
111 << "#endif\n\n";
112 }
113 else
114 {
115 sink << "#define emu_precision highp\n";
116 }
117
118 getBuiltInFunctionEmulator().outputEmulatedFunctions(sink);
119 sink << "// END: Generated code for built-in function emulation\n\n";
120 }
121
122 if (getShaderType() == GL_VERTEX_SHADER)
123 {
124 // Emulate GL_CLIP_DISTANCEi_EXT state if needed
125 if (mMetadataFlags[MetadataFlags::HasClipDistance] &&
126 compileOptions.emulateClipDistanceState)
127 {
128 constexpr const ImmutableString kClipDistanceEnabledName("angle_ClipDistanceEnabled");
129
130 const TType *type = StaticType::Get<EbtUInt, EbpLow, EvqUniform, 1, 1>();
131 const TVariable *clipDistanceEnabled = new TVariable(
132 &getSymbolTable(), kClipDistanceEnabledName, type, SymbolType::AngleInternal);
133 const TIntermSymbol *clipDistanceEnabledSymbol = new TIntermSymbol(clipDistanceEnabled);
134
135 // AngleInternal variables don't get collected
136 ShaderVariable uniform;
137 uniform.name = kClipDistanceEnabledName.data();
138 uniform.mappedName = kClipDistanceEnabledName.data();
139 uniform.type = GLVariableType(*type);
140 uniform.precision = GLVariablePrecision(*type);
141 uniform.staticUse = true;
142 uniform.active = true;
143 uniform.binding = type->getLayoutQualifier().binding;
144 uniform.location = type->getLayoutQualifier().location;
145 uniform.offset = type->getLayoutQualifier().offset;
146 uniform.rasterOrdered = type->getLayoutQualifier().rasterOrdered;
147 uniform.readonly = type->getMemoryQualifier().readonly;
148 uniform.writeonly = type->getMemoryQualifier().writeonly;
149 mUniforms.push_back(uniform);
150
151 DeclareGlobalVariable(root, clipDistanceEnabled);
152 if (!ZeroDisabledClipDistanceAssignments(this, root, &getSymbolTable(), getShaderType(),
153 clipDistanceEnabledSymbol))
154 return false;
155
156 // The previous operation always redeclares gl_ClipDistance
157 if (!DeclarePerVertexBlocks(this, root, &getSymbolTable(), nullptr, nullptr))
158 return false;
159 }
160 else if (areClipDistanceOrCullDistanceUsed() &&
161 (IsExtensionEnabled(getExtensionBehavior(), TExtension::EXT_clip_cull_distance) ||
162 IsExtensionEnabled(getExtensionBehavior(), TExtension::ANGLE_clip_cull_distance)))
163 {
164 // When clip distance state emulation is not needed,
165 // the redeclared extension built-ins still should be moved to gl_PerVertex
166 if (!DeclarePerVertexBlocks(this, root, &getSymbolTable(), nullptr, nullptr))
167 return false;
168 }
169
170 if (compileOptions.emulateClipOrigin)
171 {
172 if (!EmulateClipOrigin(this, root, &getSymbolTable()))
173 {
174 return false;
175 }
176 }
177 }
178
179 if (getShaderType() == GL_FRAGMENT_SHADER)
180 {
181 EmitEarlyFragmentTestsGLSL(*this, sink);
182 }
183
184 if (getShaderType() == GL_COMPUTE_SHADER)
185 {
186 EmitWorkGroupSizeGLSL(*this, sink);
187 }
188
189 if (getShaderType() == GL_GEOMETRY_SHADER_EXT)
190 {
191 WriteGeometryShaderLayoutQualifiers(
192 sink, getGeometryShaderInputPrimitiveType(), getGeometryShaderInvocations(),
193 getGeometryShaderOutputPrimitiveType(), getGeometryShaderMaxVertices());
194 }
195
196 // Write translated shader.
197 TOutputESSL outputESSL(this, sink, compileOptions);
198
199 root->traverse(&outputESSL);
200
201 return true;
202 }
203
shouldFlattenPragmaStdglInvariantAll()204 bool TranslatorESSL::shouldFlattenPragmaStdglInvariantAll()
205 {
206 // If following the spec to the letter, we should not flatten this pragma.
207 // However, the spec's wording means that the pragma applies only to outputs.
208 // This contradicts the spirit of using the pragma,
209 // because if the pragma is used in a vertex shader,
210 // the only way to be able to link it to a fragment shader
211 // is to manually qualify each of fragment shader's inputs as invariant.
212 // Which defeats the purpose of this pragma - temporarily make all varyings
213 // invariant for debugging.
214 // Thus, we should be non-conformant to spec's letter here and flatten.
215 return true;
216 }
217
writeExtensionBehavior(const ShCompileOptions & compileOptions)218 void TranslatorESSL::writeExtensionBehavior(const ShCompileOptions &compileOptions)
219 {
220 TInfoSinkBase &sink = getInfoSink().obj;
221 const TExtensionBehavior &extBehavior = getExtensionBehavior();
222 for (TExtensionBehavior::const_iterator iter = extBehavior.begin(); iter != extBehavior.end();
223 ++iter)
224 {
225 if (iter->second != EBhUndefined)
226 {
227 const bool isMultiview = (iter->first == TExtension::OVR_multiview) ||
228 (iter->first == TExtension::OVR_multiview2);
229 if (getResources().NV_shader_framebuffer_fetch &&
230 iter->first == TExtension::EXT_shader_framebuffer_fetch)
231 {
232 sink << "#extension GL_NV_shader_framebuffer_fetch : "
233 << GetBehaviorString(iter->second) << "\n";
234 }
235 else if (getResources().NV_draw_buffers && iter->first == TExtension::EXT_draw_buffers)
236 {
237 sink << "#extension GL_NV_draw_buffers : " << GetBehaviorString(iter->second)
238 << "\n";
239 }
240 else if (isMultiview)
241 {
242 // Only either OVR_multiview OR OVR_multiview2 should be emitted.
243 if ((iter->first != TExtension::OVR_multiview) ||
244 !IsExtensionEnabled(extBehavior, TExtension::OVR_multiview2))
245 {
246 EmitMultiviewGLSL(*this, compileOptions, iter->first, iter->second, sink);
247 }
248 }
249 else if (iter->first == TExtension::EXT_geometry_shader ||
250 iter->first == TExtension::OES_geometry_shader)
251 {
252 sink << "#ifdef GL_EXT_geometry_shader\n"
253 << "#extension GL_EXT_geometry_shader : " << GetBehaviorString(iter->second)
254 << "\n"
255 << "#elif defined GL_OES_geometry_shader\n"
256 << "#extension GL_OES_geometry_shader : " << GetBehaviorString(iter->second)
257 << "\n";
258 if (iter->second == EBhRequire)
259 {
260 sink << "#else\n"
261 << "#error \"No geometry shader extensions available.\" // Only generate "
262 "this if the extension is \"required\"\n";
263 }
264 sink << "#endif\n";
265 }
266 else if (iter->first == TExtension::ANGLE_multi_draw)
267 {
268 // Don't emit anything. This extension is emulated
269 ASSERT(compileOptions.emulateGLDrawID);
270 continue;
271 }
272 else if (iter->first == TExtension::ANGLE_base_vertex_base_instance_shader_builtin)
273 {
274 // Don't emit anything. This extension is emulated
275 ASSERT(compileOptions.emulateGLBaseVertexBaseInstance);
276 continue;
277 }
278 else if (iter->first == TExtension::EXT_clip_cull_distance ||
279 iter->first == TExtension::ANGLE_clip_cull_distance)
280 {
281 sink << "#extension GL_EXT_clip_cull_distance : " << GetBehaviorString(iter->second)
282 << "\n";
283 if (areClipDistanceOrCullDistanceUsed())
284 {
285 sink << "#extension GL_EXT_shader_io_blocks : "
286 << GetBehaviorString(iter->second) << "\n";
287 }
288 }
289 else if (iter->first == TExtension::ANGLE_shader_pixel_local_storage)
290 {
291 if (compileOptions.pls.type == ShPixelLocalStorageType::PixelLocalStorageEXT)
292 {
293 // Just enable the extension. Appropriate warnings will be generated by the
294 // frontend compiler for GL_ANGLE_shader_pixel_local_storage, if desired.
295 sink << "#extension GL_EXT_shader_pixel_local_storage : enable\n";
296 }
297 else if (compileOptions.pls.type == ShPixelLocalStorageType::FramebufferFetch)
298 {
299 // Just enable the extension. Appropriate warnings will be generated by the
300 // frontend compiler for GL_ANGLE_shader_pixel_local_storage, if desired.
301 sink << "#extension GL_EXT_shader_framebuffer_fetch : enable\n";
302 }
303 continue;
304 }
305 else if (iter->first == TExtension::EXT_shader_framebuffer_fetch)
306 {
307 sink << "#extension GL_EXT_shader_framebuffer_fetch : "
308 << GetBehaviorString(iter->second) << "\n";
309 continue;
310 }
311 else if (iter->first == TExtension::EXT_shader_framebuffer_fetch_non_coherent)
312 {
313 sink << "#extension GL_EXT_shader_framebuffer_fetch_non_coherent : "
314 << GetBehaviorString(iter->second) << "\n";
315 continue;
316 }
317 else if (iter->first == TExtension::WEBGL_video_texture)
318 {
319 // Don't emit anything. This extension is emulated
320 // TODO(crbug.com/776222): support external image.
321 continue;
322 }
323 else
324 {
325 sink << "#extension " << GetExtensionNameString(iter->first) << " : "
326 << GetBehaviorString(iter->second) << "\n";
327 }
328 }
329 }
330 }
331
332 } // namespace sh
333