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:
John Kessenich 2013-08-09 20:31:43 +00:00
parent c027579631
commit 99a0576225
3 changed files with 110 additions and 77 deletions

View File

@ -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);

View File

@ -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

View File

@ -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);