blob: fe3888590c3bd23583907694aff7439f535326ca [file] [log] [blame]
//
// Copyright 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#include "compiler/translator/DirectiveHandler.h"
#include <sstream>
#include "angle_gl.h"
#include "common/debug.h"
#include "compiler/translator/Common.h"
#include "compiler/translator/Diagnostics.h"
namespace sh
{
static TBehavior getBehavior(const std::string &str)
{
const char kRequire[] = "require";
const char kEnable[] = "enable";
const char kDisable[] = "disable";
const char kWarn[] = "warn";
if (str == kRequire)
return EBhRequire;
else if (str == kEnable)
return EBhEnable;
else if (str == kDisable)
return EBhDisable;
else if (str == kWarn)
return EBhWarn;
return EBhUndefined;
}
TDirectiveHandler::TDirectiveHandler(TExtensionBehavior &extBehavior,
TDiagnostics &diagnostics,
int &shaderVersion,
sh::GLenum shaderType,
bool debugShaderPrecisionSupported)
: mExtensionBehavior(extBehavior),
mDiagnostics(diagnostics),
mShaderVersion(shaderVersion),
mShaderType(shaderType),
mDebugShaderPrecisionSupported(debugShaderPrecisionSupported)
{}
TDirectiveHandler::~TDirectiveHandler() {}
void TDirectiveHandler::handleError(const angle::pp::SourceLocation &loc, const std::string &msg)
{
mDiagnostics.error(loc, msg.c_str(), "");
}
void TDirectiveHandler::handlePragma(const angle::pp::SourceLocation &loc,
const std::string &name,
const std::string &value,
bool stdgl)
{
if (stdgl)
{
const char kInvariant[] = "invariant";
const char kAll[] = "all";
if (name == kInvariant && value == kAll)
{
if (mShaderVersion == 300 && mShaderType == GL_FRAGMENT_SHADER)
{
// ESSL 3.00.4 section 4.6.1
mDiagnostics.error(
loc, "#pragma STDGL invariant(all) can not be used in fragment shader",
name.c_str());
}
mPragma.stdgl.invariantAll = true;
}
// The STDGL pragma is used to reserve pragmas for use by future
// revisions of GLSL. Do not generate an error on unexpected
// name and value.
return;
}
else
{
const char kOptimize[] = "optimize";
const char kDebug[] = "debug";
const char kDebugShaderPrecision[] = "webgl_debug_shader_precision";
const char kOn[] = "on";
const char kOff[] = "off";
bool invalidValue = false;
if (name == kOptimize)
{
if (value == kOn)
mPragma.optimize = true;
else if (value == kOff)
mPragma.optimize = false;
else
invalidValue = true;
}
else if (name == kDebug)
{
if (value == kOn)
mPragma.debug = true;
else if (value == kOff)
mPragma.debug = false;
else
invalidValue = true;
}
else if (name == kDebugShaderPrecision && mDebugShaderPrecisionSupported)
{
if (value == kOn)
mPragma.debugShaderPrecision = true;
else if (value == kOff)
mPragma.debugShaderPrecision = false;
else
invalidValue = true;
}
else
{
mDiagnostics.report(angle::pp::Diagnostics::PP_UNRECOGNIZED_PRAGMA, loc, name);
return;
}
if (invalidValue)
{
mDiagnostics.error(loc, "invalid pragma value - 'on' or 'off' expected", value.c_str());
}
}
}
void TDirectiveHandler::handleExtension(const angle::pp::SourceLocation &loc,
const std::string &name,
const std::string &behavior)
{
const char kExtAll[] = "all";
TBehavior behaviorVal = getBehavior(behavior);
if (behaviorVal == EBhUndefined)
{
mDiagnostics.error(loc, "behavior invalid", name.c_str());
return;
}
if (name == kExtAll)
{
if (behaviorVal == EBhRequire)
{
mDiagnostics.error(loc, "extension cannot have 'require' behavior", name.c_str());
}
else if (behaviorVal == EBhEnable)
{
mDiagnostics.error(loc, "extension cannot have 'enable' behavior", name.c_str());
}
else
{
for (TExtensionBehavior::iterator iter = mExtensionBehavior.begin();
iter != mExtensionBehavior.end(); ++iter)
iter->second = behaviorVal;
}
return;
}
TExtensionBehavior::iterator iter = mExtensionBehavior.find(GetExtensionByName(name.c_str()));
if (iter != mExtensionBehavior.end())
{
iter->second = behaviorVal;
// OVR_multiview is implicitly enabled when OVR_multiview2 is enabled
if (name == "GL_OVR_multiview2")
{
const std::string multiview = "GL_OVR_multiview";
TExtensionBehavior::iterator iterMultiview =
mExtensionBehavior.find(GetExtensionByName(multiview.c_str()));
if (iterMultiview != mExtensionBehavior.end())
{
iterMultiview->second = behaviorVal;
}
}
return;
}
switch (behaviorVal)
{
case EBhRequire:
mDiagnostics.error(loc, "extension is not supported", name.c_str());
break;
case EBhEnable:
case EBhWarn:
case EBhDisable:
mDiagnostics.warning(loc, "extension is not supported", name.c_str());
break;
default:
UNREACHABLE();
break;
}
}
void TDirectiveHandler::handleVersion(const angle::pp::SourceLocation &loc,
int version,
ShShaderSpec spec)
{
if (((version == 100 || version == 300 || version == 310) && !IsDesktopGLSpec(spec)) ||
IsDesktopGLSpec(spec))
{
mShaderVersion = version;
}
else
{
std::stringstream stream = sh::InitializeStream<std::stringstream>();
stream << version;
std::string str = stream.str();
mDiagnostics.error(loc, "client/version number not supported", str.c_str());
}
}
} // namespace sh