• 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                 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