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