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/Common.h"
14#include "compiler/translator/Diagnostics.h"
15
16namespace sh
17{
18
19static 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
37TDirectiveHandler::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
49TDirectiveHandler::~TDirectiveHandler() {}
50
51void TDirectiveHandler::handleError(const angle::pp::SourceLocation &loc, const std::string &msg)
52{
53 mDiagnostics.error(loc, msg.c_str(), "");
54}
55
56void 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
131void 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 return;
168 }
169
170 switch (behaviorVal)
171 {
172 case EBhRequire:
173 mDiagnostics.error(loc, "extension is not supported", name.c_str());
174 break;
175 case EBhEnable:
176 case EBhWarn:
177 case EBhDisable:
178 mDiagnostics.warning(loc, "extension is not supported", name.c_str());
179 break;
180 default:
181 UNREACHABLE();
182 break;
183 }
184}
185
186void TDirectiveHandler::handleVersion(const angle::pp::SourceLocation &loc, int version)
187{
188 if (version == 100 || version == 300 || version == 310)
189 {
190 mShaderVersion = version;
191 }
192 else
193 {
194 std::stringstream stream = sh::InitializeStream<std::stringstream>();
195 stream << version;
196 std::string str = stream.str();
197 mDiagnostics.error(loc, "version number not supported", str.c_str());
198 }
199}
200
201} // namespace sh
202