Share built-in symbols common to all stages for desktop (but still per profile per version).
git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@22662 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
parent
c027579631
commit
99a0576225
@ -78,35 +78,38 @@ int MapVersionToIndex(int version)
|
|||||||
} // V
|
} // V
|
||||||
const int VersionCount = 12;
|
const int VersionCount = 12;
|
||||||
|
|
||||||
//
|
// only one of these needed for non-ES; ES needs 2 for different precision defaults of built-ins
|
||||||
// A process-global symbol table per version per profile per language. This will be sparsely
|
enum EPrecisionClass {
|
||||||
|
EPcGeneral,
|
||||||
|
EPcFragment,
|
||||||
|
EPcCount
|
||||||
|
};
|
||||||
|
|
||||||
|
// A process-global symbol table per version per profile for built-ins common
|
||||||
|
// to multiple stages (languages), and a process-global symbol table per version
|
||||||
|
// per profile per stage for built-ins unique to each stage. They will be sparsely
|
||||||
// populated, so they will only only be generated as needed.
|
// populated, so they will only only be generated as needed.
|
||||||
//
|
//
|
||||||
// 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* SharedSymbolTables[VersionCount][EProfileCount][EShLangCount] = {};
|
TSymbolTable* SharedSymbolTables[VersionCount][EProfileCount][EShLangCount] = {};
|
||||||
|
|
||||||
TPoolAllocator* PerProcessGPA = 0;
|
TPoolAllocator* PerProcessGPA = 0;
|
||||||
|
|
||||||
bool InitializeSymbolTable(const TBuiltIns& builtIns, int version, EProfile profile, EShLanguage language, TInfoSink& infoSink,
|
bool InitializeSymbolTable(const TString& builtIns, int version, EProfile profile, EShLanguage language, TInfoSink& infoSink,
|
||||||
const TBuiltInResource* resources, TSymbolTable* symbolTables)
|
TSymbolTable& symbolTable)
|
||||||
{
|
{
|
||||||
TIntermediate intermediate(infoSink, version, profile);
|
TIntermediate intermediate(infoSink, version, profile);
|
||||||
TSymbolTable* symbolTable;
|
|
||||||
|
|
||||||
if (resources)
|
TParseContext parseContext(symbolTable, intermediate, true, version, profile, language, infoSink);
|
||||||
symbolTable = symbolTables;
|
|
||||||
else
|
|
||||||
symbolTable = &symbolTables[language];
|
|
||||||
|
|
||||||
TParseContext parseContext(*symbolTable, intermediate, true, version, profile, language, infoSink);
|
|
||||||
TPpContext ppContext(parseContext);
|
TPpContext ppContext(parseContext);
|
||||||
glslang::TScanContext scanContext(parseContext);
|
glslang::TScanContext scanContext(parseContext);
|
||||||
parseContext.scanContext = &scanContext;
|
parseContext.scanContext = &scanContext;
|
||||||
parseContext.ppContext = &ppContext;
|
parseContext.ppContext = &ppContext;
|
||||||
|
|
||||||
assert(symbolTable->isEmpty() || symbolTable->atSharedBuiltInLevel());
|
assert(symbolTable.isEmpty() || symbolTable.atSharedBuiltInLevel());
|
||||||
|
|
||||||
//
|
//
|
||||||
// Parse the built-ins. This should only happen once per
|
// Parse the built-ins. This should only happen once per
|
||||||
@ -117,55 +120,72 @@ bool InitializeSymbolTable(const TBuiltIns& builtIns, int version, EProfile prof
|
|||||||
// are preserved, and the test for an empty table fails.
|
// are preserved, and the test for an empty table fails.
|
||||||
//
|
//
|
||||||
|
|
||||||
symbolTable->push();
|
symbolTable.push();
|
||||||
|
|
||||||
const char* builtInShaders[2];
|
const char* builtInShaders[2];
|
||||||
int builtInLengths[2];
|
int builtInLengths[2];
|
||||||
builtInShaders[0] = builtIns.getCommonString().c_str();
|
builtInShaders[0] = builtIns.c_str();
|
||||||
builtInLengths[0] = builtIns.getCommonString().size();
|
builtInLengths[0] = builtIns.size();
|
||||||
builtInShaders[1] = builtIns.getStageString(language).c_str();
|
|
||||||
builtInLengths[1] = builtIns.getStageString(language).size();
|
|
||||||
|
|
||||||
if (! parseContext.parseShaderStrings(ppContext, const_cast<char**>(builtInShaders), builtInLengths, 2) != 0) {
|
if (! parseContext.parseShaderStrings(ppContext, const_cast<char**>(builtInShaders), builtInLengths, 1) != 0) {
|
||||||
infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
|
infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
|
||||||
printf("Unable to parse built-ins\n");
|
printf("Unable to parse built-ins\n");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resources)
|
|
||||||
IdentifyBuiltIns(version, profile, parseContext.language, *symbolTable, *resources);
|
|
||||||
else
|
|
||||||
IdentifyBuiltIns(version, profile, parseContext.language, *symbolTable);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GenerateBuiltInSymbolTable(TInfoSink& infoSink, TSymbolTable* symbolTables, int version, EProfile profile)
|
//
|
||||||
|
// To call for per-stage initialization, with the common table already complete.
|
||||||
|
//
|
||||||
|
void InitializeSymbolTable(TBuiltIns& builtIns, int version, EProfile profile, EShLanguage language, TInfoSink& infoSink, TSymbolTable* commonTable, TSymbolTable* symbolTables)
|
||||||
|
{
|
||||||
|
int commonIndex = EPcGeneral;
|
||||||
|
if (profile == EEsProfile && language == EShLangFragment)
|
||||||
|
commonIndex = EPcFragment;
|
||||||
|
|
||||||
|
symbolTables[language].adoptLevels(commonTable[commonIndex]);
|
||||||
|
InitializeSymbolTable(builtIns.getStageString(language), version, profile, language, infoSink, symbolTables[language]);
|
||||||
|
IdentifyBuiltIns(version, profile, language, symbolTables[language]);
|
||||||
|
if (profile == EEsProfile)
|
||||||
|
symbolTables[language].setNoBuiltInRedeclarations();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GenerateBuiltInSymbolTable(TInfoSink& infoSink, TSymbolTable* commonTable, TSymbolTable* symbolTables, int version, EProfile profile)
|
||||||
{
|
{
|
||||||
TBuiltIns builtIns;
|
TBuiltIns builtIns;
|
||||||
|
|
||||||
builtIns.initialize(version, profile);
|
builtIns.initialize(version, profile);
|
||||||
InitializeSymbolTable(builtIns, version, profile, EShLangVertex, infoSink, 0, symbolTables);
|
|
||||||
|
// do the common table
|
||||||
|
InitializeSymbolTable(builtIns.getCommonString(), version, profile, EShLangVertex, infoSink, commonTable[EPcGeneral]);
|
||||||
|
if (profile == EEsProfile)
|
||||||
|
InitializeSymbolTable(builtIns.getCommonString(), version, profile, EShLangFragment, infoSink, commonTable[EPcFragment]);
|
||||||
|
|
||||||
|
// do the per-stage tables
|
||||||
|
InitializeSymbolTable(builtIns, version, profile, EShLangVertex, infoSink, commonTable, symbolTables);
|
||||||
|
InitializeSymbolTable(builtIns, version, profile, EShLangFragment, infoSink, commonTable, symbolTables);
|
||||||
if (profile != EEsProfile && version >= 400) {
|
if (profile != EEsProfile && version >= 400) {
|
||||||
InitializeSymbolTable(builtIns, version, profile, EShLangTessControl, infoSink, 0, symbolTables);
|
InitializeSymbolTable(builtIns, version, profile, EShLangTessControl, infoSink, commonTable, symbolTables);
|
||||||
InitializeSymbolTable(builtIns, version, profile, EShLangTessEvaluation, infoSink, 0, symbolTables);
|
InitializeSymbolTable(builtIns, version, profile, EShLangTessEvaluation, infoSink, commonTable, symbolTables);
|
||||||
}
|
}
|
||||||
if (profile != EEsProfile && version >= 150)
|
if (profile != EEsProfile && version >= 150)
|
||||||
InitializeSymbolTable(builtIns, version, profile, EShLangGeometry, infoSink, 0, symbolTables);
|
InitializeSymbolTable(builtIns, version, profile, EShLangGeometry, infoSink, commonTable, symbolTables);
|
||||||
InitializeSymbolTable(builtIns, version, profile, EShLangFragment, infoSink, 0, symbolTables);
|
|
||||||
if (profile != EEsProfile && version >= 430)
|
if (profile != EEsProfile && version >= 430)
|
||||||
InitializeSymbolTable(builtIns, version, profile, EShLangCompute, infoSink, 0, symbolTables);
|
InitializeSymbolTable(builtIns, version, profile, EShLangCompute, infoSink, commonTable, symbolTables);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AddContextSpecificSymbols(const TBuiltInResource* resources, TInfoSink& infoSink, TSymbolTable* symbolTables, int version, EProfile profile, EShLanguage language)
|
bool AddContextSpecificSymbols(const TBuiltInResource* resources, TInfoSink& infoSink, TSymbolTable& symbolTable, int version, EProfile profile, EShLanguage language)
|
||||||
{
|
{
|
||||||
TBuiltIns builtIns;
|
TBuiltIns builtIns;
|
||||||
|
|
||||||
builtIns.initialize(*resources, version, profile, language);
|
builtIns.initialize(*resources, version, profile, language);
|
||||||
InitializeSymbolTable(builtIns, version, profile, language, infoSink, resources, symbolTables);
|
InitializeSymbolTable(builtIns.getCommonString(), version, profile, language, infoSink, symbolTable);
|
||||||
|
IdentifyBuiltIns(version, profile, language, symbolTable, *resources);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -189,9 +209,9 @@ void SetupBuiltinSymbolTable(int version, EProfile profile)
|
|||||||
// Make sure only one thread tries to do this at a time
|
// Make sure only one thread tries to do this at a time
|
||||||
glslang::GetGlobalLock();
|
glslang::GetGlobalLock();
|
||||||
|
|
||||||
// See if it's already been done.
|
// See if it's already been done for this version/profile combination
|
||||||
int versionIndex = MapVersionToIndex(version);
|
int versionIndex = MapVersionToIndex(version);
|
||||||
if (SharedSymbolTables[versionIndex][profile][EShLangVertex]) {
|
if (CommonSymbolTable[versionIndex][profile][EPcGeneral]) {
|
||||||
glslang::ReleaseGlobalLock();
|
glslang::ReleaseGlobalLock();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -202,25 +222,34 @@ void SetupBuiltinSymbolTable(int version, EProfile profile)
|
|||||||
TPoolAllocator* builtInPoolAllocator = new TPoolAllocator();
|
TPoolAllocator* builtInPoolAllocator = new TPoolAllocator();
|
||||||
SetThreadPoolAllocator(*builtInPoolAllocator);
|
SetThreadPoolAllocator(*builtInPoolAllocator);
|
||||||
|
|
||||||
// Generate the symbol table using the new pool
|
// Generate the local symbol tables using the new pool
|
||||||
TSymbolTable symTables[EShLangCount];
|
TSymbolTable commonTable[2];
|
||||||
if (profile == EEsProfile) {
|
TSymbolTable stageTables[EShLangCount];
|
||||||
for (int stage = 0; stage < EShLangCount; ++stage)
|
GenerateBuiltInSymbolTable(infoSink, commonTable, stageTables, version, profile);
|
||||||
symTables[stage].setNoBuiltInRedeclarations();
|
|
||||||
}
|
|
||||||
GenerateBuiltInSymbolTable(infoSink, symTables, version, profile);
|
|
||||||
|
|
||||||
// Switch to the process-global pool
|
// Switch to the process-global pool
|
||||||
SetThreadPoolAllocator(*PerProcessGPA);
|
SetThreadPoolAllocator(*PerProcessGPA);
|
||||||
|
|
||||||
// Copy the symbol table from the new pool to 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) {
|
||||||
|
if (! commonTable[precClass].isEmpty()) {
|
||||||
|
CommonSymbolTable[versionIndex][profile][precClass] = new TSymbolTable;
|
||||||
|
CommonSymbolTable[versionIndex][profile][precClass]->copyTable(commonTable[precClass]);
|
||||||
|
}
|
||||||
|
}
|
||||||
for (int stage = 0; stage < EShLangCount; ++stage) {
|
for (int stage = 0; stage < EShLangCount; ++stage) {
|
||||||
if (! symTables[stage].isEmpty()) {
|
if (! stageTables[stage].isEmpty()) {
|
||||||
SharedSymbolTables[versionIndex][profile][stage] = new TSymbolTable;
|
SharedSymbolTables[versionIndex][profile][stage] = new TSymbolTable;
|
||||||
SharedSymbolTables[versionIndex][profile][stage]->copyTable(symTables[stage]);
|
SharedSymbolTables[versionIndex][profile][stage]->copyTable(stageTables[stage]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Explicitly clean up the local tables before deleting the pool they used and before releasing the lock.
|
||||||
|
for (int precClass = 0; precClass < EPcCount; ++precClass)
|
||||||
|
commonTable[precClass].~TSymbolTable();
|
||||||
|
for (int stage = 0; stage < EShLangCount; ++stage)
|
||||||
|
stageTables[stage].~TSymbolTable();
|
||||||
|
|
||||||
delete builtInPoolAllocator;
|
delete builtInPoolAllocator;
|
||||||
SetThreadPoolAllocator(savedGPA);
|
SetThreadPoolAllocator(savedGPA);
|
||||||
|
|
||||||
@ -429,18 +458,13 @@ int ShCompile(
|
|||||||
TSymbolTable* cachedTable = SharedSymbolTables[MapVersionToIndex(version)]
|
TSymbolTable* cachedTable = SharedSymbolTables[MapVersionToIndex(version)]
|
||||||
[profile]
|
[profile]
|
||||||
[compiler->getLanguage()];
|
[compiler->getLanguage()];
|
||||||
TSymbolTable* errorTable = 0;
|
TSymbolTable symbolTable;
|
||||||
if (! cachedTable) {
|
if (cachedTable)
|
||||||
errorTable = new TSymbolTable;
|
symbolTable.adoptLevels(*cachedTable);
|
||||||
cachedTable = errorTable;
|
|
||||||
}
|
|
||||||
TSymbolTable symbolTable(*cachedTable);
|
|
||||||
if (errorTable)
|
|
||||||
delete errorTable;
|
|
||||||
|
|
||||||
// Add built-in symbols that are potentially context dependent;
|
// Add built-in symbols that are potentially context dependent;
|
||||||
// they get popped again further down.
|
// they get popped again further down.
|
||||||
AddContextSpecificSymbols(resources, compiler->infoSink, &symbolTable, version, profile, compiler->getLanguage());
|
AddContextSpecificSymbols(resources, compiler->infoSink, symbolTable, version, profile, compiler->getLanguage());
|
||||||
|
|
||||||
TParseContext parseContext(symbolTable, intermediate, false, version, profile, compiler->getLanguage(), compiler->infoSink, forwardCompatible, messages);
|
TParseContext parseContext(symbolTable, intermediate, false, version, profile, compiler->getLanguage(), compiler->infoSink, forwardCompatible, messages);
|
||||||
glslang::TScanContext scanContext(parseContext);
|
glslang::TScanContext scanContext(parseContext);
|
||||||
|
|||||||
@ -246,7 +246,7 @@ protected:
|
|||||||
class TSymbolTableLevel {
|
class TSymbolTableLevel {
|
||||||
public:
|
public:
|
||||||
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
|
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
|
||||||
TSymbolTableLevel() : defaultPrecision (0), anonId(0) { }
|
TSymbolTableLevel() : defaultPrecision(0), anonId(0) { }
|
||||||
~TSymbolTableLevel();
|
~TSymbolTableLevel();
|
||||||
|
|
||||||
bool insert(TSymbol& symbol)
|
bool insert(TSymbol& symbol)
|
||||||
@ -365,21 +365,12 @@ protected:
|
|||||||
|
|
||||||
class TSymbolTable {
|
class TSymbolTable {
|
||||||
public:
|
public:
|
||||||
TSymbolTable() : uniqueId(0), noBuiltInRedeclarations(false), adoptedLevels(1) // TODO: memory: can we make adoptedLevels be 0 for symbol tables we don't keep?
|
TSymbolTable() : uniqueId(0), noBuiltInRedeclarations(false), adoptedLevels(0)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// This symbol table cannot be used until push() is called.
|
// This symbol table cannot be used until push() is called.
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
explicit TSymbolTable(TSymbolTable& symTable)
|
|
||||||
{
|
|
||||||
if (! symTable.isEmpty()) {
|
|
||||||
table.push_back(symTable.table[0]);
|
|
||||||
adoptedLevels = 1;
|
|
||||||
uniqueId = symTable.uniqueId;
|
|
||||||
noBuiltInRedeclarations = symTable.noBuiltInRedeclarations;
|
|
||||||
} // else should only be to handle error paths
|
|
||||||
}
|
|
||||||
~TSymbolTable()
|
~TSymbolTable()
|
||||||
{
|
{
|
||||||
// don't deallocate levels passed in from elsewhere
|
// don't deallocate levels passed in from elsewhere
|
||||||
@ -388,18 +379,28 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// When the symbol table is initialized with the built-ins, there should
|
// While level adopting is generic, the methods below enact a the following
|
||||||
// 'push' calls, so that built-in shared across all compiles are at level 0
|
// convention for levels:
|
||||||
// built-ins specific to a compile are at level 1 and the shader
|
// 0: common built-ins shared across all stages, all compiles, only one copy for all symbol tables
|
||||||
// globals are at level 2.
|
// 1: per-stage built-ins, shared across all compiles, but a different copy per stage
|
||||||
//
|
// 2: built-ins specific to a compile, like resources that are context-dependent
|
||||||
// TODO: compile-time memory: have an even earlier level for all built-ins
|
// 3: user-shader globals
|
||||||
// common to all stages. Currently, each stage has copy.
|
|
||||||
//
|
//
|
||||||
|
void adoptLevels(TSymbolTable& symTable)
|
||||||
|
{
|
||||||
|
for (unsigned int level = 0; level < symTable.table.size(); ++level) {
|
||||||
|
table.push_back(symTable.table[level]);
|
||||||
|
++adoptedLevels;
|
||||||
|
}
|
||||||
|
uniqueId = symTable.uniqueId;
|
||||||
|
noBuiltInRedeclarations = symTable.noBuiltInRedeclarations;
|
||||||
|
}
|
||||||
bool isEmpty() { return table.size() == 0; }
|
bool isEmpty() { return table.size() == 0; }
|
||||||
bool atBuiltInLevel() { return atSharedBuiltInLevel() || atDynamicBuiltInLevel(); }
|
bool atBuiltInLevel() { return atSharedBuiltInLevel() || atDynamicBuiltInLevel(); }
|
||||||
bool atSharedBuiltInLevel() { return table.size() == 1; }
|
bool atSharedBuiltInLevel() { return table.size() <= 2; }
|
||||||
bool atGlobalLevel() { return table.size() <= 3; }
|
bool atDynamicBuiltInLevel() { return table.size() == 3; }
|
||||||
|
bool atGlobalLevel() { return table.size() <= 4; }
|
||||||
|
|
||||||
void setNoBuiltInRedeclarations() { noBuiltInRedeclarations = true; }
|
void setNoBuiltInRedeclarations() { noBuiltInRedeclarations = true; }
|
||||||
|
|
||||||
void push()
|
void push()
|
||||||
@ -450,8 +451,16 @@ public:
|
|||||||
return symbol;
|
return symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
TSymbolTableLevel* getGlobalLevel() { assert(table.size() >= 3); return table[2]; }
|
void relateToOperator(const char* name, TOperator op)
|
||||||
void relateToOperator(const char* name, TOperator op) { table[0]->relateToOperator(name, op); }
|
{
|
||||||
|
for (unsigned int level = 0; level < table.size(); ++level) {
|
||||||
|
if (atSharedBuiltInLevel())
|
||||||
|
table[level]->relateToOperator(name, op);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int getMaxSymbolId() { return uniqueId; }
|
int getMaxSymbolId() { return uniqueId; }
|
||||||
void dump(TInfoSink &infoSink) const;
|
void dump(TInfoSink &infoSink) const;
|
||||||
void copyTable(const TSymbolTable& copyOf);
|
void copyTable(const TSymbolTable& copyOf);
|
||||||
@ -459,10 +468,10 @@ public:
|
|||||||
void setPreviousDefaultPrecisions(TPrecisionQualifier *p) { table[currentLevel()]->setPreviousDefaultPrecisions(p); }
|
void setPreviousDefaultPrecisions(TPrecisionQualifier *p) { table[currentLevel()]->setPreviousDefaultPrecisions(p); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
TSymbolTable(TSymbolTable&);
|
||||||
TSymbolTable& operator=(TSymbolTableLevel&);
|
TSymbolTable& operator=(TSymbolTableLevel&);
|
||||||
|
|
||||||
int currentLevel() const { return static_cast<int>(table.size()) - 1; }
|
int currentLevel() const { return static_cast<int>(table.size()) - 1; }
|
||||||
bool atDynamicBuiltInLevel() { return table.size() == 2; }
|
|
||||||
|
|
||||||
std::vector<TSymbolTableLevel*> table;
|
std::vector<TSymbolTableLevel*> table;
|
||||||
int uniqueId; // for unique identification in code generation
|
int uniqueId; // for unique identification in code generation
|
||||||
|
|||||||
@ -1098,7 +1098,7 @@ declaration
|
|||||||
| PRECISION precision_qualifier type_specifier SEMICOLON {
|
| PRECISION precision_qualifier type_specifier SEMICOLON {
|
||||||
parseContext.profileRequires($1.loc, ENoProfile, 130, 0, "precision statement");
|
parseContext.profileRequires($1.loc, ENoProfile, 130, 0, "precision statement");
|
||||||
|
|
||||||
// lazy setting of the previous scope's defaults, only takes on first one in a particular scope
|
// lazy setting of the previous scope's defaults, has effect only the first time it is called in a particular scope
|
||||||
parseContext.symbolTable.setPreviousDefaultPrecisions(&parseContext.defaultPrecision[0]);
|
parseContext.symbolTable.setPreviousDefaultPrecisions(&parseContext.defaultPrecision[0]);
|
||||||
|
|
||||||
parseContext.setDefaultPrecision($1.loc, $3, $2.qualifier.precision);
|
parseContext.setDefaultPrecision($1.loc, $3, $2.qualifier.precision);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user