xref: /aosp_15_r20/external/angle/src/compiler/translator/glsl/TranslatorESSL.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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