Commit 61c2d141 by John Kessenich

Document how to add a new feature enabled by an extension in Versions.cpp. Also…

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
parent a5830dfc
......@@ -7,10 +7,13 @@ There are two components:
2) A standalone wrapper, glslangValidator, that can be used as a shader
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
Execution
---------
Execution of Standalone Wrapper
-------------------------------
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
.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
......
Current functionality level: ESSL 3.0
- extension adding process
Link Validation
+ provide input config file for setting limits
- also consider spitting out measures of complexity
......@@ -166,22 +164,24 @@ Shader Functionality to Implement/Finish
- 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.
- 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,...).
- Clarify that textureGatherOffset() can take non-constants for the offsets.
GLSL 4.3
- Add shader storage bufferobjects, as per the ARB_shader_storage_buffer_object extension.
This includes 1) allowing the last member of a storage buffer block to be an array that does not
know its size until render time, and 2) read/write memory shared with the application and other
shader invocations. It also adds the std430layout qualifier for shader storage blocks.
- Add shader storage buffer objects, as per the ARB_shader_storage_buffer_object extension. This includes
- allowing the last member of a storage buffer block to be an array that does not know its size until render time
- read/write memory shared with the application and other shader invocations
- 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
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.
- Array clarifications: 1) All arrays are inherently homogeneous, except for arrays of the new
shader storage buffer objects. 2) Arrays of shader storage buffer objects will be dereferenced
when the .length() method is used on an unsized array member, so that must a have valid index.
3) Arrays of other objects (uniform blocks) containing implicitly sized arrays will have the same
implicit size for all elements of the array.
- Array clarifications:
- All arrays are inherently homogeneous, except for arrays of the new shader storage buffer objects
- Arrays of shader storage buffer objects will be dereferenced when the .length() method is used on an unsized array
member, so that must a have valid index.
- 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.
- Compute shaders are now supported, as per the GL_ARB_compute_shader extension.
- 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");
//
// 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 ||
......
......@@ -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;
}
......
......@@ -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
......@@ -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;
......
......@@ -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;
......
......@@ -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,
} EProfile;
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 {
ENoProfileMask = (1 << ENoProfile),
ECoreProfileMask = (1 << ECoreProfile),
ECompatibilityProfileMask = (1 << ECompatibilityProfile),
EEsProfileMask = (1 << EEsProfile)
} EProfileMask;
EBadProfile = 0,
ENoProfile = (1 << 0), // only for desktop, before profiles showed up
ECoreProfile = (1 << 1),
ECompatibilityProfile = (1 << 2),
EEsProfile = (1 << 3)
} EProfile;
#endif // _VERSIONS_INCLUDED_
......@@ -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);
}
;
......
......@@ -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++;
......
......@@ -96,7 +96,7 @@ typedef enum {
namespace glslang {
extern const char* StageName[EShLangCount];
const char* StageName(EShLanguage);
} // end namespace glslang
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment