Commit e4249f02 by alokp@chromium.org

Refactored the way symbol tables are initialized and stored. This was done in…

Refactored the way symbol tables are initialized and stored. This was done in response to the addition of EShSpec. Symbol table entries depend on three things - language, spec (not now but may eventually), and built-in resources. We used to build two global symbol-tables - one for each language. During each compile, one of the symbol table was copied and resource-specific stuff was added. I have moved the symbol table to TCompiler that gets initilized when compiler is created and reused for each compile. This makes it much cleaner and extensible in case a spec requires special entries to be added to the symbol table. PS: Sorry for the long CL, but all of it needed to be done in one CL. I have verified that everything still compiles and passes all conformance tests. Review URL: http://codereview.appspot.com/1864044 git-svn-id: https://angleproject.googlecode.com/svn/trunk@351 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent 6db8cab4
......@@ -70,7 +70,7 @@ typedef void* ShHandle;
//
// Driver calls these to create and destroy compiler objects.
//
ShHandle ShConstructCompiler(EShLanguage, EShSpec); // one per shader
ShHandle ShConstructCompiler(EShLanguage, EShSpec, const TBuiltInResource*);
void ShDestruct(ShHandle);
//
......@@ -85,7 +85,6 @@ int ShCompile(
const char* const shaderStrings[],
const int numStrings,
const EShOptimizationLevel,
const TBuiltInResource *resources,
int debugOptions
);
......
......@@ -22,12 +22,12 @@ enum TFailCode {
};
static EShLanguage FindLanguage(char *lang);
bool CompileFile(char *fileName, ShHandle, int, const TBuiltInResource*);
bool CompileFile(char *fileName, ShHandle, int);
void usage();
void FreeFileData(char **data);
char** ReadFileData(char *fileName);
void LogMsg(char* msg, const char* name, const int num, const char* logName);
int ShOutputMultipleStrings(char ** );
//Added to accomodate the multiple strings.
int OutputMultipleStrings = 1;
......@@ -48,61 +48,77 @@ void GenerateResources(TBuiltInResource& resources)
int main(int argc, char* argv[])
{
int numCompilers = 0;
bool compileFailed = false;
TFailCode failCode = ESuccess;
int debugOptions = 0;
bool writeObjectCode = false;
int i;
ShHandle compilers[EShLangCount];
int numCompiles = 0;
ShHandle vertexCompiler = 0;
ShHandle fragmentCompiler = 0;
ShInitialize();
TBuiltInResource resources;
GenerateResources(resources);
argc--;
argv++;
for (; argc >= 1; argc--, argv++) {
for (; (argc >= 1) && (failCode == ESuccess); argc--, argv++) {
if (argv[0][0] == '-' || argv[0][0] == '/') {
switch (argv[0][1]) {
case 'i': debugOptions |= EDebugOpIntermediate; break;
case 'o': writeObjectCode = true; break;
default: usage(); return EFailUsage;
case 'i': debugOptions |= EDebugOpIntermediate; break;
case 'o': writeObjectCode = true; break;
default: failCode = EFailUsage;
}
} else {
compilers[numCompilers] = ShConstructCompiler(FindLanguage(argv[0]), EShSpecGLES2);
if (compilers[numCompilers] == 0)
return EFailCompilerCreate;
++numCompilers;
TBuiltInResource resources;
GenerateResources(resources);
if (!CompileFile(argv[0], compilers[numCompilers-1], debugOptions, &resources))
compileFailed = true;
ShHandle compiler = 0;
switch (FindLanguage(argv[0])) {
case EShLangVertex:
if (vertexCompiler == 0)
vertexCompiler = ShConstructCompiler(EShLangVertex, EShSpecGLES2, &resources);
compiler = vertexCompiler;
break;
case EShLangFragment:
if (fragmentCompiler == 0)
fragmentCompiler = ShConstructCompiler(EShLangFragment, EShSpecGLES2, &resources);
compiler = fragmentCompiler;
break;
default: break;
}
if (compiler) {
bool compiled = CompileFile(argv[0], compiler, debugOptions);
LogMsg("BEGIN", "COMPILER", numCompiles, "INFO LOG");
puts(ShGetInfoLog(compiler));
LogMsg("END", "COMPILER", numCompiles, "INFO LOG");
if (compiled && writeObjectCode) {
LogMsg("BEGIN", "COMPILER", numCompiles, "OBJ CODE");
puts(ShGetObjectCode(compiler));
LogMsg("END", "COMPILER", numCompiles, "OBJ CODE");
}
if (!compiled)
failCode = EFailCompile;
++numCompiles;
} else {
failCode = EFailCompilerCreate;
}
}
}
if (!numCompilers) {
if ((vertexCompiler == 0) && (fragmentCompiler == 0))
failCode = EFailUsage;
if (failCode == EFailUsage)
usage();
return EFailUsage;
}
for (i = 0; i < numCompilers; ++i) {
LogMsg("BEGIN", "COMPILER", i, "INFO LOG");
puts(ShGetInfoLog(compilers[i]));
LogMsg("END", "COMPILER", i, "INFO LOG");
}
if (writeObjectCode) {
for (i = 0; i < numCompilers; ++i) {
LogMsg("BEGIN", "COMPILER", i, "OBJ CODE");
puts(ShGetObjectCode(compilers[i]));
LogMsg("END", "COMPILER", i, "OBJ CODE");
}
}
for (i = 0; i < numCompilers; ++i)
ShDestruct(compilers[i]);
if (vertexCompiler)
ShDestruct(vertexCompiler);
if (fragmentCompiler)
ShDestruct(fragmentCompiler);
ShFinalize();
return compileFailed ? EFailCompile : ESuccess;
return failCode;
}
//
......@@ -133,7 +149,7 @@ static EShLanguage FindLanguage(char *name)
//
// Read a file's data into a string, and compile it using ShCompile
//
bool CompileFile(char *fileName, ShHandle compiler, int debugOptions, const TBuiltInResource *resources)
bool CompileFile(char *fileName, ShHandle compiler, int debugOptions)
{
int ret;
char **data = ReadFileData(fileName);
......@@ -141,7 +157,7 @@ bool CompileFile(char *fileName, ShHandle compiler, int debugOptions, const TBui
if (!data)
return false;
ret = ShCompile(compiler, data, OutputMultipleStrings, EShOptNone, resources, debugOptions);
ret = ShCompile(compiler, data, OutputMultipleStrings, EShOptNone, debugOptions);
FreeFileData(data);
......@@ -229,13 +245,3 @@ void LogMsg(char* msg, const char* name, const int num, const char* logName)
"#### %s %s INFO LOG ####\n", msg, name, num, logName);
}
int ShOutputMultipleStrings(char** argv)
{
if(!(abs(OutputMultipleStrings = atoi(*argv)))||((OutputMultipleStrings >5 || OutputMultipleStrings < 1)? 1:0)){
printf("Invalid Command Line Argument after -c option.\n"
"Usage: -c <integer> where integer =[1,5]\n"
"This option must be specified before the input file path\n");
return 0;
}
return 1;
}
......@@ -17,19 +17,18 @@ typedef TVector<TString> TBuiltInStrings;
class TBuiltIns {
public:
POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
void initialize();
void initialize(const TBuiltInResource& resources);
TBuiltInStrings* getBuiltInStrings() { return builtInStrings; }
POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
void initialize(EShLanguage language, EShSpec spec, const TBuiltInResource& resources);
const TBuiltInStrings& getBuiltInStrings() { return builtInStrings; }
protected:
TBuiltInStrings builtInStrings[EShLangCount];
TBuiltInStrings builtInStrings;
};
void IdentifyBuiltIns(EShLanguage, TSymbolTable&);
void IdentifyBuiltIns(EShLanguage, TSymbolTable&, const TBuiltInResource &resources);
bool GenerateBuiltInSymbolTable(const TBuiltInResource* resources, TInfoSink&, TSymbolTable*, EShLanguage language = EShLangCount);
bool InitializeSymbolTable(TBuiltInStrings* BuiltInStrings, EShLanguage language, TInfoSink& infoSink, const TBuiltInResource *resources, TSymbolTable*);
const char* GetPreprocessorBuiltinString();
void IdentifyBuiltIns(EShLanguage language, EShSpec spec, const TBuiltInResource& resources,
TSymbolTable& symbolTable);
extern "C" int InitPreprocessor(void);
extern "C" int FinalizePreprocessor(void);
......
......@@ -17,6 +17,7 @@
#include "GLSLANG/ShaderLang.h"
#include "compiler/InfoSink.h"
#include "compiler/SymbolTable.h"
class TCompiler;
class TIntermNode;
......@@ -40,18 +41,24 @@ public:
TCompiler(EShLanguage l, EShSpec s) : language(l), spec(s) { }
virtual ~TCompiler() { }
EShLanguage getLanguage() { return language; }
EShSpec getSpec() { return spec; }
virtual TInfoSink& getInfoSink() { return infoSink; }
EShLanguage getLanguage() const { return language; }
EShSpec getSpec() const { return spec; }
TSymbolTable& getSymbolTable() { return symbolTable; }
TInfoSink& getInfoSink() { return infoSink; }
virtual bool compile(TIntermNode* root) = 0;
virtual TCompiler* getAsCompiler() { return this; }
TInfoSink infoSink;
protected:
EShLanguage language;
EShSpec spec;
// Built-in symbol table for the given language, spec, and resources.
// It is preserved from compile-to-compile.
TSymbolTable symbolTable;
// Output sink.
TInfoSink infoSink;
};
//
......
......@@ -17,15 +17,68 @@
#include "compiler/ShHandle.h"
#include "compiler/SymbolTable.h"
//
// A symbol table for each language. Each has a different
// set of built-ins, and we want to preserve that from
// compile to compile.
//
TSymbolTable* SymbolTables[EShLangCount];
static bool InitializeSymbolTable(
const TBuiltInStrings& builtInStrings,
EShLanguage language, EShSpec spec, const TBuiltInResource& resources,
TInfoSink& infoSink, TSymbolTable& symbolTable)
{
TIntermediate intermediate(infoSink);
TParseContext parseContext(symbolTable, intermediate, language, spec, infoSink);
GlobalParseContext = &parseContext;
setInitialState();
assert(symbolTable.isEmpty());
//
// Parse the built-ins. This should only happen once per
// language symbol table.
//
// Push the symbol table to give it an initial scope. This
// push should not have a corresponding pop, so that built-ins
// are preserved, and the test for an empty table fails.
//
symbolTable.push();
//Initialize the Preprocessor
if (InitPreprocessor())
{
infoSink.info.message(EPrefixInternalError, "Unable to intialize the Preprocessor");
return false;
}
for (TBuiltInStrings::const_iterator i = builtInStrings.begin(); i != builtInStrings.end(); ++i)
{
const char* builtInShaders[1];
int builtInLengths[1];
builtInShaders[0] = (*i).c_str();
builtInLengths[0] = (int) (*i).size();
if (PaParseStrings(const_cast<char**>(builtInShaders), builtInLengths, 1, parseContext) != 0)
{
infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
return false;
}
}
IdentifyBuiltIns(language, spec, resources, symbolTable);
FinalizePreprocessor();
return true;
}
static bool GenerateBuiltInSymbolTable(
EShLanguage language, EShSpec spec, const TBuiltInResource& resources,
TInfoSink& infoSink, TSymbolTable& symbolTable)
{
TBuiltIns builtIns;
builtIns.initialize(language, spec, resources);
return InitializeSymbolTable(builtIns.getBuiltInStrings(), language, spec, resources, infoSink, symbolTable);
}
TPoolAllocator* PerProcessGPA = 0;
//
// This is the platform independent interface between an OGL driver
// and the shading language compiler.
......@@ -37,42 +90,7 @@ TPoolAllocator* PerProcessGPA = 0;
//
int ShInitialize()
{
TInfoSink infoSink;
bool ret = true;
if (!InitProcess())
return 0;
// This method should be called once per process. If its called by multiple threads, then
// we need to have thread synchronization code around the initialization of per process
// global pool allocator
if (!PerProcessGPA) {
TPoolAllocator *builtInPoolAllocator = new TPoolAllocator(true);
builtInPoolAllocator->push();
TPoolAllocator* gPoolAllocator = &GlobalPoolAllocator;
SetGlobalPoolAllocatorPtr(builtInPoolAllocator);
TSymbolTable symTables[EShLangCount];
GenerateBuiltInSymbolTable(0, infoSink, symTables);
PerProcessGPA = new TPoolAllocator(true);
PerProcessGPA->push();
SetGlobalPoolAllocatorPtr(PerProcessGPA);
SymbolTables[EShLangVertex] = new TSymbolTable;
SymbolTables[EShLangVertex]->copyTable(symTables[EShLangVertex]);
SymbolTables[EShLangFragment] = new TSymbolTable;
SymbolTables[EShLangFragment]->copyTable(symTables[EShLangFragment]);
SetGlobalPoolAllocatorPtr(gPoolAllocator);
symTables[EShLangVertex].pop();
symTables[EShLangFragment].pop();
builtInPoolAllocator->popAll();
delete builtInPoolAllocator;
}
bool ret = InitProcess();
return ret ? 1 : 0;
}
......@@ -81,13 +99,22 @@ int ShInitialize()
// Driver calls these to create and destroy compiler objects.
//
ShHandle ShConstructCompiler(EShLanguage language, EShSpec spec)
ShHandle ShConstructCompiler(EShLanguage language, EShSpec spec, const TBuiltInResource* resources)
{
if (!InitThread())
return 0;
TShHandleBase* base = static_cast<TShHandleBase*>(ConstructCompiler(language, spec));
TCompiler* compiler = base->getAsCompiler();
if (compiler == 0)
return 0;
// Generate built-in symbol table.
if (!GenerateBuiltInSymbolTable(language, spec, *resources, compiler->getInfoSink(), compiler->getSymbolTable())) {
ShDestruct(base);
return 0;
}
return reinterpret_cast<void*>(base);
}
......@@ -106,97 +133,8 @@ void ShDestruct(ShHandle handle)
// Cleanup symbol tables
//
int ShFinalize()
{
if (PerProcessGPA) {
PerProcessGPA->popAll();
delete PerProcessGPA;
PerProcessGPA = 0;
}
for (int i = 0; i < EShLangCount; ++i) {
delete SymbolTables[i];
SymbolTables[i] = 0;
}
return 1;
}
bool GenerateBuiltInSymbolTable(const TBuiltInResource* resources, TInfoSink& infoSink, TSymbolTable* symbolTables, EShLanguage language)
{
TBuiltIns builtIns;
if (resources) {
builtIns.initialize(*resources);
InitializeSymbolTable(builtIns.getBuiltInStrings(), language, infoSink, resources, symbolTables);
} else {
builtIns.initialize();
InitializeSymbolTable(builtIns.getBuiltInStrings(), EShLangVertex, infoSink, resources, symbolTables);
InitializeSymbolTable(builtIns.getBuiltInStrings(), EShLangFragment, infoSink, resources, symbolTables);
}
return true;
}
bool InitializeSymbolTable(TBuiltInStrings* BuiltInStrings, EShLanguage language, TInfoSink& infoSink, const TBuiltInResource* resources, TSymbolTable* symbolTables)
{
TIntermediate intermediate(infoSink);
TSymbolTable* symbolTable;
if (resources)
symbolTable = symbolTables;
else
symbolTable = &symbolTables[language];
// TODO(alokp): Investigate if a parse-context is necessary here and
// if symbol-table can be shared between GLES2 and WebGL specs.
TParseContext parseContext(*symbolTable, intermediate, language, EShSpecGLES2, infoSink);
GlobalParseContext = &parseContext;
setInitialState();
assert(symbolTable->isEmpty() || symbolTable->atSharedBuiltInLevel());
//
// Parse the built-ins. This should only happen once per
// language symbol table.
//
// Push the symbol table to give it an initial scope. This
// push should not have a corresponding pop, so that built-ins
// are preserved, and the test for an empty table fails.
//
symbolTable->push();
//Initialize the Preprocessor
int ret = InitPreprocessor();
if (ret) {
infoSink.info.message(EPrefixInternalError, "Unable to intialize the Preprocessor");
return false;
}
for (TBuiltInStrings::iterator i = BuiltInStrings[parseContext.language].begin();
i != BuiltInStrings[parseContext.language].end();
++i) {
const char* builtInShaders[1];
int builtInLengths[1];
builtInShaders[0] = (*i).c_str();
builtInLengths[0] = (int) (*i).size();
if (PaParseStrings(const_cast<char**>(builtInShaders), builtInLengths, 1, parseContext) != 0) {
infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
return false;
}
}
if (resources) {
IdentifyBuiltIns(parseContext.language, *symbolTable, *resources);
} else {
IdentifyBuiltIns(parseContext.language, *symbolTable);
}
FinalizePreprocessor();
return true;
return 1;
}
//
......@@ -211,7 +149,6 @@ int ShCompile(
const char* const shaderStrings[],
const int numStrings,
const EShOptimizationLevel optLevel,
const TBuiltInResource* resources,
int debugOptions
)
{
......@@ -227,7 +164,7 @@ int ShCompile(
return 0;
GlobalPoolAllocator.push();
TInfoSink& infoSink = compiler->infoSink;
TInfoSink& infoSink = compiler->getInfoSink();
infoSink.info.erase();
infoSink.debug.erase();
infoSink.obj.erase();
......@@ -236,25 +173,22 @@ int ShCompile(
return 1;
TIntermediate intermediate(infoSink);
TSymbolTable symbolTable(*SymbolTables[compiler->getLanguage()]);
GenerateBuiltInSymbolTable(resources, infoSink, &symbolTable, compiler->getLanguage());
TSymbolTable& symbolTable = compiler->getSymbolTable();
TParseContext parseContext(symbolTable, intermediate, compiler->getLanguage(), compiler->getSpec(), infoSink);
parseContext.initializeExtensionBehavior();
GlobalParseContext = &parseContext;
setInitialState();
InitPreprocessor();
InitPreprocessor();
//
// Parse the application's shaders. All the following symbol table
// work will be throw-away, so push a new allocation scope that can
// be thrown away, then push a scope for the current shader's globals.
//
bool success = true;
symbolTable.push();
if (!symbolTable.atGlobalLevel())
parseContext.infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
......@@ -301,7 +235,7 @@ int ShCompile(
// Ensure symbol table is returned to the built-in level,
// throwing away all but the built-ins.
//
while (! symbolTable.atSharedBuiltInLevel())
while (!symbolTable.atBuiltInLevel())
symbolTable.pop();
FinalizePreprocessor();
......
......@@ -31,9 +31,9 @@
//
#include <assert.h>
#include "compiler/Common.h"
#include "compiler/intermediate.h"
#include "compiler/InfoSink.h"
#include "compiler/intermediate.h"
//
// Symbol base class. (Can build functions or variables out of these...)
......@@ -239,13 +239,6 @@ public:
//
}
TSymbolTable(TSymbolTable& symTable)
{
table.push_back(symTable.table[0]);
precisionStack.push_back( symTable.precisionStack[0] );
uniqueId = symTable.uniqueId;
}
~TSymbolTable()
{
// level 0 is always built In symbols, so we never pop that out
......@@ -259,11 +252,10 @@ public:
// globals are at level 1.
//
bool isEmpty() { return table.size() == 0; }
bool atBuiltInLevel() { return atSharedBuiltInLevel() || atDynamicBuiltInLevel(); }
bool atSharedBuiltInLevel() { return table.size() == 1; }
bool atGlobalLevel() { return table.size() <= 3; }
bool atBuiltInLevel() { return table.size() == 1; }
bool atGlobalLevel() { return table.size() <= 2; }
void push()
{
{
table.push_back(new TSymbolTableLevel);
precisionStack.push_back( PrecisionStackLevel() );
}
......@@ -297,7 +289,7 @@ public:
return symbol;
}
TSymbolTableLevel* getGlobalLevel() { assert(table.size() >= 3); return table[2]; }
TSymbolTableLevel* getGlobalLevel() { assert(table.size() >= 2); return table[1]; }
void relateToOperator(const char* name, TOperator op) { table[0]->relateToOperator(name, op); }
int getMaxSymbolId() { return uniqueId; }
void dump(TInfoSink &infoSink) const;
......@@ -329,7 +321,6 @@ public:
protected:
int currentLevel() const { return static_cast<int>(table.size()) - 1; }
bool atDynamicBuiltInLevel() { return table.size() == 2; }
std::vector<TSymbolTableLevel*> table;
typedef std::map< TBasicType, TPrecision > PrecisionStackLevel;
......
......@@ -34,8 +34,18 @@ Shader::Shader(Context *context, GLuint handle) : mHandle(handle), mContext(cont
if (result)
{
mFragmentCompiler = ShConstructCompiler(EShLangFragment, EShSpecGLES2);
mVertexCompiler = ShConstructCompiler(EShLangVertex, EShSpecGLES2);
TBuiltInResource resources;
resources.maxVertexAttribs = MAX_VERTEX_ATTRIBS;
resources.maxVertexUniformVectors = MAX_VERTEX_UNIFORM_VECTORS;
resources.maxVaryingVectors = MAX_VARYING_VECTORS;
resources.maxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS;
resources.maxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS;
resources.maxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
resources.maxFragmentUniformVectors = MAX_FRAGMENT_UNIFORM_VECTORS;
resources.maxDrawBuffers = MAX_DRAW_BUFFERS;
mFragmentCompiler = ShConstructCompiler(EShLangFragment, EShSpecGLES2, &resources);
mVertexCompiler = ShConstructCompiler(EShLangVertex, EShSpecGLES2, &resources);
}
}
......@@ -267,18 +277,7 @@ void Shader::compileToHLSL(void *compiler)
delete[] mInfoLog;
mInfoLog = NULL;
TBuiltInResource resources;
resources.maxVertexAttribs = MAX_VERTEX_ATTRIBS;
resources.maxVertexUniformVectors = MAX_VERTEX_UNIFORM_VECTORS;
resources.maxVaryingVectors = MAX_VARYING_VECTORS;
resources.maxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS;
resources.maxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS;
resources.maxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
resources.maxFragmentUniformVectors = MAX_FRAGMENT_UNIFORM_VECTORS;
resources.maxDrawBuffers = MAX_DRAW_BUFFERS;
int result = ShCompile(compiler, &mSource, 1, EShOptNone, &resources, EDebugOpNone);
int result = ShCompile(compiler, &mSource, 1, EShOptNone, EDebugOpNone);
const char *obj = ShGetObjectCode(compiler);
const char *info = ShGetInfoLog(compiler);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment