Add GL_OES_standard_derivatives. Also added extension infrastructure that allows built-in symbols to be tagged with extensions and automatically error checked against them.

git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@24002 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
John Kessenich 2013-11-11 20:31:45 +00:00
parent 115a0adc29
commit 06a37c3964
9 changed files with 150 additions and 13 deletions

View File

@ -88,4 +88,16 @@ void foo234()
{ {
texture3D(s3D2, vec3(0.2), 0.2); texture3D(s3D2, vec3(0.2), 0.2);
texture3DProj(s3D2, v[1], 0.4); texture3DProj(s3D2, v[1], 0.4);
dFdx(v[0]); // ERROR
dFdy(3.2); // ERROR
fwidth(f13); // ERROR
}
#extension GL_OES_standard_derivatives : enable
void foo236()
{
dFdx(v[0]);
dFdy(3.2);
fwidth(f13);
} }

View File

@ -42,7 +42,10 @@ ERROR: 0:76: 'h' : cannot use storage or interpolation qualifiers on structure m
ERROR: 0:77: 'i' : cannot use invariant qualifier on structure members ERROR: 0:77: 'i' : cannot use invariant qualifier on structure members
ERROR: 0:80: 'sampler3D' : Reserved word. ERROR: 0:80: 'sampler3D' : Reserved word.
ERROR: 0:80: 'sampler/image' : type requires declaration of default precision qualifier ERROR: 0:80: 'sampler/image' : type requires declaration of default precision qualifier
ERROR: 37 compilation errors. No code generated. ERROR: 0:91: 'dFdx' : required extension not requested: GL_OES_standard_derivatives
ERROR: 0:92: 'dFdy' : required extension not requested: GL_OES_standard_derivatives
ERROR: 0:93: 'fwidth' : required extension not requested: GL_OES_standard_derivatives
ERROR: 40 compilation errors. No code generated.
ERROR: node is still EOpNull! ERROR: node is still EOpNull!
0:3 Sequence 0:3 Sequence
@ -142,6 +145,27 @@ ERROR: node is still EOpNull!
0:90 1 (const int) 0:90 1 (const int)
0:90 Constant: 0:90 Constant:
0:90 0.400000 0:90 0.400000
0:91 dPdx (mediump 4-component vector of float)
0:91 direct index (smooth mediump 4-component vector of float)
0:91 'v' (smooth in 3-element array of mediump 4-component vector of float)
0:91 Constant:
0:91 0 (const int)
0:92 Constant:
0:92 0.000000
0:93 fwidth (mediump float)
0:93 'f13' (invariant mediump float)
0:98 Function Definition: foo236( (void)
0:98 Function Parameters:
0:100 Sequence
0:100 dPdx (mediump 4-component vector of float)
0:100 direct index (smooth mediump 4-component vector of float)
0:100 'v' (smooth in 3-element array of mediump 4-component vector of float)
0:100 Constant:
0:100 0 (const int)
0:101 Constant:
0:101 0.000000
0:102 fwidth (mediump float)
0:102 'f13' (invariant mediump float)
0:? Linker Objects 0:? Linker Objects
0:? 'a' (3-element array of mediump int) 0:? 'a' (3-element array of mediump int)
0:? 'uint' (mediump int) 0:? 'uint' (mediump int)

View File

@ -42,8 +42,10 @@
// Where to put a built-in: // Where to put a built-in:
// TBuiltIns::initialize(version,profile) context-independent textual built-ins; add them to the right string // TBuiltIns::initialize(version,profile) context-independent textual built-ins; add them to the right string
// TBuiltIns::initialize(resources,...) context-dependent textual built-ins; add them to the right string // TBuiltIns::initialize(resources,...) context-dependent textual built-ins; add them to the right string
// IdentifyBuiltIns(...,symbolTable) context-independent programmatic additions/mappings to the symbol table // IdentifyBuiltIns(...,symbolTable) context-independent programmatic additions/mappings to the symbol table,
// IdentifyBuiltIns(...,symbolTable, resources) context-dependent programmatic additions/mappings to the symbol table // including identify what extensions are needed if a version does not allow a symbol
// IdentifyBuiltIns(...,symbolTable, resources) context-dependent programmatic additions/mappings to the symbol table,
// including identify what extensions are needed if a version does not allow a symbol
// //
#include "../Include/intermediate.h" #include "../Include/intermediate.h"
@ -2120,8 +2122,8 @@ void SpecialQualifier(const char* name, TStorageQualifier qualifier, TSymbolTabl
void IdentifyBuiltIns(int version, EProfile profile, EShLanguage language, TSymbolTable& symbolTable) void IdentifyBuiltIns(int version, EProfile profile, EShLanguage language, TSymbolTable& symbolTable)
{ {
// //
// First, insert some special built-in variables that are not in // Tag built-in variables and functions with additional qualifier and extension information
// the built-in text strings. // that cannot be declared with the text strings.
// //
switch(language) { switch(language) {
case EShLangVertex: case EShLangVertex:
@ -2141,6 +2143,11 @@ void IdentifyBuiltIns(int version, EProfile profile, EShLanguage language, TSymb
SpecialQualifier("gl_PointCoord", EvqPointCoord, symbolTable); SpecialQualifier("gl_PointCoord", EvqPointCoord, symbolTable);
SpecialQualifier("gl_FragColor", EvqFragColor, symbolTable); SpecialQualifier("gl_FragColor", EvqFragColor, symbolTable);
SpecialQualifier("gl_FragDepth", EvqFragDepth, symbolTable); SpecialQualifier("gl_FragDepth", EvqFragDepth, symbolTable);
if (version == 100) {
symbolTable.setFunctionExtensions("dFdx", 1, &GL_OES_standard_derivatives);
symbolTable.setFunctionExtensions("dFdy", 1, &GL_OES_standard_derivatives);
symbolTable.setFunctionExtensions("fwidth", 1, &GL_OES_standard_derivatives);
}
break; break;
case EShLangCompute: case EShLangCompute:

View File

@ -385,6 +385,10 @@ TIntermTyped* TParseContext::handleVariable(TSourceLoc loc, TSymbol* symbol, TSt
{ {
TIntermTyped* node = 0; TIntermTyped* node = 0;
// Error check for function requiring specific extensions present.
if (symbol && symbol->getNumExtensions())
requireExtensions(loc, symbol->getNumExtensions(), symbol->getExtensions(), symbol->getName().c_str());
const TAnonMember* anon = symbol ? symbol->getAsAnonMember() : 0; const TAnonMember* anon = symbol ? symbol->getAsAnonMember() : 0;
if (anon) { if (anon) {
// it was a member of an anonymous container, have to insert its dereference // it was a member of an anonymous container, have to insert its dereference
@ -903,6 +907,10 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCal
bool builtIn; bool builtIn;
fnCandidate = findFunction(loc, *fnCall, builtIn); fnCandidate = findFunction(loc, *fnCall, builtIn);
if (fnCandidate) { if (fnCandidate) {
// Error check for function requiring specific extensions present.
if (builtIn && fnCandidate->getNumExtensions())
requireExtensions(loc, fnCandidate->getNumExtensions(), fnCandidate->getExtensions(), fnCandidate->getName().c_str());
// //
// A declared function. But, it might still map to a built-in // A declared function. But, it might still map to a built-in
// operation. // operation.

View File

@ -185,6 +185,7 @@ public:
void requireStage(TSourceLoc, EShLanguage, const char *featureDesc); void requireStage(TSourceLoc, EShLanguage, const char *featureDesc);
void checkDeprecated(TSourceLoc, int queryProfiles, int depVersion, const char *featureDesc); void checkDeprecated(TSourceLoc, int queryProfiles, int depVersion, const char *featureDesc);
void requireNotRemoved(TSourceLoc, int queryProfiles, int removedVersion, const char *featureDesc); void requireNotRemoved(TSourceLoc, int queryProfiles, int removedVersion, const char *featureDesc);
void requireExtensions(TSourceLoc, int numExtensions, const char* const extensions[], const char *featureDesc);
TExtensionBehavior getExtensionBehavior(const char*); TExtensionBehavior getExtensionBehavior(const char*);
bool extensionsTurnedOn(int numExtensions, const char* const extensions[]); bool extensionsTurnedOn(int numExtensions, const char* const extensions[]);
void updateExtensionBehavior(const char* const extension, const char* behavior); void updateExtensionBehavior(const char* const extension, const char* behavior);

View File

@ -207,6 +207,23 @@ void TSymbolTableLevel::relateToOperator(const char* name, TOperator op)
} }
} }
// Make all function overloads of the given name require an extension(s).
// Should only be used for a version/profile that actually needs the extension(s).
void TSymbolTableLevel::setFunctionExtensions(const char* name, int num, const char* const extensions[])
{
tLevel::const_iterator candidate = level.lower_bound(name);
while (candidate != level.end()) {
const TString& candidateName = (*candidate).first;
TString::size_type parenAt = candidateName.find_first_of('(');
if (parenAt != candidateName.npos && candidateName.compare(0, parenAt, name) == 0) {
TSymbol* symbol = candidate->second;
symbol->setExtensions(num, extensions);
} else
break;
++candidate;
}
}
// //
// Make all symbols in this table level read only. // Make all symbols in this table level read only.
// //
@ -230,6 +247,8 @@ TVariable::TVariable(const TVariable& copyOf) : TSymbol(copyOf)
{ {
type.deepCopy(copyOf.type); type.deepCopy(copyOf.type);
userType = copyOf.userType; userType = copyOf.userType;
extensions = 0;
setExtensions(copyOf.numExtensions, copyOf.extensions);
if (! copyOf.unionArray.empty()) { if (! copyOf.unionArray.empty()) {
assert(!copyOf.type.getStruct()); assert(!copyOf.type.getStruct());
@ -255,6 +274,8 @@ TFunction::TFunction(const TFunction& copyOf) : TSymbol(copyOf)
parameters.back().copyParam(copyOf.parameters[i]); parameters.back().copyParam(copyOf.parameters[i]);
} }
extensions = 0;
setExtensions(copyOf.numExtensions, copyOf.extensions);
returnType.deepCopy(copyOf.returnType); returnType.deepCopy(copyOf.returnType);
mangledName = copyOf.mangledName; mangledName = copyOf.mangledName;
op = copyOf.op; op = copyOf.op;

View File

@ -81,9 +81,9 @@ class TAnonMember;
class TSymbol { class TSymbol {
public: public:
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
explicit TSymbol(const TString *n) : name(n), writable(true) { } explicit TSymbol(const TString *n) : name(n), writable(true), numExtensions(0), extensions(0) { }
virtual TSymbol* clone() const = 0; virtual TSymbol* clone() const = 0;
virtual ~TSymbol() { } virtual ~TSymbol() { delete [] extensions; }
virtual const TString& getName() const { return *name; } virtual const TString& getName() const { return *name; }
virtual void changeName(const TString* newName) { name = newName; } virtual void changeName(const TString* newName) { name = newName; }
@ -97,6 +97,16 @@ public:
virtual TType& getWritableType() = 0; virtual TType& getWritableType() = 0;
virtual void setUniqueId(int id) { uniqueId = id; } virtual void setUniqueId(int id) { uniqueId = id; }
virtual int getUniqueId() const { return uniqueId; } virtual int getUniqueId() const { return uniqueId; }
virtual void setExtensions(int num, const char* const exts[])
{
assert(extensions == 0);
numExtensions = num;
extensions = new const char*[numExtensions];
for (int e = 0; e < num; ++e)
extensions[e] = exts[e];
}
virtual int getNumExtensions() const { return numExtensions; }
virtual const char** getExtensions() const { return extensions; }
virtual void dump(TInfoSink &infoSink) const = 0; virtual void dump(TInfoSink &infoSink) const = 0;
virtual bool isReadOnly() const { return ! writable; } virtual bool isReadOnly() const { return ! writable; }
@ -109,6 +119,11 @@ protected:
const TString *name; const TString *name;
unsigned int uniqueId; // For cross-scope comparing during code generation unsigned int uniqueId; // For cross-scope comparing during code generation
// For tracking what extensions must be present
// (don't use if correct version/profile is present).
int numExtensions;
const char** extensions; // an array of pointers to existing constant char strings
// //
// N.B.: Non-const functions that will be generally used should assert an this, // N.B.: Non-const functions that will be generally used should assert an this,
// to avoid overwriting shared symbol-table information. // to avoid overwriting shared symbol-table information.
@ -376,6 +391,7 @@ public:
} }
void relateToOperator(const char* name, TOperator op); void relateToOperator(const char* name, TOperator op);
void setFunctionExtensions(const char* name, int num, const char* const extensions[]);
void dump(TInfoSink &infoSink) const; void dump(TInfoSink &infoSink) const;
TSymbolTableLevel* clone() const; TSymbolTableLevel* clone() const;
void readOnly(); void readOnly();
@ -551,6 +567,12 @@ public:
for (unsigned int level = 0; level < table.size(); ++level) for (unsigned int level = 0; level < table.size(); ++level)
table[level]->relateToOperator(name, op); table[level]->relateToOperator(name, op);
} }
void setFunctionExtensions(const char* name, int num, const char* const extensions[])
{
for (unsigned int level = 0; level < table.size(); ++level)
table[level]->setFunctionExtensions(name, num, extensions);
}
int getMaxSymbolId() { return uniqueId; } int getMaxSymbolId() { return uniqueId; }
void dump(TInfoSink &infoSink) const; void dump(TInfoSink &infoSink) const;

View File

@ -60,6 +60,7 @@
// requireStage() // requireStage()
// checkDeprecated() // checkDeprecated()
// requireNotRemoved() // requireNotRemoved()
// requireExtensions()
// //
// Typically, only the first two calls are needed. They go into a code path that // 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 // implements Feature F, and will log the proper error/warning messages. Parsing
@ -129,8 +130,12 @@
// //
// ~EEsProfile // ~EEsProfile
// //
// 6) If built-in symbols are added by the extension, add them in Initialize.cpp; see // 6) If built-in symbols are added by the extension, add them in Initialize.cpp: Their use
// the comment at the top of that file for where to put them. // will be automatically error checked against the extensions enabled at that moment.
// see the comment at the top of Initialize.cpp for where to put them. Establish them at
// the earliest release that supports the extension. Then, tag them with the
// set of extensions that both enable them and are necessary, given the version of the symbol
// table. (There is a different symbol table for each version.)
// //
#include "ParseHelper.h" #include "ParseHelper.h"
@ -145,6 +150,7 @@ namespace glslang {
void TParseContext::initializeExtensionBehavior() void TParseContext::initializeExtensionBehavior()
{ {
extensionBehavior[GL_OES_texture_3D] = EBhDisable; extensionBehavior[GL_OES_texture_3D] = EBhDisable;
extensionBehavior[GL_OES_standard_derivatives] = EBhDisable;
extensionBehavior[GL_ARB_texture_rectangle] = EBhDisable; extensionBehavior[GL_ARB_texture_rectangle] = EBhDisable;
extensionBehavior[GL_3DL_array_objects] = EBhDisable; extensionBehavior[GL_3DL_array_objects] = EBhDisable;
@ -159,8 +165,9 @@ const char* TParseContext::getPreamble()
{ {
if (profile == EEsProfile) { if (profile == EEsProfile) {
return return
"#define GL_ES 1\n"
"#define GL_OES_texture_3D 1\n" "#define GL_OES_texture_3D 1\n"
"#define GL_ES 1\n"; "#define GL_OES_standard_derivatives 1\n";
} else { } else {
return return
"#define GL_FRAGMENT_PRECISION_HIGH 1\n" "#define GL_FRAGMENT_PRECISION_HIGH 1\n"
@ -316,6 +323,41 @@ void TParseContext::requireNotRemoved(TSourceLoc loc, int profileMask, int remov
} }
} }
//
// Use when there are no profile/version to check, it's just an error if one of the
// extensions is not present.
//
void TParseContext::requireExtensions(TSourceLoc loc, int numExtensions, const char* const extensions[], const char *featureDesc)
{
// First, see if any of the extensions are enabled
for (int i = 0; i < numExtensions; ++i) {
TExtensionBehavior behavior = getExtensionBehavior(extensions[i]);
if (behavior == EBhEnable || behavior == EBhRequire)
return;
}
// See if any extensions want to give a warning on use; give warnings for all such extensions
bool warned = false;
for (int i = 0; i < numExtensions; ++i) {
TExtensionBehavior behavior = getExtensionBehavior(extensions[i]);
if (behavior == EBhWarn) {
infoSink.info.message(EPrefixWarning, ("extension " + TString(extensions[i]) + " is being used for " + featureDesc).c_str(), loc);
warned = true;
}
}
if (warned)
return;
// If we get this far, give errors explaining what extensions are needed
if (numExtensions == 1)
error(loc, "required extension not requested:", featureDesc, extensions[0]);
else {
error(loc, "required extension not requested:", featureDesc, "Possible extensions include:");
for (int i = 0; i < numExtensions; ++i)
infoSink.info.message(EPrefixNone, extensions[i]);
}
}
TExtensionBehavior TParseContext::getExtensionBehavior(const char* extension) TExtensionBehavior TParseContext::getExtensionBehavior(const char* extension)
{ {
TMap<TString, TExtensionBehavior>::iterator iter = extensionBehavior.find(TString(extension)); TMap<TString, TExtensionBehavior>::iterator iter = extensionBehavior.find(TString(extension));
@ -375,12 +417,12 @@ void TParseContext::updateExtensionBehavior(const char* extension, const char* b
if (iter == extensionBehavior.end()) { if (iter == extensionBehavior.end()) {
switch (behavior) { switch (behavior) {
case EBhRequire: case EBhRequire:
error(getCurrentLoc(), "extension not supported", "#extension", extension); error(getCurrentLoc(), "extension not supported:", "#extension", extension);
break; break;
case EBhEnable: case EBhEnable:
case EBhWarn: case EBhWarn:
case EBhDisable: case EBhDisable:
warn(getCurrentLoc(), "extension not supported", "#extension", extension); warn(getCurrentLoc(), "extension not supported:", "#extension", extension);
break; break;
default: default:
assert(0 && "unexpected behavior"); assert(0 && "unexpected behavior");

View File

@ -73,7 +73,7 @@ typedef enum {
// functions, but better to have the compiler do spelling checks. // functions, but better to have the compiler do spelling checks.
// //
const char* const GL_OES_texture_3D = "GL_OES_texture_3D"; const char* const GL_OES_texture_3D = "GL_OES_texture_3D";
const char* const GL_OES_standard_derivatives = "GL_OES_standard_derivatives";
const char* const GL_ARB_texture_rectangle = "GL_ARB_texture_rectangle"; const char* const GL_ARB_texture_rectangle = "GL_ARB_texture_rectangle";
const char* const GL_3DL_array_objects = "GL_3DL_array_objects"; const char* const GL_3DL_array_objects = "GL_3DL_array_objects";