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 iter->second = behaviorVal;
147 }
148 return;
149 }
150
151 TExtensionBehavior::iterator iter = mExtensionBehavior.find(GetExtensionByName(name.c_str()));
152 if (iter != mExtensionBehavior.end())
153 {
154 iter->second = behaviorVal;
155 // OVR_multiview is implicitly enabled when OVR_multiview2 is enabled
156 if (name == "GL_OVR_multiview2")
157 {
158 constexpr char kMultiviewExtName[] = "GL_OVR_multiview";
159 iter = mExtensionBehavior.find(GetExtensionByName(kMultiviewExtName));
160 if (iter != mExtensionBehavior.end())
161 {
162 iter->second = behaviorVal;
163 }
164 }
165 // All the extensions listed in the spec here:
166 // https://www.khronos.org/registry/OpenGL/extensions/ANDROID/ANDROID_extension_pack_es31a.txt
167 // are implicitly enabled when GL_ANDROID_extension_pack_es31a is enabled
168 if (name == "GL_ANDROID_extension_pack_es31a")
169 {
170 constexpr char kGeometryShaderExtName[] = "GL_EXT_geometry_shader";
171 constexpr char kTessellationShaderExtName[] = "GL_EXT_tessellation_shader";
172 constexpr char kGpuShader5ExtName[] = "GL_EXT_gpu_shader5";
173 constexpr char kTextureBufferExtName[] = "GL_EXT_texture_buffer";
174 constexpr char kTextureCubeMapArrayExtName[] = "GL_EXT_texture_cube_map_array";
175 constexpr char kSampleVariablesExtName[] = "GL_OES_sample_variables";
176 constexpr char kShaderMultisampleInterpolationExtName[] =
177 "GL_OES_shader_multisample_interpolation";
178 constexpr char kShaderImageAtomicExtName[] = "GL_OES_shader_image_atomic";
179 constexpr char kTextureStorageMultisample2dArrayExtName[] =
180 "GL_OES_texture_storage_multisample_2d_array";
181 iter = mExtensionBehavior.find(GetExtensionByName(kGeometryShaderExtName));
182 if (iter != mExtensionBehavior.end())
183 {
184 iter->second = behaviorVal;
185 }
186
187 iter = mExtensionBehavior.find(GetExtensionByName(kTessellationShaderExtName));
188 if (iter != mExtensionBehavior.end())
189 {
190 iter->second = behaviorVal;
191 }
192
193 iter = mExtensionBehavior.find(GetExtensionByName(kGpuShader5ExtName));
194 if (iter != mExtensionBehavior.end())
195 {
196 iter->second = behaviorVal;
197 }
198
199 iter = mExtensionBehavior.find(GetExtensionByName(kTextureBufferExtName));
200 if (iter != mExtensionBehavior.end())
201 {
202 iter->second = behaviorVal;
203 }
204
205 iter = mExtensionBehavior.find(GetExtensionByName(kTextureCubeMapArrayExtName));
206 if (iter != mExtensionBehavior.end())
207 {
208 iter->second = behaviorVal;
209 }
210
211 iter = mExtensionBehavior.find(GetExtensionByName(kSampleVariablesExtName));
212 if (iter != mExtensionBehavior.end())
213 {
214 iter->second = behaviorVal;
215 }
216
217 iter =
218 mExtensionBehavior.find(GetExtensionByName(kShaderMultisampleInterpolationExtName));
219 if (iter != mExtensionBehavior.end())
220 {
221 iter->second = behaviorVal;
222 }
223
224 iter = mExtensionBehavior.find(GetExtensionByName(kShaderImageAtomicExtName));
225 if (iter != mExtensionBehavior.end())
226 {
227 iter->second = behaviorVal;
228 }
229
230 iter = mExtensionBehavior.find(
231 GetExtensionByName(kTextureStorageMultisample2dArrayExtName));
232 if (iter != mExtensionBehavior.end())
233 {
234 iter->second = behaviorVal;
235 }
236 }
237 // EXT_shader_io_blocks is implicitly enabled when EXT_geometry_shader or
238 // EXT_tessellation_shader is enabled.
239 if (name == "GL_EXT_geometry_shader" || name == "GL_EXT_tessellation_shader")
240 {
241 constexpr char kIOBlocksExtName[] = "GL_EXT_shader_io_blocks";
242 iter = mExtensionBehavior.find(GetExtensionByName(kIOBlocksExtName));
243 if (iter != mExtensionBehavior.end())
244 {
245 iter->second = behaviorVal;
246 }
247 }
248 // GL_APPLE_clip_distance is implicitly enabled when GL_EXT_clip_cull_distance is enabled
249 else if (name == "GL_EXT_clip_cull_distance")
250 {
251 // This extension only can be enabled on greater than ESSL 300
252 if (mShaderVersion < 300)
253 {
254 mDiagnostics.error(loc, "extension can be enabled on greater than ESSL 300",
255 name.c_str());
256 return;
257 }
258
259 constexpr char kAPPLEClipDistanceEXTName[] = "GL_APPLE_clip_distance";
260 iter = mExtensionBehavior.find(GetExtensionByName(kAPPLEClipDistanceEXTName));
261 if (iter != mExtensionBehavior.end())
262 {
263 iter->second = behaviorVal;
264 }
265 }
266 return;
267 }
268
269 switch (behaviorVal)
270 {
271 case EBhRequire:
272 mDiagnostics.error(loc, "extension is not supported", name.c_str());
273 break;
274 case EBhEnable:
275 case EBhWarn:
276 case EBhDisable:
277 mDiagnostics.warning(loc, "extension is not supported", name.c_str());
278 break;
279 default:
280 UNREACHABLE();
281 break;
282 }
283 }
284
handleVersion(const angle::pp::SourceLocation & loc,int version,ShShaderSpec spec)285 void TDirectiveHandler::handleVersion(const angle::pp::SourceLocation &loc,
286 int version,
287 ShShaderSpec spec)
288 {
289 if (((version == 100 || version == 300 || version == 310 || version == 320) &&
290 !IsDesktopGLSpec(spec)) ||
291 IsDesktopGLSpec(spec))
292 {
293 mShaderVersion = version;
294 }
295 else
296 {
297 std::stringstream stream = sh::InitializeStream<std::stringstream>();
298 stream << version;
299 std::string str = stream.str();
300 mDiagnostics.error(loc, "client/version number not supported", str.c_str());
301 }
302 }
303
304 } // namespace sh
305