• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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