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