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:
parent
115a0adc29
commit
06a37c3964
@ -88,4 +88,16 @@ void foo234()
|
||||
{
|
||||
texture3D(s3D2, vec3(0.2), 0.2);
|
||||
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);
|
||||
}
|
||||
|
||||
@ -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:80: 'sampler3D' : Reserved word.
|
||||
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!
|
||||
0:3 Sequence
|
||||
@ -142,6 +145,27 @@ ERROR: node is still EOpNull!
|
||||
0:90 1 (const int)
|
||||
0:90 Constant:
|
||||
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:? 'a' (3-element array of mediump int)
|
||||
0:? 'uint' (mediump int)
|
||||
|
||||
@ -42,8 +42,10 @@
|
||||
// Where to put a built-in:
|
||||
// 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
|
||||
// IdentifyBuiltIns(...,symbolTable) context-independent programmatic additions/mappings to the symbol table
|
||||
// IdentifyBuiltIns(...,symbolTable, resources) context-dependent programmatic additions/mappings to the symbol table
|
||||
// IdentifyBuiltIns(...,symbolTable) context-independent 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"
|
||||
@ -2120,8 +2122,8 @@ void SpecialQualifier(const char* name, TStorageQualifier qualifier, TSymbolTabl
|
||||
void IdentifyBuiltIns(int version, EProfile profile, EShLanguage language, TSymbolTable& symbolTable)
|
||||
{
|
||||
//
|
||||
// First, insert some special built-in variables that are not in
|
||||
// the built-in text strings.
|
||||
// Tag built-in variables and functions with additional qualifier and extension information
|
||||
// that cannot be declared with the text strings.
|
||||
//
|
||||
switch(language) {
|
||||
case EShLangVertex:
|
||||
@ -2141,6 +2143,11 @@ void IdentifyBuiltIns(int version, EProfile profile, EShLanguage language, TSymb
|
||||
SpecialQualifier("gl_PointCoord", EvqPointCoord, symbolTable);
|
||||
SpecialQualifier("gl_FragColor", EvqFragColor, 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;
|
||||
|
||||
case EShLangCompute:
|
||||
|
||||
@ -385,6 +385,10 @@ TIntermTyped* TParseContext::handleVariable(TSourceLoc loc, TSymbol* symbol, TSt
|
||||
{
|
||||
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;
|
||||
if (anon) {
|
||||
// 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;
|
||||
fnCandidate = findFunction(loc, *fnCall, builtIn);
|
||||
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
|
||||
// operation.
|
||||
|
||||
@ -185,6 +185,7 @@ public:
|
||||
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 requireExtensions(TSourceLoc, int numExtensions, const char* const extensions[], const char *featureDesc);
|
||||
TExtensionBehavior getExtensionBehavior(const char*);
|
||||
bool extensionsTurnedOn(int numExtensions, const char* const extensions[]);
|
||||
void updateExtensionBehavior(const char* const extension, const char* behavior);
|
||||
|
||||
@ -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.
|
||||
//
|
||||
@ -230,6 +247,8 @@ TVariable::TVariable(const TVariable& copyOf) : TSymbol(copyOf)
|
||||
{
|
||||
type.deepCopy(copyOf.type);
|
||||
userType = copyOf.userType;
|
||||
extensions = 0;
|
||||
setExtensions(copyOf.numExtensions, copyOf.extensions);
|
||||
|
||||
if (! copyOf.unionArray.empty()) {
|
||||
assert(!copyOf.type.getStruct());
|
||||
@ -255,6 +274,8 @@ TFunction::TFunction(const TFunction& copyOf) : TSymbol(copyOf)
|
||||
parameters.back().copyParam(copyOf.parameters[i]);
|
||||
}
|
||||
|
||||
extensions = 0;
|
||||
setExtensions(copyOf.numExtensions, copyOf.extensions);
|
||||
returnType.deepCopy(copyOf.returnType);
|
||||
mangledName = copyOf.mangledName;
|
||||
op = copyOf.op;
|
||||
|
||||
@ -81,9 +81,9 @@ class TAnonMember;
|
||||
class TSymbol {
|
||||
public:
|
||||
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() { }
|
||||
virtual ~TSymbol() { delete [] extensions; }
|
||||
|
||||
virtual const TString& getName() const { return *name; }
|
||||
virtual void changeName(const TString* newName) { name = newName; }
|
||||
@ -97,6 +97,16 @@ public:
|
||||
virtual TType& getWritableType() = 0;
|
||||
virtual void setUniqueId(int id) { uniqueId = id; }
|
||||
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 bool isReadOnly() const { return ! writable; }
|
||||
@ -109,6 +119,11 @@ protected:
|
||||
const TString *name;
|
||||
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,
|
||||
// to avoid overwriting shared symbol-table information.
|
||||
@ -376,6 +391,7 @@ public:
|
||||
}
|
||||
|
||||
void relateToOperator(const char* name, TOperator op);
|
||||
void setFunctionExtensions(const char* name, int num, const char* const extensions[]);
|
||||
void dump(TInfoSink &infoSink) const;
|
||||
TSymbolTableLevel* clone() const;
|
||||
void readOnly();
|
||||
@ -552,6 +568,12 @@ public:
|
||||
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; }
|
||||
void dump(TInfoSink &infoSink) const;
|
||||
void copyTable(const TSymbolTable& copyOf);
|
||||
|
||||
@ -60,6 +60,7 @@
|
||||
// requireStage()
|
||||
// checkDeprecated()
|
||||
// requireNotRemoved()
|
||||
// requireExtensions()
|
||||
//
|
||||
// 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
|
||||
@ -129,8 +130,12 @@
|
||||
//
|
||||
// ~EEsProfile
|
||||
//
|
||||
// 6) If built-in symbols are added by the extension, add them in Initialize.cpp; see
|
||||
// the comment at the top of that file for where to put them.
|
||||
// 6) If built-in symbols are added by the extension, add them in Initialize.cpp: Their use
|
||||
// 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"
|
||||
@ -145,6 +150,7 @@ namespace glslang {
|
||||
void TParseContext::initializeExtensionBehavior()
|
||||
{
|
||||
extensionBehavior[GL_OES_texture_3D] = EBhDisable;
|
||||
extensionBehavior[GL_OES_standard_derivatives] = EBhDisable;
|
||||
|
||||
extensionBehavior[GL_ARB_texture_rectangle] = EBhDisable;
|
||||
extensionBehavior[GL_3DL_array_objects] = EBhDisable;
|
||||
@ -159,8 +165,9 @@ const char* TParseContext::getPreamble()
|
||||
{
|
||||
if (profile == EEsProfile) {
|
||||
return
|
||||
"#define GL_ES 1\n"
|
||||
"#define GL_OES_texture_3D 1\n"
|
||||
"#define GL_ES 1\n";
|
||||
"#define GL_OES_standard_derivatives 1\n";
|
||||
} else {
|
||||
return
|
||||
"#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)
|
||||
{
|
||||
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()) {
|
||||
switch (behavior) {
|
||||
case EBhRequire:
|
||||
error(getCurrentLoc(), "extension not supported", "#extension", extension);
|
||||
error(getCurrentLoc(), "extension not supported:", "#extension", extension);
|
||||
break;
|
||||
case EBhEnable:
|
||||
case EBhWarn:
|
||||
case EBhDisable:
|
||||
warn(getCurrentLoc(), "extension not supported", "#extension", extension);
|
||||
warn(getCurrentLoc(), "extension not supported:", "#extension", extension);
|
||||
break;
|
||||
default:
|
||||
assert(0 && "unexpected behavior");
|
||||
|
||||
@ -73,7 +73,7 @@ typedef enum {
|
||||
// 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_standard_derivatives = "GL_OES_standard_derivatives";
|
||||
|
||||
const char* const GL_ARB_texture_rectangle = "GL_ARB_texture_rectangle";
|
||||
const char* const GL_3DL_array_objects = "GL_3DL_array_objects";
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user