1 //
2 // Copyright 2012 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/DirectiveHandler.h"
8
9 #include <sstream>
10
11 #include "angle_gl.h"
12 #include "common/debug.h"
13 #include "compiler/translator/Common.h"
14 #include "compiler/translator/Diagnostics.h"
15
16 namespace sh
17 {
18
getBehavior(const std::string & str)19 static TBehavior getBehavior(const std::string &str)
20 {
21 const char kRequire[] = "require";
22 const char kEnable[] = "enable";
23 const char kDisable[] = "disable";
24 const char kWarn[] = "warn";
25
26 if (str == kRequire)
27 return EBhRequire;
28 else if (str == kEnable)
29 return EBhEnable;
30 else if (str == kDisable)
31 return EBhDisable;
32 else if (str == kWarn)
33 return EBhWarn;
34 return EBhUndefined;
35 }
36
TDirectiveHandler(TExtensionBehavior & extBehavior,TDiagnostics & diagnostics,int & shaderVersion,sh::GLenum shaderType)37 TDirectiveHandler::TDirectiveHandler(TExtensionBehavior &extBehavior,
38 TDiagnostics &diagnostics,
39 int &shaderVersion,
40 sh::GLenum shaderType)
41 : mExtensionBehavior(extBehavior),
42 mDiagnostics(diagnostics),
43 mShaderVersion(shaderVersion),
44 mShaderType(shaderType)
45 {}
46
~TDirectiveHandler()47 TDirectiveHandler::~TDirectiveHandler() {}
48
handleError(const angle::pp::SourceLocation & loc,const std::string & msg)49 void TDirectiveHandler::handleError(const angle::pp::SourceLocation &loc, const std::string &msg)
50 {
51 mDiagnostics.error(loc, msg.c_str(), "");
52 }
53
handlePragma(const angle::pp::SourceLocation & loc,const std::string & name,const std::string & value,bool stdgl)54 void TDirectiveHandler::handlePragma(const angle::pp::SourceLocation &loc,
55 const std::string &name,
56 const std::string &value,
57 bool stdgl)
58 {
59 if (stdgl)
60 {
61 const char kInvariant[] = "invariant";
62 const char kAll[] = "all";
63
64 if (name == kInvariant && value == kAll)
65 {
66 if (mShaderVersion == 300 && mShaderType == GL_FRAGMENT_SHADER)
67 {
68 // ESSL 3.00.4 section 4.6.1
69 mDiagnostics.error(
70 loc, "#pragma STDGL invariant(all) can not be used in fragment shader",
71 name.c_str());
72 }
73 mPragma.stdgl.invariantAll = true;
74 }
75 // The STDGL pragma is used to reserve pragmas for use by future
76 // revisions of GLSL. Do not generate an error on unexpected
77 // name and value.
78 return;
79 }
80 else
81 {
82 const char kOptimize[] = "optimize";
83 const char kDebug[] = "debug";
84 const char kOn[] = "on";
85 const char kOff[] = "off";
86
87 bool invalidValue = false;
88 if (name == kOptimize)
89 {
90 if (value == kOn)
91 mPragma.optimize = true;
92 else if (value == kOff)
93 mPragma.optimize = false;
94 else
95 invalidValue = true;
96 }
97 else if (name == kDebug)
98 {
99 if (value == kOn)
100 mPragma.debug = true;
101 else if (value == kOff)
102 mPragma.debug = false;
103 else
104 invalidValue = true;
105 }
106 else
107 {
108 mDiagnostics.report(angle::pp::Diagnostics::PP_UNRECOGNIZED_PRAGMA, loc, name);
109 return;
110 }
111
112 if (invalidValue)
113 {
114 mDiagnostics.error(loc, "invalid pragma value - 'on' or 'off' expected", value.c_str());
115 }
116 }
117 }
118
handleExtension(const angle::pp::SourceLocation & loc,const std::string & name,const std::string & behavior)119 void TDirectiveHandler::handleExtension(const angle::pp::SourceLocation &loc,
120 const std::string &name,
121 const std::string &behavior)
122 {
123 const char kExtAll[] = "all";
124
125 TBehavior behaviorVal = getBehavior(behavior);
126 if (behaviorVal == EBhUndefined)
127 {
128 mDiagnostics.error(loc, "behavior invalid", name.c_str());
129 return;
130 }
131
132 if (name == kExtAll)
133 {
134 if (behaviorVal == EBhRequire)
135 {
136 mDiagnostics.error(loc, "extension cannot have 'require' behavior", name.c_str());
137 }
138 else if (behaviorVal == EBhEnable)
139 {
140 mDiagnostics.error(loc, "extension cannot have 'enable' behavior", name.c_str());
141 }
142 else
143 {
144 for (TExtensionBehavior::iterator iter = mExtensionBehavior.begin();
145 iter != mExtensionBehavior.end(); ++iter)
146 {
147 iter->second = behaviorVal;
148 }
149 }
150 return;
151 }
152
153 TExtensionBehavior::iterator iter = mExtensionBehavior.find(GetExtensionByName(name.c_str()));
154 if (iter != mExtensionBehavior.end() && CheckExtensionVersion(iter->first, mShaderVersion))
155 {
156 iter->second = behaviorVal;
157 // OVR_multiview is implicitly enabled when OVR_multiview2 is enabled
158 if (name == "GL_OVR_multiview2")
159 {
160 constexpr char kMultiviewExtName[] = "GL_OVR_multiview";
161 iter = mExtensionBehavior.find(GetExtensionByName(kMultiviewExtName));
162 if (iter != mExtensionBehavior.end())
163 {
164 iter->second = behaviorVal;
165 }
166 }
167 // All the extensions listed in the spec here:
168 // https://www.khronos.org/registry/OpenGL/extensions/ANDROID/ANDROID_extension_pack_es31a.txt
169 // are implicitly enabled when GL_ANDROID_extension_pack_es31a is enabled
170 if (name == "GL_ANDROID_extension_pack_es31a")
171 {
172 constexpr char kGeometryShaderExtName[] = "GL_EXT_geometry_shader";
173 constexpr char kTessellationShaderExtName[] = "GL_EXT_tessellation_shader";
174 constexpr char kGpuShader5ExtName[] = "GL_EXT_gpu_shader5";
175 constexpr char kTextureBufferExtName[] = "GL_EXT_texture_buffer";
176 constexpr char kTextureCubeMapArrayExtName[] = "GL_EXT_texture_cube_map_array";
177 constexpr char kSampleVariablesExtName[] = "GL_OES_sample_variables";
178 constexpr char kShaderMultisampleInterpolationExtName[] =
179 "GL_OES_shader_multisample_interpolation";
180 constexpr char kShaderImageAtomicExtName[] = "GL_OES_shader_image_atomic";
181 constexpr char kTextureStorageMultisample2dArrayExtName[] =
182 "GL_OES_texture_storage_multisample_2d_array";
183 iter = mExtensionBehavior.find(GetExtensionByName(kGeometryShaderExtName));
184 if (iter != mExtensionBehavior.end())
185 {
186 iter->second = behaviorVal;
187 }
188
189 iter = mExtensionBehavior.find(GetExtensionByName(kTessellationShaderExtName));
190 if (iter != mExtensionBehavior.end())
191 {
192 iter->second = behaviorVal;
193 }
194
195 iter = mExtensionBehavior.find(GetExtensionByName(kGpuShader5ExtName));
196 if (iter != mExtensionBehavior.end())
197 {
198 iter->second = behaviorVal;
199 }
200
201 iter = mExtensionBehavior.find(GetExtensionByName(kTextureBufferExtName));
202 if (iter != mExtensionBehavior.end())
203 {
204 iter->second = behaviorVal;
205 }
206
207 iter = mExtensionBehavior.find(GetExtensionByName(kTextureCubeMapArrayExtName));
208 if (iter != mExtensionBehavior.end())
209 {
210 iter->second = behaviorVal;
211 }
212
213 iter = mExtensionBehavior.find(GetExtensionByName(kSampleVariablesExtName));
214 if (iter != mExtensionBehavior.end())
215 {
216 iter->second = behaviorVal;
217 }
218
219 iter =
220 mExtensionBehavior.find(GetExtensionByName(kShaderMultisampleInterpolationExtName));
221 if (iter != mExtensionBehavior.end())
222 {
223 iter->second = behaviorVal;
224 }
225
226 iter = mExtensionBehavior.find(GetExtensionByName(kShaderImageAtomicExtName));
227 if (iter != mExtensionBehavior.end())
228 {
229 iter->second = behaviorVal;
230 }
231
232 iter = mExtensionBehavior.find(
233 GetExtensionByName(kTextureStorageMultisample2dArrayExtName));
234 if (iter != mExtensionBehavior.end())
235 {
236 iter->second = behaviorVal;
237 }
238 }
239 // EXT_shader_io_blocks is implicitly enabled when EXT_geometry_shader or
240 // EXT_tessellation_shader is enabled.
241 if (name == "GL_EXT_geometry_shader" || name == "GL_EXT_tessellation_shader")
242 {
243 constexpr char kIOBlocksExtName[] = "GL_EXT_shader_io_blocks";
244 iter = mExtensionBehavior.find(GetExtensionByName(kIOBlocksExtName));
245 if (iter != mExtensionBehavior.end())
246 {
247 iter->second = behaviorVal;
248 }
249 }
250 // GL_APPLE_clip_distance is implicitly enabled when GL_EXT_clip_cull_distance or
251 // GL_ANGLE_clip_cull_distance are enabled.
252 else if (name == "GL_EXT_clip_cull_distance" || name == "GL_ANGLE_clip_cull_distance")
253 {
254 constexpr char kAPPLEClipDistanceEXTName[] = "GL_APPLE_clip_distance";
255 iter = mExtensionBehavior.find(GetExtensionByName(kAPPLEClipDistanceEXTName));
256 if (iter != mExtensionBehavior.end())
257 {
258 iter->second = behaviorVal;
259 }
260 }
261 return;
262 }
263
264 switch (behaviorVal)
265 {
266 case EBhRequire:
267 mDiagnostics.error(loc, "extension is not supported", name.c_str());
268 break;
269 case EBhEnable:
270 case EBhWarn:
271 case EBhDisable:
272 mDiagnostics.warning(loc, "extension is not supported", name.c_str());
273 break;
274 default:
275 UNREACHABLE();
276 break;
277 }
278 }
279
handleVersion(const angle::pp::SourceLocation & loc,int version,ShShaderSpec spec,angle::pp::MacroSet * macro_set)280 void TDirectiveHandler::handleVersion(const angle::pp::SourceLocation &loc,
281 int version,
282 ShShaderSpec spec,
283 angle::pp::MacroSet *macro_set)
284 {
285 if (((version == 100 || version == 300 || version == 310 || version == 320) &&
286 !IsDesktopGLSpec(spec)) ||
287 IsDesktopGLSpec(spec))
288 {
289 mShaderVersion = version;
290
291 // Add macros for supported extensions
292 for (const auto &iter : mExtensionBehavior)
293 {
294 if (CheckExtensionVersion(iter.first, version))
295 {
296 // OVR_multiview should not be defined for WebGL spec'ed shaders.
297 if (IsWebGLBasedSpec(spec) && (iter.first == TExtension::OVR_multiview))
298 {
299 continue;
300 }
301 PredefineMacro(macro_set, GetExtensionNameString(iter.first), 1);
302 }
303 }
304 }
305 else
306 {
307 std::stringstream stream = sh::InitializeStream<std::stringstream>();
308 stream << version;
309 std::string str = stream.str();
310 mDiagnostics.error(loc, "client/version number not supported", str.c_str());
311 }
312 }
313
314 } // namespace sh
315