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