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