1//
2// Copyright (c) 2002-2013 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/EmulatePrecision.h"
13#include "compiler/translator/tree_ops/RecordConstantPrecision.h"
14
15namespace sh
16{
17
18TranslatorESSL::TranslatorESSL(sh::GLenum type, ShShaderSpec spec)
19 : TCompiler(type, spec, SH_ESSL_OUTPUT)
20{}
21
22void TranslatorESSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu,
23 ShCompileOptions compileOptions)
24{
25 if (compileOptions & SH_EMULATE_ATAN2_FLOAT_FUNCTION)
26 {
27 InitBuiltInAtanFunctionEmulatorForGLSLWorkarounds(emu);
28 }
29}
30
31void TranslatorESSL::translate(TIntermBlock *root,
32 ShCompileOptions compileOptions,
33 PerformanceDiagnostics * /*perfDiagnostics*/)
34{
35 TInfoSinkBase &sink = getInfoSink().obj;
36
37 int shaderVer = getShaderVersion();
38 if (shaderVer > 100)
39 {
40 sink << "#version " << shaderVer << " es\n";
41 }
42
43 // Write built-in extension behaviors.
44 writeExtensionBehavior(compileOptions);
45
46 // Write pragmas after extensions because some drivers consider pragmas
47 // like non-preprocessor tokens.
48 writePragma(compileOptions);
49
50 bool precisionEmulation =
51 getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision;
52
53 if (precisionEmulation)
54 {
55 EmulatePrecision emulatePrecision(&getSymbolTable());
56 root->traverse(&emulatePrecision);
57 emulatePrecision.updateTree();
58 emulatePrecision.writeEmulationHelpers(sink, shaderVer, SH_ESSL_OUTPUT);
59 }
60
61 RecordConstantPrecision(root, &getSymbolTable());
62
63 // Write emulated built-in functions if needed.
64 if (!getBuiltInFunctionEmulator().isOutputEmpty())
65 {
66 sink << "// BEGIN: Generated code for built-in function emulation\n\n";
67 if (getShaderType() == GL_FRAGMENT_SHADER)
68 {
69 sink << "#if defined(GL_FRAGMENT_PRECISION_HIGH)\n"
70 << "#define emu_precision highp\n"
71 << "#else\n"
72 << "#define emu_precision mediump\n"
73 << "#endif\n\n";
74 }
75 else
76 {
77 sink << "#define emu_precision highp\n";
78 }
79
80 getBuiltInFunctionEmulator().outputEmulatedFunctions(sink);
81 sink << "// END: Generated code for built-in function emulation\n\n";
82 }
83
84 // Write array bounds clamping emulation if needed.
85 getArrayBoundsClamper().OutputClampingFunctionDefinition(sink);
86
87 if (getShaderType() == GL_COMPUTE_SHADER && isComputeShaderLocalSizeDeclared())
88 {
89 const sh::WorkGroupSize &localSize = getComputeShaderLocalSize();
90 sink << "layout (local_size_x=" << localSize[0] << ", local_size_y=" << localSize[1]
91 << ", local_size_z=" << localSize[2] << ") in;\n";
92 }
93
94 if (getShaderType() == GL_GEOMETRY_SHADER_EXT)
95 {
96 WriteGeometryShaderLayoutQualifiers(
97 sink, getGeometryShaderInputPrimitiveType(), getGeometryShaderInvocations(),
98 getGeometryShaderOutputPrimitiveType(), getGeometryShaderMaxVertices());
99 }
100
101 // Write translated shader.
102 TOutputESSL outputESSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(),
103 &getSymbolTable(), getShaderType(), shaderVer, precisionEmulation,
104 compileOptions);
105
106 root->traverse(&outputESSL);
107}
108
109bool 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
123void TranslatorESSL::writeExtensionBehavior(ShCompileOptions compileOptions)
124{
125 TInfoSinkBase &sink = getInfoSink().obj;
126 const TExtensionBehavior &extBehavior = getExtensionBehavior();
127 const bool isMultiviewExtEmulated =
128 (compileOptions & (SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW |
129 SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER)) != 0u;
130 for (TExtensionBehavior::const_iterator iter = extBehavior.begin(); iter != extBehavior.end();
131 ++iter)
132 {
133 if (iter->second != EBhUndefined)
134 {
135 const bool isMultiview = (iter->first == TExtension::OVR_multiview2);
136 if (getResources().NV_shader_framebuffer_fetch &&
137 iter->first == TExtension::EXT_shader_framebuffer_fetch)
138 {
139 sink << "#extension GL_NV_shader_framebuffer_fetch : "
140 << GetBehaviorString(iter->second) << "\n";
141 }
142 else if (getResources().NV_draw_buffers && iter->first == TExtension::EXT_draw_buffers)
143 {
144 sink << "#extension GL_NV_draw_buffers : " << GetBehaviorString(iter->second)
145 << "\n";
146 }
147 else if (isMultiview && isMultiviewExtEmulated)
148 {
149 if (getShaderType() == GL_VERTEX_SHADER &&
150 (compileOptions & SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER) != 0u)
151 {
152 // Emit the NV_viewport_array2 extension in a vertex shader if the
153 // SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER option is set and the
154 // OVR_multiview2 extension is requested.
155 sink << "#extension GL_NV_viewport_array2 : require\n";
156 }
157 }
158 else if (iter->first == TExtension::EXT_geometry_shader)
159 {
160 sink << "#ifdef GL_EXT_geometry_shader\n"
161 << "#extension GL_EXT_geometry_shader : " << GetBehaviorString(iter->second)
162 << "\n"
163 << "#elif defined GL_OES_geometry_shader\n"
164 << "#extension GL_OES_geometry_shader : " << GetBehaviorString(iter->second)
165 << "\n";
166 if (iter->second == EBhRequire)
167 {
168 sink << "#else\n"
169 << "#error \"No geometry shader extensions available.\" // Only generate "
170 "this if the extension is \"required\"\n";
171 }
172 sink << "#endif\n";
173 }
174 else if (iter->first == TExtension::ANGLE_multi_draw)
175 {
176 // Don't emit anything. This extension is emulated
177 ASSERT((compileOptions & SH_EMULATE_GL_DRAW_ID) != 0);
178 continue;
179 }
180 else
181 {
182 sink << "#extension " << GetExtensionNameString(iter->first) << " : "
183 << GetBehaviorString(iter->second) << "\n";
184 }
185 }
186 }
187}
188
189} // namespace sh
190