• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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