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,bool debugShaderPrecisionSupported)37 TDirectiveHandler::TDirectiveHandler(TExtensionBehavior &extBehavior,
38                                      TDiagnostics &diagnostics,
39                                      int &shaderVersion,
40                                      sh::GLenum shaderType,
41                                      bool debugShaderPrecisionSupported)
42     : mExtensionBehavior(extBehavior),
43       mDiagnostics(diagnostics),
44       mShaderVersion(shaderVersion),
45       mShaderType(shaderType),
46       mDebugShaderPrecisionSupported(debugShaderPrecisionSupported)
47 {}
48 
~TDirectiveHandler()49 TDirectiveHandler::~TDirectiveHandler() {}
50 
handleError(const angle::pp::SourceLocation & loc,const std::string & msg)51 void TDirectiveHandler::handleError(const angle::pp::SourceLocation &loc, const std::string &msg)
52 {
53     mDiagnostics.error(loc, msg.c_str(), "");
54 }
55 
handlePragma(const angle::pp::SourceLocation & loc,const std::string & name,const std::string & value,bool stdgl)56 void TDirectiveHandler::handlePragma(const angle::pp::SourceLocation &loc,
57                                      const std::string &name,
58                                      const std::string &value,
59                                      bool stdgl)
60 {
61     if (stdgl)
62     {
63         const char kInvariant[] = "invariant";
64         const char kAll[]       = "all";
65 
66         if (name == kInvariant && value == kAll)
67         {
68             if (mShaderVersion == 300 && mShaderType == GL_FRAGMENT_SHADER)
69             {
70                 // ESSL 3.00.4 section 4.6.1
71                 mDiagnostics.error(
72                     loc, "#pragma STDGL invariant(all) can not be used in fragment shader",
73                     name.c_str());
74             }
75             mPragma.stdgl.invariantAll = true;
76         }
77         // The STDGL pragma is used to reserve pragmas for use by future
78         // revisions of GLSL.  Do not generate an error on unexpected
79         // name and value.
80         return;
81     }
82     else
83     {
84         const char kOptimize[]             = "optimize";
85         const char kDebug[]                = "debug";
86         const char kDebugShaderPrecision[] = "webgl_debug_shader_precision";
87         const char kOn[]                   = "on";
88         const char kOff[]                  = "off";
89 
90         bool invalidValue = false;
91         if (name == kOptimize)
92         {
93             if (value == kOn)
94                 mPragma.optimize = true;
95             else if (value == kOff)
96                 mPragma.optimize = false;
97             else
98                 invalidValue = true;
99         }
100         else if (name == kDebug)
101         {
102             if (value == kOn)
103                 mPragma.debug = true;
104             else if (value == kOff)
105                 mPragma.debug = false;
106             else
107                 invalidValue = true;
108         }
109         else if (name == kDebugShaderPrecision && mDebugShaderPrecisionSupported)
110         {
111             if (value == kOn)
112                 mPragma.debugShaderPrecision = true;
113             else if (value == kOff)
114                 mPragma.debugShaderPrecision = false;
115             else
116                 invalidValue = true;
117         }
118         else
119         {
120             mDiagnostics.report(angle::pp::Diagnostics::PP_UNRECOGNIZED_PRAGMA, loc, name);
121             return;
122         }
123 
124         if (invalidValue)
125         {
126             mDiagnostics.error(loc, "invalid pragma value - 'on' or 'off' expected", value.c_str());
127         }
128     }
129 }
130 
handleExtension(const angle::pp::SourceLocation & loc,const std::string & name,const std::string & behavior)131 void TDirectiveHandler::handleExtension(const angle::pp::SourceLocation &loc,
132                                         const std::string &name,
133                                         const std::string &behavior)
134 {
135     const char kExtAll[] = "all";
136 
137     TBehavior behaviorVal = getBehavior(behavior);
138     if (behaviorVal == EBhUndefined)
139     {
140         mDiagnostics.error(loc, "behavior invalid", name.c_str());
141         return;
142     }
143 
144     if (name == kExtAll)
145     {
146         if (behaviorVal == EBhRequire)
147         {
148             mDiagnostics.error(loc, "extension cannot have 'require' behavior", name.c_str());
149         }
150         else if (behaviorVal == EBhEnable)
151         {
152             mDiagnostics.error(loc, "extension cannot have 'enable' behavior", name.c_str());
153         }
154         else
155         {
156             for (TExtensionBehavior::iterator iter = mExtensionBehavior.begin();
157                  iter != mExtensionBehavior.end(); ++iter)
158                 iter->second = behaviorVal;
159         }
160         return;
161     }
162 
163     TExtensionBehavior::iterator iter = mExtensionBehavior.find(GetExtensionByName(name.c_str()));
164     if (iter != mExtensionBehavior.end())
165     {
166         iter->second = behaviorVal;
167         // OVR_multiview is implicitly enabled when OVR_multiview2 is enabled
168         if (name == "GL_OVR_multiview2")
169         {
170             constexpr char kMultiviewExtName[] = "GL_OVR_multiview";
171             iter = mExtensionBehavior.find(GetExtensionByName(kMultiviewExtName));
172             if (iter != mExtensionBehavior.end())
173             {
174                 iter->second = behaviorVal;
175             }
176         }
177         // EXT_shader_io_blocks is implicitly enabled when EXT_geometry_shader or
178         // EXT_tessellation_shader is enabled.
179         if (name == "GL_EXT_geometry_shader" || name == "GL_EXT_tessellation_shader")
180         {
181             constexpr char kIOBlocksExtName[] = "GL_EXT_shader_io_blocks";
182             iter = mExtensionBehavior.find(GetExtensionByName(kIOBlocksExtName));
183             if (iter != mExtensionBehavior.end())
184             {
185                 iter->second = behaviorVal;
186             }
187         }
188         // GL_APPLE_clip_distance is implicitly enabled when GL_EXT_clip_cull_distance is enabled
189         else if (name == "GL_EXT_clip_cull_distance")
190         {
191             // This extension only can be enabled on greater than ESSL 300
192             if (mShaderVersion < 300)
193             {
194                 mDiagnostics.error(loc, "extension can be enabled on greater than ESSL 300",
195                                    name.c_str());
196                 return;
197             }
198 
199             constexpr char kAPPLEClipDistanceEXTName[] = "GL_APPLE_clip_distance";
200             iter = mExtensionBehavior.find(GetExtensionByName(kAPPLEClipDistanceEXTName));
201             if (iter != mExtensionBehavior.end())
202             {
203                 iter->second = behaviorVal;
204             }
205         }
206         return;
207     }
208 
209     switch (behaviorVal)
210     {
211         case EBhRequire:
212             mDiagnostics.error(loc, "extension is not supported", name.c_str());
213             break;
214         case EBhEnable:
215         case EBhWarn:
216         case EBhDisable:
217             mDiagnostics.warning(loc, "extension is not supported", name.c_str());
218             break;
219         default:
220             UNREACHABLE();
221             break;
222     }
223 }
224 
handleVersion(const angle::pp::SourceLocation & loc,int version,ShShaderSpec spec)225 void TDirectiveHandler::handleVersion(const angle::pp::SourceLocation &loc,
226                                       int version,
227                                       ShShaderSpec spec)
228 {
229     if (((version == 100 || version == 300 || version == 310 || version == 320) &&
230          !IsDesktopGLSpec(spec)) ||
231         IsDesktopGLSpec(spec))
232     {
233         mShaderVersion = version;
234     }
235     else
236     {
237         std::stringstream stream = sh::InitializeStream<std::stringstream>();
238         stream << version;
239         std::string str = stream.str();
240         mDiagnostics.error(loc, "client/version number not supported", str.c_str());
241     }
242 }
243 
244 }  // namespace sh
245