1 //
2 // Copyright (c) 2012-2013 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/Diagnostics.h"
14 
15 namespace sh
16 {
17 
getBehavior(const std::string & str)18 static TBehavior getBehavior(const std::string &str)
19 {
20     const char kRequire[] = "require";
21     const char kEnable[]  = "enable";
22     const char kDisable[] = "disable";
23     const char kWarn[]    = "warn";
24 
25     if (str == kRequire)
26         return EBhRequire;
27     else if (str == kEnable)
28         return EBhEnable;
29     else if (str == kDisable)
30         return EBhDisable;
31     else if (str == kWarn)
32         return EBhWarn;
33     return EBhUndefined;
34 }
35 
TDirectiveHandler(TExtensionBehavior & extBehavior,TDiagnostics & diagnostics,int & shaderVersion,sh::GLenum shaderType,bool debugShaderPrecisionSupported)36 TDirectiveHandler::TDirectiveHandler(TExtensionBehavior &extBehavior,
37                                      TDiagnostics &diagnostics,
38                                      int &shaderVersion,
39                                      sh::GLenum shaderType,
40                                      bool debugShaderPrecisionSupported)
41     : mExtensionBehavior(extBehavior),
42       mDiagnostics(diagnostics),
43       mShaderVersion(shaderVersion),
44       mShaderType(shaderType),
45       mDebugShaderPrecisionSupported(debugShaderPrecisionSupported)
46 {
47 }
48 
~TDirectiveHandler()49 TDirectiveHandler::~TDirectiveHandler()
50 {
51 }
52 
handleError(const pp::SourceLocation & loc,const std::string & msg)53 void TDirectiveHandler::handleError(const pp::SourceLocation &loc, const std::string &msg)
54 {
55     mDiagnostics.error(loc, msg.c_str(), "");
56 }
57 
handlePragma(const pp::SourceLocation & loc,const std::string & name,const std::string & value,bool stdgl)58 void TDirectiveHandler::handlePragma(const pp::SourceLocation &loc,
59                                      const std::string &name,
60                                      const std::string &value,
61                                      bool stdgl)
62 {
63     if (stdgl)
64     {
65         const char kInvariant[] = "invariant";
66         const char kAll[]       = "all";
67 
68         if (name == kInvariant && value == kAll)
69         {
70             if (mShaderVersion == 300 && mShaderType == GL_FRAGMENT_SHADER)
71             {
72                 // ESSL 3.00.4 section 4.6.1
73                 mDiagnostics.error(
74                     loc, "#pragma STDGL invariant(all) can not be used in fragment shader",
75                     name.c_str());
76             }
77             mPragma.stdgl.invariantAll = true;
78         }
79         // The STDGL pragma is used to reserve pragmas for use by future
80         // revisions of GLSL.  Do not generate an error on unexpected
81         // name and value.
82         return;
83     }
84     else
85     {
86         const char kOptimize[]             = "optimize";
87         const char kDebug[]                = "debug";
88         const char kDebugShaderPrecision[] = "webgl_debug_shader_precision";
89         const char kOn[]                   = "on";
90         const char kOff[]                  = "off";
91 
92         bool invalidValue = false;
93         if (name == kOptimize)
94         {
95             if (value == kOn)
96                 mPragma.optimize = true;
97             else if (value == kOff)
98                 mPragma.optimize = false;
99             else
100                 invalidValue = true;
101         }
102         else if (name == kDebug)
103         {
104             if (value == kOn)
105                 mPragma.debug = true;
106             else if (value == kOff)
107                 mPragma.debug = false;
108             else
109                 invalidValue = true;
110         }
111         else if (name == kDebugShaderPrecision && mDebugShaderPrecisionSupported)
112         {
113             if (value == kOn)
114                 mPragma.debugShaderPrecision = true;
115             else if (value == kOff)
116                 mPragma.debugShaderPrecision = false;
117             else
118                 invalidValue = true;
119         }
120         else
121         {
122             mDiagnostics.report(pp::Diagnostics::PP_UNRECOGNIZED_PRAGMA, loc, name);
123             return;
124         }
125 
126         if (invalidValue)
127         {
128             mDiagnostics.error(loc, "invalid pragma value - 'on' or 'off' expected", value.c_str());
129         }
130     }
131 }
132 
handleExtension(const pp::SourceLocation & loc,const std::string & name,const std::string & behavior)133 void TDirectiveHandler::handleExtension(const pp::SourceLocation &loc,
134                                         const std::string &name,
135                                         const std::string &behavior)
136 {
137     const char kExtAll[] = "all";
138 
139     TBehavior behaviorVal = getBehavior(behavior);
140     if (behaviorVal == EBhUndefined)
141     {
142         mDiagnostics.error(loc, "behavior invalid", name.c_str());
143         return;
144     }
145 
146     if (name == kExtAll)
147     {
148         if (behaviorVal == EBhRequire)
149         {
150             mDiagnostics.error(loc, "extension cannot have 'require' behavior", name.c_str());
151         }
152         else if (behaviorVal == EBhEnable)
153         {
154             mDiagnostics.error(loc, "extension cannot have 'enable' behavior", name.c_str());
155         }
156         else
157         {
158             for (TExtensionBehavior::iterator iter = mExtensionBehavior.begin();
159                  iter != mExtensionBehavior.end(); ++iter)
160                 iter->second = behaviorVal;
161         }
162         return;
163     }
164 
165     TExtensionBehavior::iterator iter = mExtensionBehavior.find(GetExtensionByName(name.c_str()));
166     if (iter != mExtensionBehavior.end())
167     {
168         iter->second = behaviorVal;
169         return;
170     }
171 
172     switch (behaviorVal)
173     {
174         case EBhRequire:
175             mDiagnostics.error(loc, "extension is not supported", name.c_str());
176             break;
177         case EBhEnable:
178         case EBhWarn:
179         case EBhDisable:
180             mDiagnostics.warning(loc, "extension is not supported", name.c_str());
181             break;
182         default:
183             UNREACHABLE();
184             break;
185     }
186 }
187 
handleVersion(const pp::SourceLocation & loc,int version)188 void TDirectiveHandler::handleVersion(const pp::SourceLocation &loc, int version)
189 {
190     if (version == 100 || version == 300 || version == 310)
191     {
192         mShaderVersion = version;
193     }
194     else
195     {
196         std::stringstream stream;
197         stream << version;
198         std::string str = stream.str();
199         mDiagnostics.error(loc, "version number not supported", str.c_str());
200     }
201 }
202 
203 }  // namespace sh
204