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:
parent
a5830dfc0e
commit
61c2d1410a
12
README.txt
12
README.txt
@ -7,10 +7,13 @@ There are two components:
|
|||||||
2) A standalone wrapper, glslangValidator, that can be used as a shader
|
2) A standalone wrapper, glslangValidator, that can be used as a shader
|
||||||
validation tool.
|
validation tool.
|
||||||
|
|
||||||
|
How to add a feature protected by a version/extension/stage/profile: See the
|
||||||
|
comment in glslang/MachineIndependent/Versions.cpp.
|
||||||
|
|
||||||
Things left to do: See Todo.txt
|
Things left to do: See Todo.txt
|
||||||
|
|
||||||
Execution
|
Execution of Standalone Wrapper
|
||||||
---------
|
-------------------------------
|
||||||
|
|
||||||
There are binaries in the Install/Windows and Install/Linux directories.
|
There are binaries in the Install/Windows and Install/Linux directories.
|
||||||
|
|
||||||
@ -26,7 +29,10 @@ The applied stage-specific rules are based on the file extension:
|
|||||||
.frag for a fragment shader
|
.frag for a fragment shader
|
||||||
.comp for a compute shader
|
.comp for a compute shader
|
||||||
|
|
||||||
Source: Build and run on linux
|
There is also a non-shader extension
|
||||||
|
.conf for a configuration file of limits, see usage statement for example
|
||||||
|
|
||||||
|
Source: Build and run on Linux
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
A simple bash script "BuildLinux.sh" is provided at the root directory
|
A simple bash script "BuildLinux.sh" is provided at the root directory
|
||||||
|
|||||||
24
Todo.txt
24
Todo.txt
@ -1,7 +1,5 @@
|
|||||||
Current functionality level: ESSL 3.0
|
Current functionality level: ESSL 3.0
|
||||||
|
|
||||||
- extension adding process
|
|
||||||
|
|
||||||
Link Validation
|
Link Validation
|
||||||
+ provide input config file for setting limits
|
+ provide input config file for setting limits
|
||||||
- also consider spitting out measures of complexity
|
- also consider spitting out measures of complexity
|
||||||
@ -166,22 +164,24 @@ Shader Functionality to Implement/Finish
|
|||||||
- Allow swizzle operations on scalars.
|
- Allow swizzle operations on scalars.
|
||||||
- Positive signed decimal literals, as well as octal and hexadecimal, can set all 32 bits. This includes setting the sign bit to create a negative value.
|
- Positive signed decimal literals, as well as octal and hexadecimal, can set all 32 bits. This includes setting the sign bit to create a negative value.
|
||||||
- Make GLSL consistent with the API regarding user clipping, by no longer referring to gl_Positionwhen gl_ClipVertex is not written. Rather, user clipping becomes undefined.
|
- Make GLSL consistent with the API regarding user clipping, by no longer referring to gl_Positionwhen gl_ClipVertex is not written. Rather, user clipping becomes undefined.
|
||||||
- Clarified that a comma sequence-operator expression cannot be a constant expression. E.g., “(2,3)” is not allowed, semantically, as a valid constant expression 3, even though it is an expression that will evaluate to 3.
|
- Clarified that a comma sequence-operator expression cannot be a constant expression. E.g., “(2,3)” is not allowed, semantically,
|
||||||
|
as a valid constant expression 3, even though it is an expression that will evaluate to 3.
|
||||||
- Use vec2 instead of vec3 for coordinate in textureGather*(sampler2DRect,...).
|
- Use vec2 instead of vec3 for coordinate in textureGather*(sampler2DRect,...).
|
||||||
- Clarify that textureGatherOffset() can take non-constants for the offsets.
|
- Clarify that textureGatherOffset() can take non-constants for the offsets.
|
||||||
GLSL 4.3
|
GLSL 4.3
|
||||||
- Add shader storage bufferobjects, as per the ARB_shader_storage_buffer_object extension.
|
- Add shader storage buffer objects, as per the ARB_shader_storage_buffer_object extension. This includes
|
||||||
This includes 1) allowing the last member of a storage buffer block to be an array that does not
|
- allowing the last member of a storage buffer block to be an array that does not know its size until render time
|
||||||
know its size until render time, and 2) read/write memory shared with the application and other
|
- read/write memory shared with the application and other shader invocations
|
||||||
shader invocations. It also adds the std430layout qualifier for shader storage blocks.
|
- adding the std430 layout qualifier for shader storage blocks
|
||||||
- Allow .length() on all arrays; returning a compile-time constant or not, depending on how the
|
- Allow .length() on all arrays; returning a compile-time constant or not, depending on how the
|
||||||
array is sized, as per the ARB_shader_storage_buffer_object extension.
|
array is sized, as per the ARB_shader_storage_buffer_object extension.
|
||||||
- Be clear that implicit array sizing is only within a stage, not cross stage.
|
- Be clear that implicit array sizing is only within a stage, not cross stage.
|
||||||
- Array clarifications: 1) All arrays are inherently homogeneous, except for arrays of the new
|
- Array clarifications:
|
||||||
shader storage buffer objects. 2) Arrays of shader storage buffer objects will be dereferenced
|
- All arrays are inherently homogeneous, except for arrays of the new shader storage buffer objects
|
||||||
when the .length() method is used on an unsized array member, so that must a have valid index.
|
- Arrays of shader storage buffer objects will be dereferenced when the .length() method is used on an unsized array
|
||||||
3) Arrays of other objects (uniform blocks) containing implicitly sized arrays will have the same
|
member, so that must a have valid index.
|
||||||
implicit size for all elements of the array.
|
- Arrays of other objects (uniform blocks) containing implicitly sized arrays will have the same implicit size for all
|
||||||
|
elements of the array.
|
||||||
- Arrays of arrays are now supported, as per the GL_ARB_arrays_of_arraysextension.
|
- Arrays of arrays are now supported, as per the GL_ARB_arrays_of_arraysextension.
|
||||||
- Compute shaders are now supported, as per the GL_ARB_compute_shader extension.
|
- Compute shaders are now supported, as per the GL_ARB_compute_shader extension.
|
||||||
- Added imageSize() built-ins to query the dimensions of an image.
|
- Added imageSize() built-ins to query the dimensions of an image.
|
||||||
|
|||||||
@ -584,7 +584,7 @@ void TBuiltIns::initialize(int version, EProfile profile)
|
|||||||
s.append("\n");
|
s.append("\n");
|
||||||
|
|
||||||
//
|
//
|
||||||
// Original-style texture Functions existing in both stages.
|
// Original-style texture functions existing in both stages.
|
||||||
// (Per-stage functions below.)
|
// (Per-stage functions below.)
|
||||||
//
|
//
|
||||||
if (profile == EEsProfile && version == 100 ||
|
if (profile == EEsProfile && version == 100 ||
|
||||||
|
|||||||
@ -1098,7 +1098,7 @@ void TIntermediate::checkCallGraphCycles(TInfoSink& infoSink)
|
|||||||
void TIntermediate::error(TInfoSink& infoSink, const char* message)
|
void TIntermediate::error(TInfoSink& infoSink, const char* message)
|
||||||
{
|
{
|
||||||
infoSink.info.prefix(EPrefixError);
|
infoSink.info.prefix(EPrefixError);
|
||||||
infoSink.info << "Linking " << StageName[language] << " stage: " << message << "\n";
|
infoSink.info << "Linking " << StageName(language) << " stage: " << message << "\n";
|
||||||
|
|
||||||
++numErrors;
|
++numErrors;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
// Sub- vector and matrix fields
|
||||||
@ -538,12 +485,11 @@ TIntermTyped* TParseContext::handleBracketDereference(TSourceLoc loc, TIntermTyp
|
|||||||
if (base->isArray() && base->getType().getArraySize() == 0)
|
if (base->isArray() && base->getType().getArraySize() == 0)
|
||||||
error(loc, "", "[", "array must be redeclared with a size before being indexed with a variable");
|
error(loc, "", "[", "array must be redeclared with a size before being indexed with a variable");
|
||||||
if (base->getBasicType() == EbtBlock)
|
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) {
|
if (base->getBasicType() == EbtSampler && version >= 130) {
|
||||||
const char* explanation = "variable indexing sampler array";
|
const char* explanation = "variable indexing sampler array";
|
||||||
requireProfile(base->getLoc(), static_cast<EProfileMask>(ECoreProfileMask | ECompatibilityProfileMask), explanation);
|
requireProfile(base->getLoc(), ECoreProfile | ECompatibilityProfile, explanation);
|
||||||
profileRequires(base->getLoc(), ECoreProfile, 400, 0, explanation);
|
profileRequires(base->getLoc(), ECoreProfile | ECompatibilityProfile, 400, 0, explanation);
|
||||||
profileRequires(base->getLoc(), ECompatibilityProfile, 400, 0, explanation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result = intermediate.addIndex(EOpIndexIndirect, base, index, loc);
|
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
|
// ES can't declare prototypes inside functions
|
||||||
if (! symbolTable.atGlobalLevel())
|
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.
|
// Multiple declarations of the same function are allowed.
|
||||||
@ -1479,7 +1425,7 @@ void TParseContext::globalQualifierFix(TSourceLoc loc, TQualifier& qualifier, co
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (publicType.arraySizes) {
|
if (publicType.arraySizes) {
|
||||||
requireProfile(loc, (EProfileMask)~EEsProfileMask, "vertex input arrays");
|
requireProfile(loc, ~EEsProfile, "vertex input arrays");
|
||||||
profileRequires(loc, ENoProfile, 150, 0, "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");
|
profileRequires(loc, ENoProfile, 120, "GL_3DL_array_objects", "const array");
|
||||||
|
|
||||||
if (qualifier.storage == EvqVaryingIn && language == EShLangVertex) {
|
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");
|
profileRequires(loc, ENoProfile, 150, 0, "vertex input arrays");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1726,9 +1672,8 @@ void TParseContext::arraySizeRequiredCheck(TSourceLoc loc, int size)
|
|||||||
|
|
||||||
void TParseContext::arrayDimError(TSourceLoc loc)
|
void TParseContext::arrayDimError(TSourceLoc loc)
|
||||||
{
|
{
|
||||||
requireProfile(loc, (EProfileMask)(ECoreProfileMask | ECompatibilityProfileMask), "arrays of arrays");
|
requireProfile(loc, ECoreProfile | ECompatibilityProfile, "arrays of arrays");
|
||||||
profileRequires(loc, ECoreProfile, 430, 0, "arrays of arrays");
|
profileRequires(loc, ECoreProfile | ECompatibilityProfile, 430, 0, "arrays of arrays");
|
||||||
profileRequires(loc, ECompatibilityProfile, 430, 0, "arrays of arrays");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TParseContext::arrayDimCheck(TSourceLoc loc, TArraySizes* sizes1, TArraySizes* sizes2)
|
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());
|
arraySizeRequiredCheck(loc, arraySizes->getSize());
|
||||||
|
|
||||||
if (currentBlockDefaults.storage == EvqUniform) {
|
if (currentBlockDefaults.storage == EvqUniform) {
|
||||||
requireProfile(loc, (EProfileMask)(~ENoProfileMask), "uniform block");
|
requireProfile(loc, ~ENoProfile, "uniform block");
|
||||||
profileRequires(loc, EEsProfile, 300, 0, "uniform block");
|
profileRequires(loc, EEsProfile, 300, 0, "uniform block");
|
||||||
} else {
|
} else {
|
||||||
error(loc, "only uniform interface blocks are supported", blockName->c_str(), "");
|
error(loc, "only uniform interface blocks are supported", blockName->c_str(), "");
|
||||||
@ -2788,17 +2733,4 @@ TIntermTyped* TParseContext::addConstStruct(TString& identifier, TIntermTyped* n
|
|||||||
return typedNode;
|
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
|
} // end namespace glslang
|
||||||
|
|||||||
@ -43,13 +43,6 @@
|
|||||||
|
|
||||||
namespace glslang {
|
namespace glslang {
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
EBhRequire,
|
|
||||||
EBhEnable,
|
|
||||||
EBhWarn,
|
|
||||||
EBhDisable
|
|
||||||
} TBehavior;
|
|
||||||
|
|
||||||
struct TPragma {
|
struct TPragma {
|
||||||
TPragma(bool o, bool d) : optimize(o), debug(d) { }
|
TPragma(bool o, bool d) : optimize(o), debug(d) { }
|
||||||
bool optimize;
|
bool optimize;
|
||||||
@ -71,7 +64,6 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
bool parseShaderStrings(TPpContext&, char* strings[], int strLen[], int numStrings);
|
bool parseShaderStrings(TPpContext&, char* strings[], int strLen[], int numStrings);
|
||||||
void initializeExtensionBehavior();
|
|
||||||
void parserError(const char *s); // for bison's yyerror
|
void parserError(const char *s); // for bison's yyerror
|
||||||
|
|
||||||
void C_DECL error(TSourceLoc, const char *szReason, const char *szToken,
|
void C_DECL error(TSourceLoc, const char *szReason, const char *szToken,
|
||||||
@ -148,15 +140,6 @@ public:
|
|||||||
|
|
||||||
bool arraySetMaxSize(TSourceLoc, TIntermSymbol*, int);
|
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; }
|
void setScanContext(TScanContext* c) { scanContext = c; }
|
||||||
TScanContext* getScanContext() const { return scanContext; }
|
TScanContext* getScanContext() const { return scanContext; }
|
||||||
void setPpContext(TPpContext* c) { ppContext = c; }
|
void setPpContext(TPpContext* c) { ppContext = c; }
|
||||||
@ -164,9 +147,21 @@ public:
|
|||||||
void addError() { ++numErrors; }
|
void addError() { ++numErrors; }
|
||||||
int getNumErrors() const { return 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:
|
protected:
|
||||||
const char* getPreamble();
|
const char* getPreamble();
|
||||||
TBehavior getExtensionBehavior(const char* behavior);
|
TExtensionBehavior getExtensionBehavior(const char* behavior);
|
||||||
void nonInitConstCheck(TSourceLoc, TString& identifier, TType& type);
|
void nonInitConstCheck(TSourceLoc, TString& identifier, TType& type);
|
||||||
TVariable* declareNonArray(TSourceLoc, TString& identifier, TType&, bool& newDeclaration);
|
TVariable* declareNonArray(TSourceLoc, TString& identifier, TType&, bool& newDeclaration);
|
||||||
void declareArray(TSourceLoc, TString& identifier, const TType&, TVariable*&, bool& newDeclaration);
|
void declareArray(TSourceLoc, TString& identifier, const TType&, TVariable*&, bool& newDeclaration);
|
||||||
@ -208,7 +203,7 @@ protected:
|
|||||||
TPpContext* ppContext;
|
TPpContext* ppContext;
|
||||||
int numErrors; // number of compile-time errors encountered
|
int numErrors; // number of compile-time errors encountered
|
||||||
bool parsingBuiltins; // true if parsing built-in symbols/functions
|
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()
|
static const int maxSamplerIndex = EsdNumDims * (EbtNumTypes * (2 * 2)); // see computeSamplerTypeIndex()
|
||||||
TPrecisionQualifier defaultSamplerPrecision[maxSamplerIndex];
|
TPrecisionQualifier defaultSamplerPrecision[maxSamplerIndex];
|
||||||
bool afterEOF;
|
bool afterEOF;
|
||||||
|
|||||||
@ -59,9 +59,11 @@ namespace { // anonymous namespace for file-local functions and symbols
|
|||||||
|
|
||||||
using namespace glslang;
|
using namespace glslang;
|
||||||
|
|
||||||
|
// Local mapping functions for making arrays of symbol tables....
|
||||||
|
|
||||||
int MapVersionToIndex(int version)
|
int MapVersionToIndex(int version)
|
||||||
{
|
{
|
||||||
switch(version) {
|
switch (version) {
|
||||||
case 100: return 0;
|
case 100: return 0;
|
||||||
case 110: return 1;
|
case 110: return 1;
|
||||||
case 120: return 2;
|
case 120: return 2;
|
||||||
@ -81,6 +83,19 @@ int MapVersionToIndex(int version)
|
|||||||
} // V
|
} // V
|
||||||
const int VersionCount = 13; // number of case statements above
|
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
|
// only one of these needed for non-ES; ES needs 2 for different precision defaults of built-ins
|
||||||
enum EPrecisionClass {
|
enum EPrecisionClass {
|
||||||
EPcGeneral,
|
EPcGeneral,
|
||||||
@ -96,8 +111,8 @@ enum EPrecisionClass {
|
|||||||
// Each has a different set of built-ins, and we want to preserve that from
|
// Each has a different set of built-ins, and we want to preserve that from
|
||||||
// compile to compile.
|
// compile to compile.
|
||||||
//
|
//
|
||||||
TSymbolTable* CommonSymbolTable[VersionCount][EProfileCount][EPcCount] = {};
|
TSymbolTable* CommonSymbolTable[VersionCount][ProfileCount][EPcCount] = {};
|
||||||
TSymbolTable* SharedSymbolTables[VersionCount][EProfileCount][EShLangCount] = {};
|
TSymbolTable* SharedSymbolTables[VersionCount][ProfileCount][EShLangCount] = {};
|
||||||
|
|
||||||
TPoolAllocator* PerProcessGPA = 0;
|
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
|
// See if it's already been done for this version/profile combination
|
||||||
int versionIndex = MapVersionToIndex(version);
|
int versionIndex = MapVersionToIndex(version);
|
||||||
if (CommonSymbolTable[versionIndex][profile][EPcGeneral]) {
|
int profileIndex = MapProfileToIndex(profile);
|
||||||
|
if (CommonSymbolTable[versionIndex][profileIndex][EPcGeneral]) {
|
||||||
glslang::ReleaseGlobalLock();
|
glslang::ReleaseGlobalLock();
|
||||||
|
|
||||||
return;
|
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
|
// 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) {
|
for (int precClass = 0; precClass < EPcCount; ++precClass) {
|
||||||
if (! commonTable[precClass]->isEmpty()) {
|
if (! commonTable[precClass]->isEmpty()) {
|
||||||
CommonSymbolTable[versionIndex][profile][precClass] = new TSymbolTable;
|
CommonSymbolTable[versionIndex][profileIndex][precClass] = new TSymbolTable;
|
||||||
CommonSymbolTable[versionIndex][profile][precClass]->copyTable(*commonTable[precClass]);
|
CommonSymbolTable[versionIndex][profileIndex][precClass]->copyTable(*commonTable[precClass]);
|
||||||
CommonSymbolTable[versionIndex][profile][precClass]->readOnly();
|
CommonSymbolTable[versionIndex][profileIndex][precClass]->readOnly();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int stage = 0; stage < EShLangCount; ++stage) {
|
for (int stage = 0; stage < EShLangCount; ++stage) {
|
||||||
if (! stageTables[stage]->isEmpty()) {
|
if (! stageTables[stage]->isEmpty()) {
|
||||||
SharedSymbolTables[versionIndex][profile][stage] = new TSymbolTable;
|
SharedSymbolTables[versionIndex][profileIndex][stage] = new TSymbolTable;
|
||||||
SharedSymbolTables[versionIndex][profile][stage]->adoptLevels(*CommonSymbolTable[versionIndex][profile][CommonIndex(profile, (EShLanguage)stage)]);
|
SharedSymbolTables[versionIndex][profileIndex][stage]->adoptLevels(*CommonSymbolTable[versionIndex][profileIndex][CommonIndex(profile, (EShLanguage)stage)]);
|
||||||
SharedSymbolTables[versionIndex][profile][stage]->copyTable(*stageTables[stage]);
|
SharedSymbolTables[versionIndex][profileIndex][stage]->copyTable(*stageTables[stage]);
|
||||||
SharedSymbolTables[versionIndex][profile][stage]->readOnly();
|
SharedSymbolTables[versionIndex][profileIndex][stage]->readOnly();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,7 +449,7 @@ bool CompileDeferred(
|
|||||||
SetupBuiltinSymbolTable(version, profile);
|
SetupBuiltinSymbolTable(version, profile);
|
||||||
|
|
||||||
TSymbolTable* cachedTable = SharedSymbolTables[MapVersionToIndex(version)]
|
TSymbolTable* cachedTable = SharedSymbolTables[MapVersionToIndex(version)]
|
||||||
[profile]
|
[MapProfileToIndex(profile)]
|
||||||
[compiler->getLanguage()];
|
[compiler->getLanguage()];
|
||||||
|
|
||||||
// Dynamically allocate the symbol table so we can control when it is deallocated WRT the pool.
|
// 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()
|
int __fastcall ShFinalize()
|
||||||
{
|
{
|
||||||
for (int version = 0; version < VersionCount; ++version)
|
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)
|
for (int lang = 0; lang < EShLangCount; ++lang)
|
||||||
delete SharedSymbolTables[version][p][lang];
|
delete SharedSymbolTables[version][p][lang];
|
||||||
|
|
||||||
@ -964,7 +980,7 @@ bool TProgram::linkStage(EShLanguage stage, EShMessages messages)
|
|||||||
merged = intermediate[stage];
|
merged = intermediate[stage];
|
||||||
}
|
}
|
||||||
|
|
||||||
infoSink->info << "\nLinked " << StageName[stage] << " stage:\n\n";
|
infoSink->info << "\nLinked " << StageName(stage) << " stage:\n\n";
|
||||||
|
|
||||||
if (stages[stage].size() > 1) {
|
if (stages[stage].size() > 1) {
|
||||||
std::list<TShader*>::const_iterator it;
|
std::list<TShader*>::const_iterator it;
|
||||||
|
|||||||
@ -37,68 +37,166 @@
|
|||||||
//
|
//
|
||||||
// Help manage multiple profiles, versions, extensions etc.
|
// Help manage multiple profiles, versions, extensions etc.
|
||||||
//
|
//
|
||||||
// These don't return error codes, as the presumption is parsing
|
// These don't return error codes, as the presumption is parsing will
|
||||||
// will always continue as if the feature were present, and there
|
// always continue as if the tested feature were enabled, and thus there
|
||||||
// is no error recovery needed to enable that.
|
// 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"
|
#include "ParseHelper.h"
|
||||||
|
|
||||||
namespace glslang {
|
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
|
// Initialize all extensions, almost always to 'disable', as once their features
|
||||||
// which subset allows the feature. If the current profile is not present,
|
// are incorporated into a core version, their features are supported through allowing that
|
||||||
// give an error message.
|
// 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)
|
extensionBehavior["GL_ARB_texture_rectangle"] = EBhDisable;
|
||||||
error(loc, "not supported with this profile:", featureDesc, ProfileName[profile]);
|
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
|
// When to use requireProfile():
|
||||||
// which subset allows the feature. If the current stage is not present,
|
//
|
||||||
|
// 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.
|
// 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)
|
if (! (profile & profileMask))
|
||||||
error(loc, "not supported in this stage:", featureDesc, StageName[language]);
|
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
|
// When to use profileRequires():
|
||||||
// ProfileRequires(). This only checks if the current profile matches
|
//
|
||||||
// the passed-in profile.
|
// 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
|
// entry point that takes multiple extensions
|
||||||
void TParseContext::profileRequires(TSourceLoc loc, EProfile callingProfile, int minVersion, int numExtensions, const char* extensions[], const char *featureDesc)
|
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;
|
bool okay = false;
|
||||||
if (version >= minVersion)
|
if (minVersion > 0 && version >= minVersion)
|
||||||
okay = true;
|
okay = true;
|
||||||
for (int i = 0; i < numExtensions; ++i) {
|
for (int i = 0; i < numExtensions; ++i) {
|
||||||
TBehavior behavior = extensionBehavior[extensions[i]];
|
TExtensionBehavior behavior = extensionBehavior[extensions[i]];
|
||||||
switch (behavior) {
|
switch (behavior) {
|
||||||
case EBhWarn:
|
case EBhWarn:
|
||||||
infoSink.info.message(EPrefixWarning, ("extension " + TString(extensions[i]) + " is being used for " + featureDesc).c_str(), loc);
|
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
|
// entry point for the above that takes a single extension
|
||||||
void TParseContext::profileRequires(TSourceLoc loc, EProfile callingProfile, int minVersion, const char* extension, const char *featureDesc)
|
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.
|
// 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 (version >= depVersion) {
|
||||||
if (forwardCompatible)
|
if (forwardCompatible)
|
||||||
error(loc, "deprecated, may be removed in future release", featureDesc, "");
|
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.
|
// 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) {
|
if (version >= removedVersion) {
|
||||||
const int maxSize = 60;
|
const int maxSize = 60;
|
||||||
char buf[maxSize];
|
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);
|
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)
|
void TParseContext::fullIntegerCheck(TSourceLoc loc, const char* op)
|
||||||
{
|
{
|
||||||
profileRequires(loc, ENoProfile, 130, 0, op);
|
profileRequires(loc, ENoProfile, 130, 0, op);
|
||||||
profileRequires(loc, EEsProfile, 300, 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)
|
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, ECoreProfile, 400, 0, op);
|
||||||
profileRequires(loc, ECompatibilityProfile, 400, 0, op);
|
profileRequires(loc, ECompatibilityProfile, 400, 0, op);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -40,19 +40,29 @@
|
|||||||
// Help manage multiple profiles, versions, extensions etc.
|
// Help manage multiple profiles, versions, extensions etc.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// The behaviors from "#extension extension_name : behavior"
|
||||||
|
//
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ENoProfile, // only for desktop, before profiles showed up
|
EBhRequire,
|
||||||
ECoreProfile,
|
EBhEnable,
|
||||||
ECompatibilityProfile,
|
EBhWarn,
|
||||||
EEsProfile,
|
EBhDisable
|
||||||
EProfileCount,
|
} 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;
|
} EProfile;
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
ENoProfileMask = (1 << ENoProfile),
|
|
||||||
ECoreProfileMask = (1 << ECoreProfile),
|
|
||||||
ECompatibilityProfileMask = (1 << ECompatibilityProfile),
|
|
||||||
EEsProfileMask = (1 << EEsProfile)
|
|
||||||
} EProfileMask;
|
|
||||||
|
|
||||||
#endif // _VERSIONS_INCLUDED_
|
#endif // _VERSIONS_INCLUDED_
|
||||||
|
|||||||
@ -1047,7 +1047,7 @@ interpolation_qualifier
|
|||||||
}
|
}
|
||||||
| NOPERSPECTIVE {
|
| NOPERSPECTIVE {
|
||||||
parseContext.globalCheck($1.loc, parseContext.symbolTable.atGlobalLevel(), "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");
|
parseContext.profileRequires($1.loc, ENoProfile, 130, 0, "noperspective");
|
||||||
$$.init($1.loc);
|
$$.init($1.loc);
|
||||||
$$.qualifier.nopersp = true;
|
$$.qualifier.nopersp = true;
|
||||||
@ -1138,7 +1138,7 @@ storage_qualifier
|
|||||||
$$.qualifier.storage = EvqConst;
|
$$.qualifier.storage = EvqConst;
|
||||||
}
|
}
|
||||||
| ATTRIBUTE {
|
| ATTRIBUTE {
|
||||||
parseContext.requireStage($1.loc, EShLangVertexMask, "attribute");
|
parseContext.requireStage($1.loc, EShLangVertex, "attribute");
|
||||||
parseContext.checkDeprecated($1.loc, ECoreProfile, 130, "attribute");
|
parseContext.checkDeprecated($1.loc, ECoreProfile, 130, "attribute");
|
||||||
parseContext.checkDeprecated($1.loc, ENoProfile, 130, "attribute");
|
parseContext.checkDeprecated($1.loc, ENoProfile, 130, "attribute");
|
||||||
parseContext.requireNotRemoved($1.loc, ECoreProfile, 420, "attribute");
|
parseContext.requireNotRemoved($1.loc, ECoreProfile, 420, "attribute");
|
||||||
@ -1206,9 +1206,9 @@ storage_qualifier
|
|||||||
$$.qualifier.storage = EvqUniform; // TODO: 4.0 functionality: implement BUFFER
|
$$.qualifier.storage = EvqUniform; // TODO: 4.0 functionality: implement BUFFER
|
||||||
}
|
}
|
||||||
| SHARED {
|
| 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.profileRequires($1.loc, ECoreProfile, 430, 0, "shared");
|
||||||
parseContext.requireStage($1.loc, EShLangComputeMask, "shared");
|
parseContext.requireStage($1.loc, EShLangCompute, "shared");
|
||||||
$$.init($1.loc);
|
$$.init($1.loc);
|
||||||
$$.qualifier.shared = true;
|
$$.qualifier.shared = true;
|
||||||
}
|
}
|
||||||
@ -2315,7 +2315,7 @@ jump_statement
|
|||||||
parseContext.error($1.loc, "function return is not matching type:", "return", "");
|
parseContext.error($1.loc, "function return is not matching type:", "return", "");
|
||||||
}
|
}
|
||||||
| DISCARD SEMICOLON {
|
| DISCARD SEMICOLON {
|
||||||
parseContext.requireStage($1.loc, EShLangFragmentMask, "discard");
|
parseContext.requireStage($1.loc, EShLangFragment, "discard");
|
||||||
$$ = parseContext.intermediate.addBranch(EOpKill, $1.loc);
|
$$ = parseContext.intermediate.addBranch(EOpKill, $1.loc);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|||||||
@ -529,7 +529,7 @@ int TPpContext::CPPifdef(int defined, TPpToken * yylvalpp)
|
|||||||
int token = currentInput->scan(this, currentInput, yylvalpp);
|
int token = currentInput->scan(this, currentInput, yylvalpp);
|
||||||
int name = yylvalpp->atom;
|
int name = yylvalpp->atom;
|
||||||
if (++ifdepth > maxIfNesting) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
elsetracker++;
|
elsetracker++;
|
||||||
|
|||||||
@ -96,7 +96,7 @@ typedef enum {
|
|||||||
|
|
||||||
namespace glslang {
|
namespace glslang {
|
||||||
|
|
||||||
extern const char* StageName[EShLangCount];
|
const char* StageName(EShLanguage);
|
||||||
|
|
||||||
} // end namespace glslang
|
} // end namespace glslang
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user