Document how to add a new feature enabled by an extension in Versions.cpp. Also reorganized slightly to localize related functions.

git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@23376 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
John Kessenich 2013-10-03 20:23:57 +00:00
parent a5830dfc0e
commit 61c2d1410a
12 changed files with 336 additions and 197 deletions

View file

@ -584,7 +584,7 @@ void TBuiltIns::initialize(int version, EProfile profile)
s.append("\n");
//
// Original-style texture Functions existing in both stages.
// Original-style texture functions existing in both stages.
// (Per-stage functions below.)
//
if (profile == EEsProfile && version == 100 ||

View file

@ -1098,7 +1098,7 @@ void TIntermediate::checkCallGraphCycles(TInfoSink& infoSink)
void TIntermediate::error(TInfoSink& infoSink, const char* message)
{
infoSink.info.prefix(EPrefixError);
infoSink.info << "Linking " << StageName[language] << " stage: " << message << "\n";
infoSink.info << "Linking " << StageName(language) << " stage: " << message << "\n";
++numErrors;
}

View file

@ -249,59 +249,6 @@ void TParseContext::handlePragma(const char **tokens, int numTokens)
}
}
TBehavior TParseContext::getExtensionBehavior(const char* behavior)
{
if (!strcmp("require", behavior))
return EBhRequire;
else if (!strcmp("enable", behavior))
return EBhEnable;
else if (!strcmp("disable", behavior))
return EBhDisable;
else if (!strcmp("warn", behavior))
return EBhWarn;
else {
error(currentLoc, "behavior not supported", "#extension", behavior);
return EBhDisable;
}
}
void TParseContext::updateExtensionBehavior(const char* extName, const char* behavior)
{
TBehavior behaviorVal = getExtensionBehavior(behavior);
TMap<TString, TBehavior>:: iterator iter;
TString msg;
// special cased for all extension
if (!strcmp(extName, "all")) {
if (behaviorVal == EBhRequire || behaviorVal == EBhEnable) {
error(currentLoc, "extension 'all' cannot have 'require' or 'enable' behavior", "#extension", "");
return;
} else {
for (iter = extensionBehavior.begin(); iter != extensionBehavior.end(); ++iter)
iter->second = behaviorVal;
}
} else {
iter = extensionBehavior.find(TString(extName));
if (iter == extensionBehavior.end()) {
switch (behaviorVal) {
case EBhRequire:
error(currentLoc, "extension not supported", "#extension", extName);
break;
case EBhEnable:
case EBhWarn:
case EBhDisable:
warn(currentLoc, "extension not supported", "#extension", extName);
break;
default:
assert(0 && "unexpected behaviorVal");
}
return;
} else
iter->second = behaviorVal;
}
}
///////////////////////////////////////////////////////////////////////
//
// Sub- vector and matrix fields
@ -538,12 +485,11 @@ TIntermTyped* TParseContext::handleBracketDereference(TSourceLoc loc, TIntermTyp
if (base->isArray() && base->getType().getArraySize() == 0)
error(loc, "", "[", "array must be redeclared with a size before being indexed with a variable");
if (base->getBasicType() == EbtBlock)
requireProfile(base->getLoc(), static_cast<EProfileMask>(~EEsProfileMask), "variable indexing block array");
requireProfile(base->getLoc(), ~EEsProfile, "variable indexing block array");
if (base->getBasicType() == EbtSampler && version >= 130) {
const char* explanation = "variable indexing sampler array";
requireProfile(base->getLoc(), static_cast<EProfileMask>(ECoreProfileMask | ECompatibilityProfileMask), explanation);
profileRequires(base->getLoc(), ECoreProfile, 400, 0, explanation);
profileRequires(base->getLoc(), ECompatibilityProfile, 400, 0, explanation);
requireProfile(base->getLoc(), ECoreProfile | ECompatibilityProfile, explanation);
profileRequires(base->getLoc(), ECoreProfile | ECompatibilityProfile, 400, 0, explanation);
}
result = intermediate.addIndex(EOpIndexIndirect, base, index, loc);
@ -662,7 +608,7 @@ TFunction* TParseContext::handleFunctionDeclarator(TSourceLoc loc, TFunction& fu
{
// ES can't declare prototypes inside functions
if (! symbolTable.atGlobalLevel())
requireProfile(loc, static_cast<EProfileMask>(~EEsProfileMask), "local function declaration");
requireProfile(loc, ~EEsProfile, "local function declaration");
//
// Multiple declarations of the same function are allowed.
@ -1479,7 +1425,7 @@ void TParseContext::globalQualifierFix(TSourceLoc loc, TQualifier& qualifier, co
return;
}
if (publicType.arraySizes) {
requireProfile(loc, (EProfileMask)~EEsProfileMask, "vertex input arrays");
requireProfile(loc, ~EEsProfile, "vertex input arrays");
profileRequires(loc, ENoProfile, 150, 0, "vertex input arrays");
}
}
@ -1706,7 +1652,7 @@ bool TParseContext::arrayQualifierError(TSourceLoc loc, const TQualifier& qualif
profileRequires(loc, ENoProfile, 120, "GL_3DL_array_objects", "const array");
if (qualifier.storage == EvqVaryingIn && language == EShLangVertex) {
requireProfile(loc, (EProfileMask)~EEsProfileMask, "vertex input arrays");
requireProfile(loc, ~EEsProfile, "vertex input arrays");
profileRequires(loc, ENoProfile, 150, 0, "vertex input arrays");
}
@ -1726,9 +1672,8 @@ void TParseContext::arraySizeRequiredCheck(TSourceLoc loc, int size)
void TParseContext::arrayDimError(TSourceLoc loc)
{
requireProfile(loc, (EProfileMask)(ECoreProfileMask | ECompatibilityProfileMask), "arrays of arrays");
profileRequires(loc, ECoreProfile, 430, 0, "arrays of arrays");
profileRequires(loc, ECompatibilityProfile, 430, 0, "arrays of arrays");
requireProfile(loc, ECoreProfile | ECompatibilityProfile, "arrays of arrays");
profileRequires(loc, ECoreProfile | ECompatibilityProfile, 430, 0, "arrays of arrays");
}
void TParseContext::arrayDimCheck(TSourceLoc loc, TArraySizes* sizes1, TArraySizes* sizes2)
@ -2387,7 +2332,7 @@ void TParseContext::addBlock(TSourceLoc loc, TTypeList& typeList, const TString*
arraySizeRequiredCheck(loc, arraySizes->getSize());
if (currentBlockDefaults.storage == EvqUniform) {
requireProfile(loc, (EProfileMask)(~ENoProfileMask), "uniform block");
requireProfile(loc, ~ENoProfile, "uniform block");
profileRequires(loc, EEsProfile, 300, 0, "uniform block");
} else {
error(loc, "only uniform interface blocks are supported", blockName->c_str(), "");
@ -2788,17 +2733,4 @@ TIntermTyped* TParseContext::addConstStruct(TString& identifier, TIntermTyped* n
return typedNode;
}
//
// Initialize all supported extensions to disable
//
void TParseContext::initializeExtensionBehavior()
{
//
// example code: extensionBehavior["test"] = EBhDisable; // where "test" is the name of
// supported extension
//
extensionBehavior["GL_ARB_texture_rectangle"] = EBhDisable;
extensionBehavior["GL_3DL_array_objects"] = EBhDisable;
}
} // end namespace glslang

View file

@ -43,13 +43,6 @@
namespace glslang {
typedef enum {
EBhRequire,
EBhEnable,
EBhWarn,
EBhDisable
} TBehavior;
struct TPragma {
TPragma(bool o, bool d) : optimize(o), debug(d) { }
bool optimize;
@ -71,7 +64,6 @@ public:
public:
bool parseShaderStrings(TPpContext&, char* strings[], int strLen[], int numStrings);
void initializeExtensionBehavior();
void parserError(const char *s); // for bison's yyerror
void C_DECL error(TSourceLoc, const char *szReason, const char *szToken,
@ -148,15 +140,6 @@ public:
bool arraySetMaxSize(TSourceLoc, TIntermSymbol*, int);
void requireProfile(TSourceLoc, EProfileMask profileMask, const char *featureDesc);
void requireStage(TSourceLoc, EShLanguageMask languageMask, const char *featureDesc);
void profileRequires(TSourceLoc, EProfile callingProfile, int minVersion, int numExtensions, const char* extensions[], const char *featureDesc);
void profileRequires(TSourceLoc, EProfile callingProfile, int minVersion, const char* extension, const char *featureDesc);
void checkDeprecated(TSourceLoc, EProfile callingProfile, int depVersion, const char *featureDesc);
void requireNotRemoved(TSourceLoc, EProfile callingProfile, int removedVersion, const char *featureDesc);
void fullIntegerCheck(TSourceLoc, const char* op);
void doubleCheck(TSourceLoc, const char* op);
void setScanContext(TScanContext* c) { scanContext = c; }
TScanContext* getScanContext() const { return scanContext; }
void setPpContext(TPpContext* c) { ppContext = c; }
@ -164,9 +147,21 @@ public:
void addError() { ++numErrors; }
int getNumErrors() const { return numErrors; }
// The following are implemented in Versions.cpp to localize version/profile/stage/extensions control
void initializeExtensionBehavior();
void requireProfile(TSourceLoc, int queryProfiles, const char *featureDesc);
void profileRequires(TSourceLoc, int queryProfiles, int minVersion, int numExtensions, const char* extensions[], const char *featureDesc);
void profileRequires(TSourceLoc, int queryProfiles, int minVersion, const char* extension, const char *featureDesc);
void requireStage(TSourceLoc, EShLanguageMask, const char *featureDesc);
void requireStage(TSourceLoc, EShLanguage, const char *featureDesc);
void checkDeprecated(TSourceLoc, int queryProfiles, int depVersion, const char *featureDesc);
void requireNotRemoved(TSourceLoc, int queryProfiles, int removedVersion, const char *featureDesc);
void fullIntegerCheck(TSourceLoc, const char* op);
void doubleCheck(TSourceLoc, const char* op);
protected:
const char* getPreamble();
TBehavior getExtensionBehavior(const char* behavior);
TExtensionBehavior getExtensionBehavior(const char* behavior);
void nonInitConstCheck(TSourceLoc, TString& identifier, TType& type);
TVariable* declareNonArray(TSourceLoc, TString& identifier, TType&, bool& newDeclaration);
void declareArray(TSourceLoc, TString& identifier, const TType&, TVariable*&, bool& newDeclaration);
@ -208,7 +203,7 @@ protected:
TPpContext* ppContext;
int numErrors; // number of compile-time errors encountered
bool parsingBuiltins; // true if parsing built-in symbols/functions
TMap<TString, TBehavior> extensionBehavior; // for each extension string, what it's current enablement is
TMap<TString, TExtensionBehavior> extensionBehavior; // for each extension string, what it's current behavior is set to
static const int maxSamplerIndex = EsdNumDims * (EbtNumTypes * (2 * 2)); // see computeSamplerTypeIndex()
TPrecisionQualifier defaultSamplerPrecision[maxSamplerIndex];
bool afterEOF;

View file

@ -59,9 +59,11 @@ namespace { // anonymous namespace for file-local functions and symbols
using namespace glslang;
// Local mapping functions for making arrays of symbol tables....
int MapVersionToIndex(int version)
{
switch(version) {
switch (version) {
case 100: return 0;
case 110: return 1;
case 120: return 2;
@ -81,6 +83,19 @@ int MapVersionToIndex(int version)
} // V
const int VersionCount = 13; // number of case statements above
int MapProfileToIndex(EProfile profile)
{
switch (profile) {
case ENoProfile: return 0;
case ECoreProfile: return 1;
case ECompatibilityProfile: return 2;
case EEsProfile: return 3;
default: // |
return 0; // |
} // |
} // V
const int ProfileCount = 4; // number of case statements above
// only one of these needed for non-ES; ES needs 2 for different precision defaults of built-ins
enum EPrecisionClass {
EPcGeneral,
@ -96,8 +111,8 @@ enum EPrecisionClass {
// Each has a different set of built-ins, and we want to preserve that from
// compile to compile.
//
TSymbolTable* CommonSymbolTable[VersionCount][EProfileCount][EPcCount] = {};
TSymbolTable* SharedSymbolTables[VersionCount][EProfileCount][EShLangCount] = {};
TSymbolTable* CommonSymbolTable[VersionCount][ProfileCount][EPcCount] = {};
TSymbolTable* SharedSymbolTables[VersionCount][ProfileCount][EShLangCount] = {};
TPoolAllocator* PerProcessGPA = 0;
@ -216,7 +231,8 @@ void SetupBuiltinSymbolTable(int version, EProfile profile)
// See if it's already been done for this version/profile combination
int versionIndex = MapVersionToIndex(version);
if (CommonSymbolTable[versionIndex][profile][EPcGeneral]) {
int profileIndex = MapProfileToIndex(profile);
if (CommonSymbolTable[versionIndex][profileIndex][EPcGeneral]) {
glslang::ReleaseGlobalLock();
return;
@ -244,17 +260,17 @@ void SetupBuiltinSymbolTable(int version, EProfile profile)
// Copy the local symbol tables from the new pool to the global tables using the process-global pool
for (int precClass = 0; precClass < EPcCount; ++precClass) {
if (! commonTable[precClass]->isEmpty()) {
CommonSymbolTable[versionIndex][profile][precClass] = new TSymbolTable;
CommonSymbolTable[versionIndex][profile][precClass]->copyTable(*commonTable[precClass]);
CommonSymbolTable[versionIndex][profile][precClass]->readOnly();
CommonSymbolTable[versionIndex][profileIndex][precClass] = new TSymbolTable;
CommonSymbolTable[versionIndex][profileIndex][precClass]->copyTable(*commonTable[precClass]);
CommonSymbolTable[versionIndex][profileIndex][precClass]->readOnly();
}
}
for (int stage = 0; stage < EShLangCount; ++stage) {
if (! stageTables[stage]->isEmpty()) {
SharedSymbolTables[versionIndex][profile][stage] = new TSymbolTable;
SharedSymbolTables[versionIndex][profile][stage]->adoptLevels(*CommonSymbolTable[versionIndex][profile][CommonIndex(profile, (EShLanguage)stage)]);
SharedSymbolTables[versionIndex][profile][stage]->copyTable(*stageTables[stage]);
SharedSymbolTables[versionIndex][profile][stage]->readOnly();
SharedSymbolTables[versionIndex][profileIndex][stage] = new TSymbolTable;
SharedSymbolTables[versionIndex][profileIndex][stage]->adoptLevels(*CommonSymbolTable[versionIndex][profileIndex][CommonIndex(profile, (EShLanguage)stage)]);
SharedSymbolTables[versionIndex][profileIndex][stage]->copyTable(*stageTables[stage]);
SharedSymbolTables[versionIndex][profileIndex][stage]->readOnly();
}
}
@ -433,7 +449,7 @@ bool CompileDeferred(
SetupBuiltinSymbolTable(version, profile);
TSymbolTable* cachedTable = SharedSymbolTables[MapVersionToIndex(version)]
[profile]
[MapProfileToIndex(profile)]
[compiler->getLanguage()];
// Dynamically allocate the symbol table so we can control when it is deallocated WRT the pool.
@ -569,7 +585,7 @@ void ShDestruct(ShHandle handle)
int __fastcall ShFinalize()
{
for (int version = 0; version < VersionCount; ++version)
for (int p = 0; p < EProfileCount; ++p)
for (int p = 0; p < ProfileCount; ++p)
for (int lang = 0; lang < EShLangCount; ++lang)
delete SharedSymbolTables[version][p][lang];
@ -964,7 +980,7 @@ bool TProgram::linkStage(EShLanguage stage, EShMessages messages)
merged = intermediate[stage];
}
infoSink->info << "\nLinked " << StageName[stage] << " stage:\n\n";
infoSink->info << "\nLinked " << StageName(stage) << " stage:\n\n";
if (stages[stage].size() > 1) {
std::list<TShader*>::const_iterator it;

View file

@ -37,68 +37,166 @@
//
// Help manage multiple profiles, versions, extensions etc.
//
// These don't return error codes, as the presumption is parsing
// will always continue as if the feature were present, and there
// is no error recovery needed to enable that.
// These don't return error codes, as the presumption is parsing will
// always continue as if the tested feature were enabled, and thus there
// is no error recovery needed.
//
//
// HOW TO add a feature enabled by an extension.
//
// To add a new hypothetical "Feature F" to the front end, where an extension
// "XXX_extension_X" can be used to enable the feature, do the following.
//
// 1) Understand that specific features are what are error-checked for, not
// extensions: A specific Feature F might be enabled by an extension, or a
// particular version in a particular profile, or a stage, or combinations, etc.
//
// The basic mechanism is to use the following to "declare" all the things that
// enable/disable Feature F, in a code path that implements Feature F:
//
// requireProfile()
// profileRequires()
// requireStage()
// checkDeprecated()
// requireNotRemoved()
//
// Typically, only the first two calls are needed. They go into a code path that
// implements Feature F, and will log the proper error/warning messages. Parsing
// will then always continue as if the tested feature was enabled.
//
// There is typically no if-testing or conditional parsing, just insertion of requirements.
//
// 2) Add extension initialization to TParseContext::initializeExtensionBehavior(),
// the first function below:
//
// extensionBehavior["XXX_extension_X"] = EBhDisable;
//
// 3) Insert a profile check in the feature's path (unless all profiles support the feature,
// for some version level). That is, call requireProfile() to constrain the profiles, e.g.:
//
// // ... in a path specific to Feature F...
// requireProfile(loc,
// ECoreProfile | ECompatibilityProfile,
// "Feature F");
//
// 4) For each profile that supports the feature, insert version/extension checks:
//
// The mostly likely scenario is that Feature F can only be used with a
// particular profile if XXX_extension_X is present or the version is
// high enough that the core specification already incorporated it.
//
// // following the requireProfile() call...
// profileRequires(loc,
// ECoreProfile | ECompatibilityProfile,
// 420, // 0 if no version incorporated the feature into the core spec.
// "XXX_extension_X", // can be a list of extensions that all add the feature
// "Feature F");
//
// This allows the feature if either A) one of the extensions is enabled or
// B) the version is high enough. If no version yet incorporates the feature
// into core, pass in 0.
//
// This can be called multiple times, if different profiles support the
// feature starting at different version numbers or with different
// extensions.
//
// This must be called for each profile allowed by the initial call to requireProfile().
//
// Profiles are all masks, which can be "or"-ed together.
//
// ENoProfile
// ECoreProfile
// ECompatibilityProfile
// EEsProfile
//
// The ENoProfile profile is only for desktop, before profiles showed up in version 150;
// All other #version with no profile default to either es or core, and so have profiles.
//
// You can select all but a particular profile using ~. The following basically means "desktop":
//
// ~EEsProfile
//
#include "ParseHelper.h"
namespace glslang {
const char* StageName[EShLangCount] = {
"vertex",
"tessellation control",
"tessellation evaluation",
"geometry",
"fragment",
"compute"
};
const char* ProfileName[EProfileCount] = {
"none",
"core",
"compatibility",
"es"
};
//
// If only some profiles support a feature, use requireProfile() to specify
// which subset allows the feature. If the current profile is not present,
// give an error message.
// Initialize all extensions, almost always to 'disable', as once their features
// are incorporated into a core version, their features are supported through allowing that
// core version, not through a pseudo-enablement of the extension.
//
void TParseContext::requireProfile(TSourceLoc loc, EProfileMask profileMask, const char *featureDesc)
void TParseContext::initializeExtensionBehavior()
{
if (((1 << profile) & profileMask) == 0)
error(loc, "not supported with this profile:", featureDesc, ProfileName[profile]);
extensionBehavior["GL_ARB_texture_rectangle"] = EBhDisable;
extensionBehavior["GL_3DL_array_objects"] = EBhDisable;
}
const char* ProfileName(EProfile profile)
{
switch (profile) {
case ENoProfile: return "none";
case ECoreProfile: return "core";
case ECompatibilityProfile: return "compatibility";
case EEsProfile: return "es";
default: return "unknown profile";
}
}
//
// If only some stages support a feature, use requireStage() to specify
// which subset allows the feature. If the current stage is not present,
// When to use requireProfile():
//
// If only some profiles support a feature. However, if within a profile the feature
// is version or extension specific, follow this call with calls to profileRequires().
//
// Operation: If the current profile is not one of the profileMask,
// give an error message.
//
void TParseContext::requireStage(TSourceLoc loc, EShLanguageMask languageMask, const char *featureDesc)
void TParseContext::requireProfile(TSourceLoc loc, int profileMask, const char *featureDesc)
{
if (((1 << language) & languageMask) == 0)
error(loc, "not supported in this stage:", featureDesc, StageName[language]);
if (! (profile & profileMask))
error(loc, "not supported with this profile:", featureDesc, ProfileName(profile));
}
const char* StageName(EShLanguage stage)
{
switch(stage) {
case EShLangVertex: return "vertex";
case EShLangTessControl: return "tessellation control";
case EShLangTessEvaluation: return "tessellation evaluation";
case EShLangGeometry: return "geometry";
case EShLangFragment: return "fragment";
case EShLangCompute: return "compute";
default: return "unknown stage";
}
}
//
// Within a profile, if a feature requires a version level or extension, use
// ProfileRequires(). This only checks if the current profile matches
// the passed-in profile.
// When to use profileRequires():
//
// If a set of profiles have the same requirements for what version or extensions
// are needed to support a feature.
//
// It must be called for each profile that needs protection. Use requireProfile() first
// to reduce that set of profiles.
//
// Operation: Will issue warnings/errors based on the current profile, version, and extension
// behaviors. It only checks extensions when the current profile is one of the profileMask.
//
// A minVersion of 0 means no version of the profileMask support this in core,
// the extension must be present.
//
// one that takes multiple extensions
void TParseContext::profileRequires(TSourceLoc loc, EProfile callingProfile, int minVersion, int numExtensions, const char* extensions[], const char *featureDesc)
// entry point that takes multiple extensions
void TParseContext::profileRequires(TSourceLoc loc, int profileMask, int minVersion, int numExtensions, const char* extensions[], const char *featureDesc)
{
if (profile == callingProfile) {
if (profile & profileMask) {
bool okay = false;
if (version >= minVersion)
if (minVersion > 0 && version >= minVersion)
okay = true;
for (int i = 0; i < numExtensions; ++i) {
TBehavior behavior = extensionBehavior[extensions[i]];
TExtensionBehavior behavior = extensionBehavior[extensions[i]];
switch (behavior) {
case EBhWarn:
infoSink.info.message(EPrefixWarning, ("extension " + TString(extensions[i]) + " is being used for " + featureDesc).c_str(), loc);
@ -116,19 +214,39 @@ void TParseContext::profileRequires(TSourceLoc loc, EProfile callingProfile, int
}
}
// one that takes a single extension
void TParseContext::profileRequires(TSourceLoc loc, EProfile callingProfile, int minVersion, const char* extension, const char *featureDesc)
// entry point for the above that takes a single extension
void TParseContext::profileRequires(TSourceLoc loc, int profileMask, int minVersion, const char* extension, const char *featureDesc)
{
profileRequires(loc, callingProfile, minVersion, extension ? 1 : 0, &extension, featureDesc);
profileRequires(loc, profileMask, minVersion, extension ? 1 : 0, &extension, featureDesc);
}
//
// Within a profile, see if a feature is deprecated and error or warn based on whether
// When to use requireStage()
//
// If only some stages support a feature.
//
// Operation: If the current stage is not present, give an error message.
//
void TParseContext::requireStage(TSourceLoc loc, EShLanguageMask languageMask, const char *featureDesc)
{
if (((1 << language) & languageMask) == 0)
error(loc, "not supported in this stage:", featureDesc, StageName(language));
}
// If only one stage supports a feature, this can be called. But, all supporting stages
// must be specified with one call.
void TParseContext::requireStage(TSourceLoc loc, EShLanguage stage, const char *featureDesc)
{
requireStage(loc, static_cast<EShLanguageMask>(1 << stage), featureDesc);
}
//
// Within a set of profiles, see if a feature is deprecated and give an error or warning based on whether
// a future compatibility context is being use.
//
void TParseContext::checkDeprecated(TSourceLoc loc, EProfile callingProfile, int depVersion, const char *featureDesc)
void TParseContext::checkDeprecated(TSourceLoc loc, int profileMask, int depVersion, const char *featureDesc)
{
if (profile == callingProfile) {
if (profile & profileMask) {
if (version >= depVersion) {
if (forwardCompatible)
error(loc, "deprecated, may be removed in future release", featureDesc, "");
@ -140,30 +258,92 @@ void TParseContext::checkDeprecated(TSourceLoc loc, EProfile callingProfile, int
}
//
// Within a profile, see if a feature has now been removed and if so, give an error.
// Within a set of profiles, see if a feature has now been removed and if so, give an error.
// The version argument is the first version no longer having the feature.
//
void TParseContext::requireNotRemoved(TSourceLoc loc, EProfile callingProfile, int removedVersion, const char *featureDesc)
void TParseContext::requireNotRemoved(TSourceLoc loc, int profileMask, int removedVersion, const char *featureDesc)
{
if (profile == callingProfile) {
if (profile & profileMask) {
if (version >= removedVersion) {
const int maxSize = 60;
char buf[maxSize];
snprintf(buf, maxSize, "%s profile; removed in version %d", ProfileName[profile], removedVersion);
snprintf(buf, maxSize, "%s profile; removed in version %d", ProfileName(profile), removedVersion);
error(loc, "no longer supported in", featureDesc, buf);
}
}
}
//
// Translate from text string of extension's behavior to enum.
//
TExtensionBehavior TParseContext::getExtensionBehavior(const char* behavior)
{
if (! strcmp("require", behavior))
return EBhRequire;
else if (! strcmp("enable", behavior))
return EBhEnable;
else if (! strcmp("disable", behavior))
return EBhDisable;
else if (! strcmp("warn", behavior))
return EBhWarn;
else {
error(currentLoc, "behavior not supported", "#extension", behavior);
return EBhDisable;
}
}
void TParseContext::updateExtensionBehavior(const char* extName, const char* behaviorString)
{
TExtensionBehavior behavior = getExtensionBehavior(behaviorString);
TMap<TString, TExtensionBehavior>:: iterator iter;
TString msg;
// special case for the 'all' extension
if (! strcmp(extName, "all")) {
if (behavior == EBhRequire || behavior == EBhEnable) {
error(currentLoc, "extension 'all' cannot have 'require' or 'enable' behavior", "#extension", "");
return;
} else {
for (iter = extensionBehavior.begin(); iter != extensionBehavior.end(); ++iter)
iter->second = behavior;
}
} else {
iter = extensionBehavior.find(TString(extName));
if (iter == extensionBehavior.end()) {
switch (behavior) {
case EBhRequire:
error(currentLoc, "extension not supported", "#extension", extName);
break;
case EBhEnable:
case EBhWarn:
case EBhDisable:
warn(currentLoc, "extension not supported", "#extension", extName);
break;
default:
assert(0 && "unexpected behavior");
}
return;
} else
iter->second = behavior;
}
}
//
// Call for any operation needing full GLSL integer data-type support.
//
void TParseContext::fullIntegerCheck(TSourceLoc loc, const char* op)
{
{
profileRequires(loc, ENoProfile, 130, 0, op);
profileRequires(loc, EEsProfile, 300, 0, op);
}
//
// Call for any operation needing GLSL double data-type support.
//
void TParseContext::doubleCheck(TSourceLoc loc, const char* op)
{
requireProfile(loc, (EProfileMask)(ECoreProfileMask | ECompatibilityProfileMask), op);
{
requireProfile(loc, ECoreProfile | ECompatibilityProfile, op);
profileRequires(loc, ECoreProfile, 400, 0, op);
profileRequires(loc, ECompatibilityProfile, 400, 0, op);
}

View file

@ -40,19 +40,29 @@
// Help manage multiple profiles, versions, extensions etc.
//
//
// The behaviors from "#extension extension_name : behavior"
//
typedef enum {
ENoProfile, // only for desktop, before profiles showed up
ECoreProfile,
ECompatibilityProfile,
EEsProfile,
EProfileCount,
EBhRequire,
EBhEnable,
EBhWarn,
EBhDisable
} TExtensionBehavior;
//
// Profiles are set up for masking operations, so queries can be done on multiple
// profiles at the same time.
//
// Don't maintain an ordinal set of enums (0,1,2,3...) to avoid all possible
// defects from mixing the two different forms.
//
typedef enum {
EBadProfile = 0,
ENoProfile = (1 << 0), // only for desktop, before profiles showed up
ECoreProfile = (1 << 1),
ECompatibilityProfile = (1 << 2),
EEsProfile = (1 << 3)
} EProfile;
typedef enum {
ENoProfileMask = (1 << ENoProfile),
ECoreProfileMask = (1 << ECoreProfile),
ECompatibilityProfileMask = (1 << ECompatibilityProfile),
EEsProfileMask = (1 << EEsProfile)
} EProfileMask;
#endif // _VERSIONS_INCLUDED_

View file

@ -1047,7 +1047,7 @@ interpolation_qualifier
}
| NOPERSPECTIVE {
parseContext.globalCheck($1.loc, parseContext.symbolTable.atGlobalLevel(), "noperspective");
parseContext.requireProfile($1.loc, static_cast<EProfileMask>(~EEsProfileMask), "noperspective");
parseContext.requireProfile($1.loc, ~EEsProfile, "noperspective");
parseContext.profileRequires($1.loc, ENoProfile, 130, 0, "noperspective");
$$.init($1.loc);
$$.qualifier.nopersp = true;
@ -1138,7 +1138,7 @@ storage_qualifier
$$.qualifier.storage = EvqConst;
}
| ATTRIBUTE {
parseContext.requireStage($1.loc, EShLangVertexMask, "attribute");
parseContext.requireStage($1.loc, EShLangVertex, "attribute");
parseContext.checkDeprecated($1.loc, ECoreProfile, 130, "attribute");
parseContext.checkDeprecated($1.loc, ENoProfile, 130, "attribute");
parseContext.requireNotRemoved($1.loc, ECoreProfile, 420, "attribute");
@ -1206,9 +1206,9 @@ storage_qualifier
$$.qualifier.storage = EvqUniform; // TODO: 4.0 functionality: implement BUFFER
}
| SHARED {
parseContext.requireProfile($1.loc, static_cast<EProfileMask>(~EEsProfileMask), "shared");
parseContext.requireProfile($1.loc, ~EEsProfile, "shared");
parseContext.profileRequires($1.loc, ECoreProfile, 430, 0, "shared");
parseContext.requireStage($1.loc, EShLangComputeMask, "shared");
parseContext.requireStage($1.loc, EShLangCompute, "shared");
$$.init($1.loc);
$$.qualifier.shared = true;
}
@ -2315,7 +2315,7 @@ jump_statement
parseContext.error($1.loc, "function return is not matching type:", "return", "");
}
| DISCARD SEMICOLON {
parseContext.requireStage($1.loc, EShLangFragmentMask, "discard");
parseContext.requireStage($1.loc, EShLangFragment, "discard");
$$ = parseContext.intermediate.addBranch(EOpKill, $1.loc);
}
;

View file

@ -529,7 +529,7 @@ int TPpContext::CPPifdef(int defined, TPpToken * yylvalpp)
int token = currentInput->scan(this, currentInput, yylvalpp);
int name = yylvalpp->atom;
if (++ifdepth > maxIfNesting) {
parseContext.error(yylvalpp->loc, "maximum nesting depth exceededextension name not specified", "#ifdef", "");
parseContext.error(yylvalpp->loc, "maximum nesting depth exceeded", "#ifdef", "");
return 0;
}
elsetracker++;

View file

@ -96,7 +96,7 @@ typedef enum {
namespace glslang {
extern const char* StageName[EShLangCount];
const char* StageName(EShLanguage);
} // end namespace glslang