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/TranslatorESSL.h"
8
9 #include "angle_gl.h"
10 #include "compiler/translator/BuiltInFunctionEmulatorGLSL.h"
11 #include "compiler/translator/OutputESSL.h"
12 #include "compiler/translator/tree_ops/RecordConstantPrecision.h"
13
14 namespace sh
15 {
16
TranslatorESSL(sh::GLenum type,ShShaderSpec spec)17 TranslatorESSL::TranslatorESSL(sh::GLenum type, ShShaderSpec spec)
18 : TCompiler(type, spec, SH_ESSL_OUTPUT)
19 {}
20
initBuiltInFunctionEmulator(BuiltInFunctionEmulator * emu,ShCompileOptions compileOptions)21 void TranslatorESSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu,
22 ShCompileOptions compileOptions)
23 {
24 if (compileOptions & SH_EMULATE_ATAN2_FLOAT_FUNCTION)
25 {
26 InitBuiltInAtanFunctionEmulatorForGLSLWorkarounds(emu);
27 }
28 }
29
translate(TIntermBlock * root,ShCompileOptions compileOptions,PerformanceDiagnostics *)30 bool TranslatorESSL::translate(TIntermBlock *root,
31 ShCompileOptions compileOptions,
32 PerformanceDiagnostics * /*perfDiagnostics*/)
33 {
34 TInfoSinkBase &sink = getInfoSink().obj;
35
36 int shaderVer = getShaderVersion();
37 if (shaderVer > 100)
38 {
39 sink << "#version " << shaderVer << " es\n";
40 }
41
42 // Write built-in extension behaviors.
43 writeExtensionBehavior(compileOptions);
44
45 // Write pragmas after extensions because some drivers consider pragmas
46 // like non-preprocessor tokens.
47 writePragma(compileOptions);
48
49 bool precisionEmulation = false;
50 if (!emulatePrecisionIfNeeded(root, sink, &precisionEmulation, SH_ESSL_OUTPUT))
51 return false;
52
53 if (!RecordConstantPrecision(this, root, &getSymbolTable()))
54 {
55 return false;
56 }
57
58 // Write emulated built-in functions if needed.
59 if (!getBuiltInFunctionEmulator().isOutputEmpty())
60 {
61 sink << "// BEGIN: Generated code for built-in function emulation\n\n";
62 if (getShaderType() == GL_FRAGMENT_SHADER)
63 {
64 sink << "#if defined(GL_FRAGMENT_PRECISION_HIGH)\n"
65 << "#define emu_precision highp\n"
66 << "#else\n"
67 << "#define emu_precision mediump\n"
68 << "#endif\n\n";
69 }
70 else
71 {
72 sink << "#define emu_precision highp\n";
73 }
74
75 getBuiltInFunctionEmulator().outputEmulatedFunctions(sink);
76 sink << "// END: Generated code for built-in function emulation\n\n";
77 }
78
79 // Write array bounds clamping emulation if needed.
80 getArrayBoundsClamper().OutputClampingFunctionDefinition(sink);
81
82 if (getShaderType() == GL_FRAGMENT_SHADER)
83 {
84 EmitEarlyFragmentTestsGLSL(*this, sink);
85 }
86
87 if (getShaderType() == GL_COMPUTE_SHADER)
88 {
89 EmitWorkGroupSizeGLSL(*this, sink);
90 }
91
92 if (getShaderType() == GL_GEOMETRY_SHADER_EXT)
93 {
94 WriteGeometryShaderLayoutQualifiers(
95 sink, getGeometryShaderInputPrimitiveType(), getGeometryShaderInvocations(),
96 getGeometryShaderOutputPrimitiveType(), getGeometryShaderMaxVertices());
97 }
98
99 // Write translated shader.
100 TOutputESSL outputESSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(),
101 &getSymbolTable(), getShaderType(), shaderVer, precisionEmulation,
102 compileOptions);
103
104 root->traverse(&outputESSL);
105
106 return true;
107 }
108
shouldFlattenPragmaStdglInvariantAll()109 bool TranslatorESSL::shouldFlattenPragmaStdglInvariantAll()
110 {
111 // If following the spec to the letter, we should not flatten this pragma.
112 // However, the spec's wording means that the pragma applies only to outputs.
113 // This contradicts the spirit of using the pragma,
114 // because if the pragma is used in a vertex shader,
115 // the only way to be able to link it to a fragment shader
116 // is to manually qualify each of fragment shader's inputs as invariant.
117 // Which defeats the purpose of this pragma - temporarily make all varyings
118 // invariant for debugging.
119 // Thus, we should be non-conformant to spec's letter here and flatten.
120 return true;
121 }
122
writeExtensionBehavior(ShCompileOptions compileOptions)123 void TranslatorESSL::writeExtensionBehavior(ShCompileOptions compileOptions)
124 {
125 TInfoSinkBase &sink = getInfoSink().obj;
126 const TExtensionBehavior &extBehavior = getExtensionBehavior();
127 for (TExtensionBehavior::const_iterator iter = extBehavior.begin(); iter != extBehavior.end();
128 ++iter)
129 {
130 if (iter->second != EBhUndefined)
131 {
132 const bool isMultiview = (iter->first == TExtension::OVR_multiview) ||
133 (iter->first == TExtension::OVR_multiview2);
134 if (getResources().NV_shader_framebuffer_fetch &&
135 iter->first == TExtension::EXT_shader_framebuffer_fetch)
136 {
137 sink << "#extension GL_NV_shader_framebuffer_fetch : "
138 << GetBehaviorString(iter->second) << "\n";
139 }
140 else if (getResources().NV_draw_buffers && iter->first == TExtension::EXT_draw_buffers)
141 {
142 sink << "#extension GL_NV_draw_buffers : " << GetBehaviorString(iter->second)
143 << "\n";
144 }
145 else if (isMultiview)
146 {
147 // Only either OVR_multiview OR OVR_multiview2 should be emitted.
148 if ((iter->first != TExtension::OVR_multiview) ||
149 !IsExtensionEnabled(extBehavior, TExtension::OVR_multiview2))
150 {
151 EmitMultiviewGLSL(*this, compileOptions, iter->first, iter->second, sink);
152 }
153 }
154 else if (iter->first == TExtension::EXT_geometry_shader)
155 {
156 sink << "#ifdef GL_EXT_geometry_shader\n"
157 << "#extension GL_EXT_geometry_shader : " << GetBehaviorString(iter->second)
158 << "\n"
159 << "#elif defined GL_OES_geometry_shader\n"
160 << "#extension GL_OES_geometry_shader : " << GetBehaviorString(iter->second)
161 << "\n";
162 if (iter->second == EBhRequire)
163 {
164 sink << "#else\n"
165 << "#error \"No geometry shader extensions available.\" // Only generate "
166 "this if the extension is \"required\"\n";
167 }
168 sink << "#endif\n";
169 }
170 else if (iter->first == TExtension::ANGLE_multi_draw)
171 {
172 // Don't emit anything. This extension is emulated
173 ASSERT((compileOptions & SH_EMULATE_GL_DRAW_ID) != 0);
174 continue;
175 }
176 else if (iter->first == TExtension::ANGLE_base_vertex_base_instance)
177 {
178 // Don't emit anything. This extension is emulated
179 ASSERT((compileOptions & SH_EMULATE_GL_BASE_VERTEX_BASE_INSTANCE) != 0);
180 continue;
181 }
182 else if (iter->first == TExtension::WEBGL_video_texture)
183 {
184 // Don't emit anything. This extension is emulated
185 // TODO(crbug.com/776222): support external image.
186 continue;
187 }
188 else
189 {
190 sink << "#extension " << GetExtensionNameString(iter->first) << " : "
191 << GetBehaviorString(iter->second) << "\n";
192 }
193 }
194 }
195 }
196
197 } // namespace sh
198