Ensure the shared symbol table levels are read-only to make multi-threading safe. Also removed inadvertent extra copies of the symbol table shared across all stages.
git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@22939 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
parent
69f4b517c2
commit
38f3b890de
Binary file not shown.
@ -55,6 +55,7 @@ enum TOptions {
|
|||||||
EOptionRelaxedErrors = 0x008,
|
EOptionRelaxedErrors = 0x008,
|
||||||
EOptionGiveWarnings = 0x010,
|
EOptionGiveWarnings = 0x010,
|
||||||
EOptionsLinkProgram = 0x020,
|
EOptionsLinkProgram = 0x020,
|
||||||
|
EOptionMultiThreaded = 0x040,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -119,16 +120,29 @@ void GenerateResources(TBuiltInResource& resources)
|
|||||||
resources.maxProgramTexelOffset = 7;
|
resources.maxProgramTexelOffset = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// thread-safe list of shaders to asynchronously grab and compile
|
||||||
glslang::TWorklist Worklist;
|
glslang::TWorklist Worklist;
|
||||||
|
|
||||||
|
// array of unique places to leave the shader names and infologs for the asynchronous compiles
|
||||||
|
glslang::TWorkItem **Work = 0;
|
||||||
|
int NumWorkItems = 0;
|
||||||
|
|
||||||
int Options = 0;
|
int Options = 0;
|
||||||
bool Delay = false;
|
bool Delay = false;
|
||||||
|
const char* ExecutableName;
|
||||||
|
|
||||||
bool ProcessArguments(int argc, char* argv[])
|
bool ProcessArguments(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
ExecutableName = argv[0];
|
||||||
|
NumWorkItems = argc; // will include some empties where the '-' options were, but it doesn't matter, they'll be 0
|
||||||
|
Work = new glslang::TWorkItem*[NumWorkItems];
|
||||||
|
Work[0] = 0;
|
||||||
|
|
||||||
argc--;
|
argc--;
|
||||||
argv++;
|
argv++;
|
||||||
for (; argc >= 1; argc--, argv++) {
|
for (; argc >= 1; argc--, argv++) {
|
||||||
if (argv[0][0] == '-') {
|
if (argv[0][0] == '-') {
|
||||||
|
Work[argc] = 0;
|
||||||
switch (argv[0][1]) {
|
switch (argv[0][1]) {
|
||||||
case 'd':
|
case 'd':
|
||||||
Delay = true;
|
Delay = true;
|
||||||
@ -148,11 +162,18 @@ bool ProcessArguments(int argc, char* argv[])
|
|||||||
case 's':
|
case 's':
|
||||||
Options |= EOptionSuppressInfolog;
|
Options |= EOptionSuppressInfolog;
|
||||||
break;
|
break;
|
||||||
|
case 't':
|
||||||
|
#ifdef _WIN32
|
||||||
|
Options |= EOptionMultiThreaded;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
Worklist.add(std::string(argv[0]));
|
Work[argc] = new glslang::TWorkItem(std::string(argv[0]));
|
||||||
|
Worklist.add(Work[argc]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Worklist.empty())
|
if (Worklist.empty())
|
||||||
@ -168,18 +189,18 @@ unsigned int
|
|||||||
#endif
|
#endif
|
||||||
CompileShaders(void*)
|
CompileShaders(void*)
|
||||||
{
|
{
|
||||||
std::string shaderName;
|
glslang::TWorkItem* workItem;
|
||||||
while (Worklist.remove(shaderName)) {
|
while (Worklist.remove(workItem)) {
|
||||||
ShHandle compiler = ShConstructCompiler(FindLanguage(shaderName), Options);
|
ShHandle compiler = ShConstructCompiler(FindLanguage(workItem->name), Options);
|
||||||
if (compiler == 0)
|
if (compiler == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
TBuiltInResource resources;
|
TBuiltInResource resources;
|
||||||
GenerateResources(resources);
|
GenerateResources(resources);
|
||||||
CompileFile(shaderName.c_str(), compiler, Options, &resources);
|
CompileFile(workItem->name.c_str(), compiler, Options, &resources);
|
||||||
|
|
||||||
if (! (Options & EOptionSuppressInfolog))
|
if (! (Options & EOptionSuppressInfolog))
|
||||||
puts(ShGetInfoLog(compiler));
|
workItem->results = ShGetInfoLog(compiler);
|
||||||
|
|
||||||
ShDestruct(compiler);
|
ShDestruct(compiler);
|
||||||
}
|
}
|
||||||
@ -212,13 +233,13 @@ void CompileAndLinkShaders()
|
|||||||
//
|
//
|
||||||
|
|
||||||
glslang::TProgram program;
|
glslang::TProgram program;
|
||||||
std::string shaderName;
|
glslang::TWorkItem* workItem;
|
||||||
while (Worklist.remove(shaderName)) {
|
while (Worklist.remove(workItem)) {
|
||||||
EShLanguage stage = FindLanguage(shaderName);
|
EShLanguage stage = FindLanguage(workItem->name);
|
||||||
glslang::TShader* shader = new glslang::TShader(stage);
|
glslang::TShader* shader = new glslang::TShader(stage);
|
||||||
shaders.push_back(shader);
|
shaders.push_back(shader);
|
||||||
|
|
||||||
char** shaderStrings = ReadFileData(shaderName.c_str());
|
char** shaderStrings = ReadFileData(workItem->name.c_str());
|
||||||
if (! shaderStrings) {
|
if (! shaderStrings) {
|
||||||
usage();
|
usage();
|
||||||
return;
|
return;
|
||||||
@ -231,7 +252,7 @@ void CompileAndLinkShaders()
|
|||||||
program.addShader(shader);
|
program.addShader(shader);
|
||||||
|
|
||||||
if (! (Options & EOptionSuppressInfolog)) {
|
if (! (Options & EOptionSuppressInfolog)) {
|
||||||
puts(shaderName.c_str());
|
puts(workItem->name.c_str());
|
||||||
puts(shader->getInfoLog());
|
puts(shader->getInfoLog());
|
||||||
puts(shader->getInfoDebugLog());
|
puts(shader->getInfoDebugLog());
|
||||||
}
|
}
|
||||||
@ -266,7 +287,7 @@ int C_DECL main(int argc, char* argv[])
|
|||||||
// Init for front-end proper
|
// Init for front-end proper
|
||||||
ShInitialize();
|
ShInitialize();
|
||||||
|
|
||||||
// Init for for standalone
|
// Init for standalone
|
||||||
glslang::InitGlobalLock();
|
glslang::InitGlobalLock();
|
||||||
|
|
||||||
if (! ProcessArguments(argc, argv)) {
|
if (! ProcessArguments(argc, argv)) {
|
||||||
@ -276,13 +297,16 @@ int C_DECL main(int argc, char* argv[])
|
|||||||
|
|
||||||
//
|
//
|
||||||
// Two modes:
|
// Two modes:
|
||||||
// 1) linking all arguments together, single-threaded
|
// 1) linking all arguments together, single-threaded, new C++ interface
|
||||||
// 2) independent arguments, can be tackled by multiple asynchronous threads, for testing thread safety
|
// 2) independent arguments, can be tackled by multiple asynchronous threads, for testing thread safety, using the old handle interface
|
||||||
//
|
//
|
||||||
|
if (Options & EOptionsLinkProgram)
|
||||||
|
CompileAndLinkShaders();
|
||||||
|
else {
|
||||||
|
bool printShaderNames = Worklist.size() > 1;
|
||||||
|
|
||||||
// TODO: finish threading, allow external control over number of threads
|
if (Options & EOptionMultiThreaded) {
|
||||||
const int NumThreads = 1;
|
const int NumThreads = 16;
|
||||||
if (NumThreads > 1) {
|
|
||||||
void* threads[NumThreads];
|
void* threads[NumThreads];
|
||||||
for (int t = 0; t < NumThreads; ++t) {
|
for (int t = 0; t < NumThreads; ++t) {
|
||||||
threads[t] = glslang::OS_CreateThread(&CompileShaders);
|
threads[t] = glslang::OS_CreateThread(&CompileShaders);
|
||||||
@ -292,13 +316,20 @@ int C_DECL main(int argc, char* argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
glslang::OS_WaitForAllThreads(threads, NumThreads);
|
glslang::OS_WaitForAllThreads(threads, NumThreads);
|
||||||
} else {
|
|
||||||
if (Options & EOptionsLinkProgram) {
|
|
||||||
CompileAndLinkShaders();
|
|
||||||
} else {
|
} else {
|
||||||
if (! CompileShaders(0))
|
if (! CompileShaders(0))
|
||||||
compileFailed = true;
|
compileFailed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Print out all the resulting infologs
|
||||||
|
for (int w = 0; w < NumWorkItems; ++w) {
|
||||||
|
if (Work[w]) {
|
||||||
|
if (printShaderNames)
|
||||||
|
puts(Work[w]->name.c_str());
|
||||||
|
puts(Work[w]->results.c_str());
|
||||||
|
delete Work[w];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Delay)
|
if (Delay)
|
||||||
@ -401,7 +432,7 @@ bool CompileFile(const char *fileName, ShHandle compiler, int Options, const TBu
|
|||||||
//
|
//
|
||||||
void usage()
|
void usage()
|
||||||
{
|
{
|
||||||
printf("Usage: standalone [ options ] filename\n"
|
printf("Usage: glslangValidator [ options ] filename\n"
|
||||||
"Where: filename is a name ending in\n"
|
"Where: filename is a name ending in\n"
|
||||||
" .vert for a vertex shader\n"
|
" .vert for a vertex shader\n"
|
||||||
" .tesc for a tessellation control shader\n"
|
" .tesc for a tessellation control shader\n"
|
||||||
@ -415,8 +446,9 @@ void usage()
|
|||||||
"-d: delay exit\n"
|
"-d: delay exit\n"
|
||||||
"-l: link validation of all input files\n"
|
"-l: link validation of all input files\n"
|
||||||
"-m: memory leak mode\n"
|
"-m: memory leak mode\n"
|
||||||
|
"-r: relaxed semantic error-checking mode\n"
|
||||||
"-s: silent mode\n"
|
"-s: silent mode\n"
|
||||||
"-r: relaxed semantic error-checking mode\n");
|
"-t: multi-threaded mode\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
|
@ -41,27 +41,36 @@
|
|||||||
|
|
||||||
namespace glslang {
|
namespace glslang {
|
||||||
|
|
||||||
|
class TWorkItem {
|
||||||
|
public:
|
||||||
|
TWorkItem() { }
|
||||||
|
explicit TWorkItem(const std::string& s) :
|
||||||
|
name(s) { }
|
||||||
|
std::string name;
|
||||||
|
std::string results;
|
||||||
|
};
|
||||||
|
|
||||||
class TWorklist {
|
class TWorklist {
|
||||||
public:
|
public:
|
||||||
TWorklist() { }
|
TWorklist() { }
|
||||||
virtual ~TWorklist() { }
|
virtual ~TWorklist() { }
|
||||||
|
|
||||||
void add(const std::string& s)
|
void add(TWorkItem* item)
|
||||||
{
|
{
|
||||||
GetGlobalLock();
|
GetGlobalLock();
|
||||||
|
|
||||||
worklist.push_back(s);
|
worklist.push_back(item);
|
||||||
|
|
||||||
ReleaseGlobalLock();
|
ReleaseGlobalLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool remove(std::string& s)
|
bool remove(TWorkItem*& item)
|
||||||
{
|
{
|
||||||
GetGlobalLock();
|
GetGlobalLock();
|
||||||
|
|
||||||
if (worklist.empty())
|
if (worklist.empty())
|
||||||
return false;
|
return false;
|
||||||
s = worklist.front();
|
item = worklist.front();
|
||||||
worklist.pop_front();
|
worklist.pop_front();
|
||||||
|
|
||||||
ReleaseGlobalLock();
|
ReleaseGlobalLock();
|
||||||
@ -69,13 +78,18 @@ namespace glslang {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int size()
|
||||||
|
{
|
||||||
|
return worklist.size();
|
||||||
|
}
|
||||||
|
|
||||||
bool empty()
|
bool empty()
|
||||||
{
|
{
|
||||||
return worklist.empty();
|
return worklist.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::list<std::string> worklist;
|
std::list<TWorkItem*> worklist;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace glslang
|
} // end namespace glslang
|
||||||
|
@ -27,3 +27,12 @@ function runLinkTest {
|
|||||||
|
|
||||||
runLinkTest mains1.frag mains2.frag noMain1.geom noMain2.geom
|
runLinkTest mains1.frag mains2.frag noMain1.geom noMain2.geom
|
||||||
runLinkTest noMain.vert mains.frag
|
runLinkTest noMain.vert mains.frag
|
||||||
|
|
||||||
|
#
|
||||||
|
# multi-threaded test
|
||||||
|
#
|
||||||
|
|
||||||
|
echo Comparing single thread to multithread for all tests in current directory...
|
||||||
|
$EXE -i *.vert *.geom *.frag *.tes* *.comp > singleThread.out
|
||||||
|
$EXE -i *.vert *.geom *.frag *.tes* *.comp -t > multiThread.out
|
||||||
|
diff singleThread.out multiThread.out
|
||||||
|
7
Todo.txt
7
Todo.txt
@ -1,10 +1,5 @@
|
|||||||
Current functionality level: ESSL 3.0
|
Current functionality level: ESSL 3.0
|
||||||
|
|
||||||
Performance
|
|
||||||
|
|
||||||
Testing
|
|
||||||
- thread safety
|
|
||||||
|
|
||||||
Link Validation
|
Link Validation
|
||||||
- ensure no static references thrown away
|
- ensure no static references thrown away
|
||||||
Cross-stage linking
|
Cross-stage linking
|
||||||
@ -21,6 +16,8 @@ Link Validation
|
|||||||
Intra-stage linking
|
Intra-stage linking
|
||||||
- exactly one main
|
- exactly one main
|
||||||
- type consistency check of uniforms, globals, ins, and outs, both variables and blocks
|
- type consistency check of uniforms, globals, ins, and outs, both variables and blocks
|
||||||
|
- value checking of global const initializers
|
||||||
|
- value checking of uniform initializers
|
||||||
- location/component/binding/index/offset match check
|
- location/component/binding/index/offset match check
|
||||||
- location/component aliasing (except desktop vertex shader inputs)
|
- location/component aliasing (except desktop vertex shader inputs)
|
||||||
- location layout range/overlap semantics
|
- location layout range/overlap semantics
|
||||||
|
@ -577,12 +577,14 @@ public:
|
|||||||
virtual bool isMatrix() const { return matrixCols ? true : false; }
|
virtual bool isMatrix() const { return matrixCols ? true : false; }
|
||||||
virtual bool isArray() const { return arraySizes != 0; }
|
virtual bool isArray() const { return arraySizes != 0; }
|
||||||
int getArraySize() const { return arraySizes->front(); }
|
int getArraySize() const { return arraySizes->front(); }
|
||||||
void setArraySizes(TArraySizes s) {
|
void setArraySizes(TArraySizes s)
|
||||||
|
{
|
||||||
// copy; we don't want distinct types sharing the same descriptor
|
// copy; we don't want distinct types sharing the same descriptor
|
||||||
if (! arraySizes)
|
if (! arraySizes)
|
||||||
arraySizes = NewPoolTArraySizes();
|
arraySizes = NewPoolTArraySizes();
|
||||||
*arraySizes = *s;
|
*arraySizes = *s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void changeArraySize(int s) { arraySizes->front() = s; }
|
void changeArraySize(int s) { arraySizes->front() = s; }
|
||||||
void setMaxArraySize (int s) { maxArraySize = s; }
|
void setMaxArraySize (int s) { maxArraySize = s; }
|
||||||
int getMaxArraySize () const { return maxArraySize; }
|
int getMaxArraySize () const { return maxArraySize; }
|
||||||
@ -590,10 +592,13 @@ public:
|
|||||||
TType* getArrayInformationType() { return arrayInformationType; }
|
TType* getArrayInformationType() { return arrayInformationType; }
|
||||||
virtual bool isVector() const { return vectorSize > 1; }
|
virtual bool isVector() const { return vectorSize > 1; }
|
||||||
virtual bool isScalar() const { return vectorSize == 1; }
|
virtual bool isScalar() const { return vectorSize == 1; }
|
||||||
const char* getBasicString() const {
|
const char* getBasicString() const
|
||||||
|
{
|
||||||
return TType::getBasicString(basicType);
|
return TType::getBasicString(basicType);
|
||||||
}
|
}
|
||||||
static const char* getBasicString(TBasicType t) {
|
|
||||||
|
static const char* getBasicString(TBasicType t)
|
||||||
|
{
|
||||||
switch (t) {
|
switch (t) {
|
||||||
case EbtVoid: return "void";
|
case EbtVoid: return "void";
|
||||||
case EbtFloat: return "float";
|
case EbtFloat: return "float";
|
||||||
|
@ -456,10 +456,10 @@ TIntermTyped* TParseContext::handleVariable(TSourceLoc loc, TSymbol* symbol, TSt
|
|||||||
{
|
{
|
||||||
TIntermTyped* node = 0;
|
TIntermTyped* node = 0;
|
||||||
|
|
||||||
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
|
||||||
TVariable* variable = anon->getAnonContainer().getAsVariable();
|
const TVariable* variable = anon->getAnonContainer().getAsVariable();
|
||||||
TIntermTyped* container = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), loc);
|
TIntermTyped* container = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), loc);
|
||||||
TConstUnion* unionArray = new TConstUnion[1];
|
TConstUnion* unionArray = new TConstUnion[1];
|
||||||
unionArray->setUConst(anon->getMemberNumber());
|
unionArray->setUConst(anon->getMemberNumber());
|
||||||
@ -1626,7 +1626,7 @@ bool TParseContext::insertBuiltInArrayAtGlobalLevel()
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
TVariable* variable = symbol->getAsVariable();
|
const TVariable* variable = symbol->getAsVariable();
|
||||||
|
|
||||||
if (! variable) {
|
if (! variable) {
|
||||||
infoSink.info.message(EPrefixInternalError, "variable expected");
|
infoSink.info.message(EPrefixInternalError, "variable expected");
|
||||||
@ -1730,21 +1730,18 @@ void TParseContext::arrayCheck(TSourceLoc loc, TString& identifier, const TPubli
|
|||||||
// Don't check for reserved word use until after we know it's not in the symbol table,
|
// Don't check for reserved word use until after we know it's not in the symbol table,
|
||||||
// because reserved arrays can be redeclared.
|
// because reserved arrays can be redeclared.
|
||||||
//
|
//
|
||||||
|
// However, reserved arrays cannot be modified in a shared symbol table, so add a new
|
||||||
|
// one at a non-shared level in the table.
|
||||||
|
//
|
||||||
|
|
||||||
bool sameScope = false;
|
bool currentScope;
|
||||||
TSymbol* symbol = symbolTable.find(identifier, 0, &sameScope);
|
TSymbol* symbol = symbolTable.find(identifier, 0, ¤tScope);
|
||||||
if (symbol == 0 || !sameScope) {
|
if (symbol == 0 || ! currentScope) {
|
||||||
if (reservedErrorCheck(loc, identifier))
|
if (reservedErrorCheck(loc, identifier))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
variable = new TVariable(&identifier, TType(type));
|
variable = new TVariable(&identifier, TType(type));
|
||||||
|
symbolTable.insert(*variable);
|
||||||
if (! symbolTable.insert(*variable)) {
|
|
||||||
delete variable;
|
|
||||||
error(loc, "INTERNAL ERROR inserting new symbol", identifier.c_str(), "");
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
variable = symbol->getAsVariable();
|
variable = symbol->getAsVariable();
|
||||||
|
|
||||||
@ -1777,7 +1774,7 @@ void TParseContext::arrayCheck(TSourceLoc loc, TString& identifier, const TPubli
|
|||||||
t = t->getArrayInformationType();
|
t = t->getArrayInformationType();
|
||||||
}
|
}
|
||||||
|
|
||||||
variable->getType().setArraySizes(type.arraySizes);
|
variable->getWritableType().setArraySizes(type.arraySizes);
|
||||||
}
|
}
|
||||||
|
|
||||||
voidErrorCheck(loc, identifier, type);
|
voidErrorCheck(loc, identifier, type);
|
||||||
@ -1797,6 +1794,8 @@ bool TParseContext::arraySetMaxSize(TIntermSymbol *node, TType* type, int size,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// There are multiple copies of the array type tagging results of operations.
|
||||||
|
// Chain these together, so they can all reflect the final size.
|
||||||
type->setArrayInformationType(variable->getArrayInformationType());
|
type->setArrayInformationType(variable->getArrayInformationType());
|
||||||
variable->updateArrayInformationType(type);
|
variable->updateArrayInformationType(type);
|
||||||
|
|
||||||
@ -1816,13 +1815,13 @@ bool TParseContext::arraySetMaxSize(TIntermSymbol *node, TType* type, int size,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// we dont want to update the maxArraySize when this flag is not set, we just want to include this
|
// We don't want to update the maxArraySize when this flag is not set, we just want to include this
|
||||||
// node type in the chain of node types so that its updated when a higher maxArraySize comes in.
|
// node type in the chain of node types so that it's updated when a higher maxArraySize comes in.
|
||||||
if (!updateFlag)
|
if (! updateFlag)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
size++;
|
size++;
|
||||||
variable->getType().setMaxArraySize(size);
|
variable->getWritableType().setMaxArraySize(size);
|
||||||
type->setMaxArraySize(size);
|
type->setMaxArraySize(size);
|
||||||
TType* tt = type;
|
TType* tt = type;
|
||||||
|
|
||||||
@ -1997,8 +1996,7 @@ const TFunction* TParseContext::findFunction(TSourceLoc loc, TFunction* call, bo
|
|||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Initializers show up in several places in the grammar. Have one set of
|
// Handle all types of initializers from the grammar.
|
||||||
// code to handle them here.
|
|
||||||
//
|
//
|
||||||
bool TParseContext::executeInitializerError(TSourceLoc loc, TString& identifier, TPublicType& pType,
|
bool TParseContext::executeInitializerError(TSourceLoc loc, TString& identifier, TPublicType& pType,
|
||||||
TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable)
|
TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable)
|
||||||
@ -2044,13 +2042,13 @@ bool TParseContext::executeInitializerError(TSourceLoc loc, TString& identifier,
|
|||||||
if (qualifier == EvqConst) {
|
if (qualifier == EvqConst) {
|
||||||
if (qualifier != initializer->getType().getQualifier().storage) {
|
if (qualifier != initializer->getType().getQualifier().storage) {
|
||||||
error(loc, " assigning non-constant to", "=", "'%s'", variable->getType().getCompleteString().c_str());
|
error(loc, " assigning non-constant to", "=", "'%s'", variable->getType().getCompleteString().c_str());
|
||||||
variable->getType().getQualifier().storage = EvqTemporary;
|
variable->getWritableType().getQualifier().storage = EvqTemporary;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (type != initializer->getType()) {
|
if (type != initializer->getType()) {
|
||||||
error(loc, " non-matching types for const initializer ",
|
error(loc, " non-matching types for const initializer ",
|
||||||
variable->getType().getStorageQualifierString(), "");
|
variable->getType().getStorageQualifierString(), "");
|
||||||
variable->getType().getQualifier().storage = EvqTemporary;
|
variable->getWritableType().getQualifier().storage = EvqTemporary;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (initializer->getAsConstantUnion()) {
|
if (initializer->getAsConstantUnion()) {
|
||||||
@ -2063,7 +2061,7 @@ bool TParseContext::executeInitializerError(TSourceLoc loc, TString& identifier,
|
|||||||
}
|
}
|
||||||
} else if (initializer->getAsSymbolNode()) {
|
} else if (initializer->getAsSymbolNode()) {
|
||||||
TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getName());
|
TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getName());
|
||||||
if (TVariable* tVar = symbol->getAsVariable()) {
|
if (const TVariable* tVar = symbol->getAsVariable()) {
|
||||||
TConstUnion* constArray = tVar->getConstUnionPointer();
|
TConstUnion* constArray = tVar->getConstUnionPointer();
|
||||||
variable->shareConstPointer(constArray);
|
variable->shareConstPointer(constArray);
|
||||||
} else {
|
} else {
|
||||||
@ -2072,7 +2070,7 @@ bool TParseContext::executeInitializerError(TSourceLoc loc, TString& identifier,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error(loc, " cannot assign to", "=", "'%s'", variable->getType().getCompleteString().c_str());
|
error(loc, " cannot assign to", "=", "'%s'", variable->getType().getCompleteString().c_str());
|
||||||
variable->getType().getQualifier().storage = EvqTemporary;
|
variable->getWritableType().getQualifier().storage = EvqTemporary;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2372,7 +2370,8 @@ void TParseContext::addBlock(TSourceLoc loc, TTypeList& typeList, const TString*
|
|||||||
// For an identifier that is already declared, add more qualification to it.
|
// For an identifier that is already declared, add more qualification to it.
|
||||||
void TParseContext::addQualifierToExisting(TSourceLoc loc, TQualifier qualifier, const TString& identifier)
|
void TParseContext::addQualifierToExisting(TSourceLoc loc, TQualifier qualifier, const TString& identifier)
|
||||||
{
|
{
|
||||||
TSymbol* existing = symbolTable.find(identifier);
|
bool sharedLevel;
|
||||||
|
TSymbol* existing = symbolTable.find(identifier, 0, 0, &sharedLevel);
|
||||||
TVariable* variable = existing ? existing->getAsVariable() : 0;
|
TVariable* variable = existing ? existing->getAsVariable() : 0;
|
||||||
if (! variable) {
|
if (! variable) {
|
||||||
error(loc, "identifier not previously declared", identifier.c_str(), "");
|
error(loc, "identifier not previously declared", identifier.c_str(), "");
|
||||||
@ -2390,8 +2389,16 @@ void TParseContext::addQualifierToExisting(TSourceLoc loc, TQualifier qualifier,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Don't change a shared variable; rather add a new one at the current scope.
|
||||||
|
//
|
||||||
|
if (sharedLevel) {
|
||||||
|
variable = new TVariable(&variable->getName(), variable->getType());
|
||||||
|
symbolTable.insert(*variable);
|
||||||
|
}
|
||||||
|
|
||||||
if (qualifier.invariant)
|
if (qualifier.invariant)
|
||||||
variable->getType().getQualifier().invariant = true;
|
variable->getWritableType().getQualifier().invariant = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TParseContext::addQualifierToExisting(TSourceLoc loc, TQualifier qualifier, TIdentifierList& identifiers)
|
void TParseContext::addQualifierToExisting(TSourceLoc loc, TQualifier qualifier, TIdentifierList& identifiers)
|
||||||
|
@ -868,7 +868,7 @@ int TScanContext::identifierOrType()
|
|||||||
|
|
||||||
parserToken->sType.lex.symbol = parseContext.symbolTable.find(*parserToken->sType.lex.string);
|
parserToken->sType.lex.symbol = parseContext.symbolTable.find(*parserToken->sType.lex.string);
|
||||||
if (afterType == false && parserToken->sType.lex.symbol) {
|
if (afterType == false && parserToken->sType.lex.symbol) {
|
||||||
if (TVariable* variable = parserToken->sType.lex.symbol->getAsVariable()) {
|
if (const TVariable* variable = parserToken->sType.lex.symbol->getAsVariable()) {
|
||||||
if (variable->isUserType()) {
|
if (variable->isUserType()) {
|
||||||
afterType = true;
|
afterType = true;
|
||||||
|
|
||||||
|
@ -100,6 +100,9 @@ TSymbolTable* SharedSymbolTables[VersionCount][EProfileCount][EShLangCount] = {}
|
|||||||
|
|
||||||
TPoolAllocator* PerProcessGPA = 0;
|
TPoolAllocator* PerProcessGPA = 0;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Parse and add to the given symbol table the content of the given shader string.
|
||||||
|
//
|
||||||
bool InitializeSymbolTable(const TString& builtIns, int version, EProfile profile, EShLanguage language, TInfoSink& infoSink,
|
bool InitializeSymbolTable(const TString& builtIns, int version, EProfile profile, EShLanguage language, TInfoSink& infoSink,
|
||||||
TSymbolTable& symbolTable)
|
TSymbolTable& symbolTable)
|
||||||
{
|
{
|
||||||
@ -111,9 +114,6 @@ bool InitializeSymbolTable(const TString& builtIns, int version, EProfile profil
|
|||||||
parseContext.setScanContext(&scanContext);
|
parseContext.setScanContext(&scanContext);
|
||||||
parseContext.setPpContext(&ppContext);
|
parseContext.setPpContext(&ppContext);
|
||||||
|
|
||||||
//
|
|
||||||
// Parse the built-ins. This should only happen once per
|
|
||||||
// language symbol table when no 'resources' are passed in.
|
|
||||||
//
|
//
|
||||||
// Push the symbol table to give it an initial scope. This
|
// Push the symbol table to give it an initial scope. This
|
||||||
// push should not have a corresponding pop, so that built-ins
|
// push should not have a corresponding pop, so that built-ins
|
||||||
@ -137,44 +137,48 @@ bool InitializeSymbolTable(const TString& builtIns, int version, EProfile profil
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
int CommonIndex(EProfile profile, EShLanguage language)
|
||||||
// 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;
|
return (profile == EEsProfile && language == EShLangFragment) ? EPcFragment : EPcGeneral;
|
||||||
if (profile == EEsProfile && language == EShLangFragment)
|
}
|
||||||
commonIndex = EPcFragment;
|
|
||||||
|
|
||||||
(*symbolTables[language]).adoptLevels(*commonTable[commonIndex]);
|
//
|
||||||
|
// To initialize per-stage shared tables, with the common table already complete.
|
||||||
|
//
|
||||||
|
void InitializeStageSymbolTable(TBuiltIns& builtIns, int version, EProfile profile, EShLanguage language, TInfoSink& infoSink, TSymbolTable** commonTable, TSymbolTable** symbolTables)
|
||||||
|
{
|
||||||
|
(*symbolTables[language]).adoptLevels(*commonTable[CommonIndex(profile, language)]);
|
||||||
InitializeSymbolTable(builtIns.getStageString(language), version, profile, language, infoSink, *symbolTables[language]);
|
InitializeSymbolTable(builtIns.getStageString(language), version, profile, language, infoSink, *symbolTables[language]);
|
||||||
IdentifyBuiltIns(version, profile, language, *symbolTables[language]);
|
IdentifyBuiltIns(version, profile, language, *symbolTables[language]);
|
||||||
if (profile == EEsProfile)
|
if (profile == EEsProfile)
|
||||||
(*symbolTables[language]).setNoBuiltInRedeclarations();
|
(*symbolTables[language]).setNoBuiltInRedeclarations();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GenerateBuiltInSymbolTable(TInfoSink& infoSink, TSymbolTable** commonTable, TSymbolTable** symbolTables, int version, EProfile profile)
|
//
|
||||||
|
// Initialize the full set of shareable symbol tables;
|
||||||
|
// The common (cross-stage) and those sharable per-stage.
|
||||||
|
//
|
||||||
|
bool InitializeSymbolTables(TInfoSink& infoSink, TSymbolTable** commonTable, TSymbolTable** symbolTables, int version, EProfile profile)
|
||||||
{
|
{
|
||||||
TBuiltIns builtIns;
|
TBuiltIns builtIns;
|
||||||
|
|
||||||
builtIns.initialize(version, profile);
|
builtIns.initialize(version, profile);
|
||||||
|
|
||||||
// do the common table
|
// do the common tables
|
||||||
InitializeSymbolTable(builtIns.getCommonString(), version, profile, EShLangVertex, infoSink, *commonTable[EPcGeneral]);
|
InitializeSymbolTable(builtIns.getCommonString(), version, profile, EShLangVertex, infoSink, *commonTable[EPcGeneral]);
|
||||||
if (profile == EEsProfile)
|
if (profile == EEsProfile)
|
||||||
InitializeSymbolTable(builtIns.getCommonString(), version, profile, EShLangFragment, infoSink, *commonTable[EPcFragment]);
|
InitializeSymbolTable(builtIns.getCommonString(), version, profile, EShLangFragment, infoSink, *commonTable[EPcFragment]);
|
||||||
|
|
||||||
// do the per-stage tables
|
// do the per-stage tables
|
||||||
InitializeSymbolTable(builtIns, version, profile, EShLangVertex, infoSink, commonTable, symbolTables);
|
InitializeStageSymbolTable(builtIns, version, profile, EShLangVertex, infoSink, commonTable, symbolTables);
|
||||||
InitializeSymbolTable(builtIns, version, profile, EShLangFragment, infoSink, commonTable, symbolTables);
|
InitializeStageSymbolTable(builtIns, version, profile, EShLangFragment, infoSink, commonTable, symbolTables);
|
||||||
if (profile != EEsProfile && version >= 400) {
|
if (profile != EEsProfile && version >= 400) {
|
||||||
InitializeSymbolTable(builtIns, version, profile, EShLangTessControl, infoSink, commonTable, symbolTables);
|
InitializeStageSymbolTable(builtIns, version, profile, EShLangTessControl, infoSink, commonTable, symbolTables);
|
||||||
InitializeSymbolTable(builtIns, version, profile, EShLangTessEvaluation, infoSink, commonTable, symbolTables);
|
InitializeStageSymbolTable(builtIns, version, profile, EShLangTessEvaluation, infoSink, commonTable, symbolTables);
|
||||||
}
|
}
|
||||||
if (profile != EEsProfile && version >= 150)
|
if (profile != EEsProfile && version >= 150)
|
||||||
InitializeSymbolTable(builtIns, version, profile, EShLangGeometry, infoSink, commonTable, symbolTables);
|
InitializeStageSymbolTable(builtIns, version, profile, EShLangGeometry, infoSink, commonTable, symbolTables);
|
||||||
if (profile != EEsProfile && version >= 430)
|
if (profile != EEsProfile && version >= 430)
|
||||||
InitializeSymbolTable(builtIns, version, profile, EShLangCompute, infoSink, commonTable, symbolTables);
|
InitializeStageSymbolTable(builtIns, version, profile, EShLangCompute, infoSink, commonTable, symbolTables);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -222,7 +226,7 @@ void SetupBuiltinSymbolTable(int version, EProfile profile)
|
|||||||
TPoolAllocator* builtInPoolAllocator = new TPoolAllocator();
|
TPoolAllocator* builtInPoolAllocator = new TPoolAllocator();
|
||||||
SetThreadPoolAllocator(*builtInPoolAllocator);
|
SetThreadPoolAllocator(*builtInPoolAllocator);
|
||||||
|
|
||||||
// Dynamically allocate the symbol tables so we can control when they are deallocated WRT the pool.
|
// Dynamically allocate the local symbol tables so we can control when they are deallocated WRT when the pool is popped.
|
||||||
TSymbolTable* commonTable[EPcCount];
|
TSymbolTable* commonTable[EPcCount];
|
||||||
TSymbolTable* stageTables[EShLangCount];
|
TSymbolTable* stageTables[EShLangCount];
|
||||||
for (int precClass = 0; precClass < EPcCount; ++precClass)
|
for (int precClass = 0; precClass < EPcCount; ++precClass)
|
||||||
@ -231,7 +235,7 @@ void SetupBuiltinSymbolTable(int version, EProfile profile)
|
|||||||
stageTables[stage] = new TSymbolTable;
|
stageTables[stage] = new TSymbolTable;
|
||||||
|
|
||||||
// Generate the local symbol tables using the new pool
|
// Generate the local symbol tables using the new pool
|
||||||
GenerateBuiltInSymbolTable(infoSink, commonTable, stageTables, version, profile);
|
InitializeSymbolTables(infoSink, commonTable, stageTables, version, profile);
|
||||||
|
|
||||||
// Switch to the process-global pool
|
// Switch to the process-global pool
|
||||||
SetThreadPoolAllocator(*PerProcessGPA);
|
SetThreadPoolAllocator(*PerProcessGPA);
|
||||||
@ -241,12 +245,15 @@ void SetupBuiltinSymbolTable(int version, EProfile profile)
|
|||||||
if (! commonTable[precClass]->isEmpty()) {
|
if (! commonTable[precClass]->isEmpty()) {
|
||||||
CommonSymbolTable[versionIndex][profile][precClass] = new TSymbolTable;
|
CommonSymbolTable[versionIndex][profile][precClass] = new TSymbolTable;
|
||||||
CommonSymbolTable[versionIndex][profile][precClass]->copyTable(*commonTable[precClass]);
|
CommonSymbolTable[versionIndex][profile][precClass]->copyTable(*commonTable[precClass]);
|
||||||
|
CommonSymbolTable[versionIndex][profile][precClass]->readOnly();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int stage = 0; stage < EShLangCount; ++stage) {
|
for (int stage = 0; stage < EShLangCount; ++stage) {
|
||||||
if (! stageTables[stage]->isEmpty()) {
|
if (! stageTables[stage]->isEmpty()) {
|
||||||
SharedSymbolTables[versionIndex][profile][stage] = new TSymbolTable;
|
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]->copyTable(*stageTables[stage]);
|
||||||
|
SharedSymbolTables[versionIndex][profile][stage]->readOnly();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,6 +207,15 @@ void TSymbolTableLevel::relateToOperator(const char* name, TOperator op)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Make all symbols in this table level read only.
|
||||||
|
//
|
||||||
|
void TSymbolTableLevel::readOnly()
|
||||||
|
{
|
||||||
|
for (tLevel::iterator it = level.begin(); it != level.end(); ++it)
|
||||||
|
(*it).second->readOnly();
|
||||||
|
}
|
||||||
|
|
||||||
TSymbol::TSymbol(const TSymbol& copyOf)
|
TSymbol::TSymbol(const TSymbol& copyOf)
|
||||||
{
|
{
|
||||||
name = NewPoolTString(copyOf.name->c_str());
|
name = NewPoolTString(copyOf.name->c_str());
|
||||||
@ -279,10 +288,12 @@ TSymbolTableLevel* TSymbolTableLevel::clone(TStructureMap& remapper)
|
|||||||
|
|
||||||
void TSymbolTable::copyTable(const TSymbolTable& copyOf)
|
void TSymbolTable::copyTable(const TSymbolTable& copyOf)
|
||||||
{
|
{
|
||||||
|
assert(adoptedLevels == copyOf.adoptedLevels);
|
||||||
|
|
||||||
TStructureMap remapper;
|
TStructureMap remapper;
|
||||||
uniqueId = copyOf.uniqueId;
|
uniqueId = copyOf.uniqueId;
|
||||||
noBuiltInRedeclarations = copyOf.noBuiltInRedeclarations;
|
noBuiltInRedeclarations = copyOf.noBuiltInRedeclarations;
|
||||||
for (unsigned int i = 0; i < copyOf.table.size(); ++i)
|
for (unsigned int i = copyOf.adoptedLevels; i < copyOf.table.size(); ++i)
|
||||||
table.push_back(copyOf.table[i]->clone(remapper));
|
table.push_back(copyOf.table[i]->clone(remapper));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ 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) { }
|
explicit TSymbol(const TString *n) : name(n), writable(true) { }
|
||||||
virtual TSymbol* clone(TStructureMap& remapper) = 0;
|
virtual TSymbol* clone(TStructureMap& remapper) = 0;
|
||||||
virtual ~TSymbol() { }
|
virtual ~TSymbol() { }
|
||||||
|
|
||||||
@ -88,18 +88,28 @@ public:
|
|||||||
void changeName(const char* buf) { name = new TString(buf); }
|
void changeName(const char* buf) { name = new TString(buf); }
|
||||||
virtual const TString& getMangledName() const { return getName(); }
|
virtual const TString& getMangledName() const { return getName(); }
|
||||||
virtual TFunction* getAsFunction() { return 0; }
|
virtual TFunction* getAsFunction() { return 0; }
|
||||||
|
virtual const TFunction* getAsFunction() const { return 0; }
|
||||||
virtual TVariable* getAsVariable() { return 0; }
|
virtual TVariable* getAsVariable() { return 0; }
|
||||||
virtual TAnonMember* getAsAnonMember() { return 0; }
|
virtual const TVariable* getAsVariable() const { return 0; }
|
||||||
|
virtual const TAnonMember* getAsAnonMember() const { return 0; }
|
||||||
void setUniqueId(int id) { uniqueId = id; }
|
void setUniqueId(int id) { uniqueId = id; }
|
||||||
int getUniqueId() const { return uniqueId; }
|
int getUniqueId() const { return uniqueId; }
|
||||||
virtual void dump(TInfoSink &infoSink) const = 0;
|
virtual void dump(TInfoSink &infoSink) const = 0;
|
||||||
|
|
||||||
|
void readOnly() { writable = false; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit TSymbol(const TSymbol&);
|
explicit TSymbol(const TSymbol&);
|
||||||
TSymbol& operator=(const TSymbol&);
|
TSymbol& operator=(const TSymbol&);
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
//
|
||||||
|
// N.B.: Non-const functions that will be generally used should assert an this,
|
||||||
|
// to avoid overwriting shared symbol-table information.
|
||||||
|
//
|
||||||
|
bool writable;
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -119,12 +129,12 @@ public:
|
|||||||
virtual ~TVariable() { }
|
virtual ~TVariable() { }
|
||||||
|
|
||||||
virtual TVariable* getAsVariable() { return this; }
|
virtual TVariable* getAsVariable() { return this; }
|
||||||
TType& getType() { return type; }
|
virtual const TVariable* getAsVariable() const { return this; }
|
||||||
|
TType& getWritableType() { assert(writable); return type; }
|
||||||
const TType& getType() const { return type; }
|
const TType& getType() const { return type; }
|
||||||
bool isUserType() const { return userType; }
|
bool isUserType() const { return userType; }
|
||||||
void setStorageQualifier(TStorageQualifier qualifier) { type.getQualifier().storage = qualifier; }
|
void updateArrayInformationType(TType *t) { assert(writable); arrayInformationType = t; }
|
||||||
void updateArrayInformationType(TType *t) { arrayInformationType = t; }
|
TType* getArrayInformationType() { assert(writable); return arrayInformationType; }
|
||||||
TType* getArrayInformationType() { return arrayInformationType; }
|
|
||||||
|
|
||||||
virtual void dump(TInfoSink &infoSink) const;
|
virtual void dump(TInfoSink &infoSink) const;
|
||||||
|
|
||||||
@ -193,22 +203,24 @@ public:
|
|||||||
virtual ~TFunction();
|
virtual ~TFunction();
|
||||||
|
|
||||||
virtual TFunction* getAsFunction() { return this; }
|
virtual TFunction* getAsFunction() { return this; }
|
||||||
|
virtual const TFunction* getAsFunction() const { return this; }
|
||||||
|
|
||||||
void addParameter(TParameter& p)
|
void addParameter(TParameter& p)
|
||||||
{
|
{
|
||||||
|
assert(writable);
|
||||||
parameters.push_back(p);
|
parameters.push_back(p);
|
||||||
p.type->appendMangledName(mangledName);
|
p.type->appendMangledName(mangledName);
|
||||||
}
|
}
|
||||||
|
|
||||||
const TString& getMangledName() const { return mangledName; }
|
const TString& getMangledName() const { return mangledName; }
|
||||||
const TType& getReturnType() const { return returnType; }
|
const TType& getReturnType() const { return returnType; }
|
||||||
void relateToOperator(TOperator o) { op = o; }
|
void relateToOperator(TOperator o) { assert(writable); op = o; }
|
||||||
TOperator getBuiltInOp() const { return op; }
|
TOperator getBuiltInOp() const { return op; }
|
||||||
void setDefined() { defined = true; }
|
void setDefined() { assert(writable); defined = true; }
|
||||||
bool isDefined() { return defined; }
|
bool isDefined() const { return defined; }
|
||||||
|
|
||||||
int getParamCount() const { return static_cast<int>(parameters.size()); }
|
int getParamCount() const { return static_cast<int>(parameters.size()); }
|
||||||
TParameter& operator [](int i) { return parameters[i]; }
|
TParameter& operator [](int i) { assert(writable); return parameters[i]; }
|
||||||
const TParameter& operator [](int i) const { return parameters[i]; }
|
const TParameter& operator [](int i) const { return parameters[i]; }
|
||||||
|
|
||||||
virtual void dump(TInfoSink &infoSink) const;
|
virtual void dump(TInfoSink &infoSink) const;
|
||||||
@ -232,7 +244,7 @@ public:
|
|||||||
virtual TAnonMember* clone(TStructureMap& remapper);
|
virtual TAnonMember* clone(TStructureMap& remapper);
|
||||||
virtual ~TAnonMember() { }
|
virtual ~TAnonMember() { }
|
||||||
|
|
||||||
TAnonMember* getAsAnonMember() { return this; }
|
const TAnonMember* getAsAnonMember() const { return this; }
|
||||||
TSymbol& getAnonContainer() const { return anonContainer; }
|
TSymbol& getAnonContainer() const { return anonContainer; }
|
||||||
unsigned int getMemberNumber() const { return memberNumber; }
|
unsigned int getMemberNumber() const { return memberNumber; }
|
||||||
virtual void dump(TInfoSink &infoSink) const;
|
virtual void dump(TInfoSink &infoSink) const;
|
||||||
@ -266,7 +278,7 @@ public:
|
|||||||
symbol.changeName(buf);
|
symbol.changeName(buf);
|
||||||
|
|
||||||
bool isOkay = true;
|
bool isOkay = true;
|
||||||
TTypeList& types = *symbol.getAsVariable()->getType().getStruct();
|
const TTypeList& types = *symbol.getAsVariable()->getType().getStruct();
|
||||||
for (unsigned int m = 0; m < types.size(); ++m) {
|
for (unsigned int m = 0; m < types.size(); ++m) {
|
||||||
TAnonMember* member = new TAnonMember(&types[m].type->getFieldName(), m, symbol);
|
TAnonMember* member = new TAnonMember(&types[m].type->getFieldName(), m, symbol);
|
||||||
result = level.insert(tLevelPair(member->getMangledName(), member));
|
result = level.insert(tLevelPair(member->getMangledName(), member));
|
||||||
@ -351,6 +363,7 @@ public:
|
|||||||
void relateToOperator(const char* name, TOperator op);
|
void relateToOperator(const char* name, TOperator op);
|
||||||
void dump(TInfoSink &infoSink) const;
|
void dump(TInfoSink &infoSink) const;
|
||||||
TSymbolTableLevel* clone(TStructureMap& remapper);
|
TSymbolTableLevel* clone(TStructureMap& remapper);
|
||||||
|
void readOnly();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit TSymbolTableLevel(TSymbolTableLevel&);
|
explicit TSymbolTableLevel(TSymbolTableLevel&);
|
||||||
@ -397,15 +410,17 @@ public:
|
|||||||
// convention for levels:
|
// convention for levels:
|
||||||
// 0: common built-ins shared across all stages, all compiles, only one copy for all symbol tables
|
// 0: common built-ins shared across all stages, all compiles, only one copy for all symbol tables
|
||||||
// 1: per-stage built-ins, shared across all compiles, but a different copy per stage
|
// 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
|
// 2: built-ins specific to a compile, like resources that are context-dependent, or redeclared built-ins
|
||||||
// 3: user-shader globals
|
// 3: user-shader globals
|
||||||
//
|
//
|
||||||
protected:
|
protected:
|
||||||
static const int globalLevel = 3;
|
bool isSharedLevel(int level) { return level <= 1; } // exclude all per-compile levels
|
||||||
|
bool isBuiltInLevel(int level) { return level <= 2; } // exclude user globals
|
||||||
|
bool isGlobalLevel(int level) { return level <= 3; } // include user globals
|
||||||
public:
|
public:
|
||||||
bool isEmpty() { return table.size() == 0; }
|
bool isEmpty() { return table.size() == 0; }
|
||||||
bool atBuiltInLevel() { return table.size() <= globalLevel; } // exclude user globals
|
bool atBuiltInLevel() { return isBuiltInLevel(currentLevel()); }
|
||||||
bool atGlobalLevel() { return table.size() <= globalLevel + 1; } // include user globals
|
bool atGlobalLevel() { return isGlobalLevel(currentLevel()); }
|
||||||
|
|
||||||
void setNoBuiltInRedeclarations() { noBuiltInRedeclarations = true; }
|
void setNoBuiltInRedeclarations() { noBuiltInRedeclarations = true; }
|
||||||
|
|
||||||
@ -440,7 +455,7 @@ public:
|
|||||||
return table[currentLevel()]->insert(symbol);
|
return table[currentLevel()]->insert(symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
TSymbol* find(const TString& name, bool* builtIn = 0, bool *sameScope = 0)
|
TSymbol* find(const TString& name, bool* builtIn = 0, bool *currentScope = 0, bool *sharedLevel = 0)
|
||||||
{
|
{
|
||||||
int level = currentLevel();
|
int level = currentLevel();
|
||||||
TSymbol* symbol;
|
TSymbol* symbol;
|
||||||
@ -450,9 +465,11 @@ public:
|
|||||||
} while (symbol == 0 && level >= 0);
|
} while (symbol == 0 && level >= 0);
|
||||||
level++;
|
level++;
|
||||||
if (builtIn)
|
if (builtIn)
|
||||||
*builtIn = level < 2;
|
*builtIn = isBuiltInLevel(level);
|
||||||
if (sameScope)
|
if (currentScope)
|
||||||
*sameScope = level == currentLevel();
|
*currentScope = level == currentLevel();
|
||||||
|
if (sharedLevel)
|
||||||
|
*sharedLevel = isSharedLevel(level);
|
||||||
|
|
||||||
return symbol;
|
return symbol;
|
||||||
}
|
}
|
||||||
@ -469,6 +486,12 @@ public:
|
|||||||
|
|
||||||
void setPreviousDefaultPrecisions(TPrecisionQualifier *p) { table[currentLevel()]->setPreviousDefaultPrecisions(p); }
|
void setPreviousDefaultPrecisions(TPrecisionQualifier *p) { table[currentLevel()]->setPreviousDefaultPrecisions(p); }
|
||||||
|
|
||||||
|
void readOnly()
|
||||||
|
{
|
||||||
|
for (unsigned int level = 0; level < table.size(); ++level)
|
||||||
|
table[level]->readOnly();
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
TSymbolTable(TSymbolTable&);
|
TSymbolTable(TSymbolTable&);
|
||||||
TSymbolTable& operator=(TSymbolTableLevel&);
|
TSymbolTable& operator=(TSymbolTableLevel&);
|
||||||
|
@ -807,7 +807,7 @@ function_prototype
|
|||||||
TSymbol* symbol = parseContext.symbolTable.find($1->getMangledName(), &builtIn);
|
TSymbol* symbol = parseContext.symbolTable.find($1->getMangledName(), &builtIn);
|
||||||
if (symbol && symbol->getAsFunction() && builtIn)
|
if (symbol && symbol->getAsFunction() && builtIn)
|
||||||
parseContext.requireProfile($2.loc, static_cast<EProfileMask>(~EEsProfileMask), "redeclaration of built-in function");
|
parseContext.requireProfile($2.loc, static_cast<EProfileMask>(~EEsProfileMask), "redeclaration of built-in function");
|
||||||
TFunction* prevDec = symbol ? symbol->getAsFunction() : 0;
|
const TFunction* prevDec = symbol ? symbol->getAsFunction() : 0;
|
||||||
if (prevDec) {
|
if (prevDec) {
|
||||||
if (prevDec->getReturnType() != $1->getReturnType()) {
|
if (prevDec->getReturnType() != $1->getReturnType()) {
|
||||||
parseContext.error($2.loc, "overloaded functions must have the same return type", $1->getReturnType().getCompleteTypeString().c_str(), "");
|
parseContext.error($2.loc, "overloaded functions must have the same return type", $1->getReturnType().getCompleteTypeString().c_str(), "");
|
||||||
@ -2041,7 +2041,7 @@ type_specifier_nonarray
|
|||||||
// This is for user defined type names. The lexical phase looked up the
|
// This is for user defined type names. The lexical phase looked up the
|
||||||
// type.
|
// type.
|
||||||
//
|
//
|
||||||
if (TVariable* variable = ($1.symbol)->getAsVariable()) {
|
if (const TVariable* variable = ($1.symbol)->getAsVariable()) {
|
||||||
const TType& structure = variable->getType();
|
const TType& structure = variable->getType();
|
||||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||||
$$.basicType = EbtStruct;
|
$$.basicType = EbtStruct;
|
||||||
|
@ -286,7 +286,7 @@ protected:
|
|||||||
friend class TProgram;
|
friend class TProgram;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void operator=(TShader&);
|
TShader& operator=(TShader&);
|
||||||
};
|
};
|
||||||
|
|
||||||
class TProgram {
|
class TProgram {
|
||||||
@ -306,7 +306,7 @@ protected:
|
|||||||
TInfoSink* infoSink;
|
TInfoSink* infoSink;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void operator=(TProgram&);
|
TProgram& operator=(TProgram&);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace glslang
|
} // end namespace glslang
|
||||||
|
Loading…
x
Reference in New Issue
Block a user