Standalone: Rationalize ShaderCompUnit and file data.

ShaderCompUnit was poorly done, a mix of a list of things and hard
coding to a single thing. This makes it all a true list.

File data was greatly simplified to be a single string, no longer
supporting breaking a single file into multiple strings.
This commit is contained in:
John Kessenich 2017-06-14 17:36:50 -06:00
parent 6263fb19fb
commit 04acb1b7c9

View File

@ -115,18 +115,14 @@ enum TFailCode {
EShLanguage FindLanguage(const std::string& name, bool parseSuffix=true); EShLanguage FindLanguage(const std::string& name, bool parseSuffix=true);
void CompileFile(const char* fileName, ShHandle); void CompileFile(const char* fileName, ShHandle);
void usage(); void usage();
void FreeFileData(char** data); char* ReadFileData(const char* fileName);
char** ReadFileData(const char* fileName); void FreeFileData(char* data);
void InfoLogMsg(const char* msg, const char* name, const int num); void InfoLogMsg(const char* msg, const char* name, const int num);
// Globally track if any compile or link failure. // Globally track if any compile or link failure.
bool CompileFailed = false; bool CompileFailed = false;
bool LinkFailed = false; bool LinkFailed = false;
// Use to test breaking up a single shader file into multiple strings.
// Set in ReadFileData().
int NumShaderStrings;
TBuiltInResource Resources; TBuiltInResource Resources;
std::string ConfigFile; std::string ConfigFile;
@ -135,29 +131,13 @@ std::string ConfigFile;
// //
void ProcessConfigFile() void ProcessConfigFile()
{ {
char** configStrings = 0; if (ConfigFile.size() == 0)
char* config = 0;
if (ConfigFile.size() > 0) {
configStrings = ReadFileData(ConfigFile.c_str());
if (configStrings)
config = *configStrings;
else {
printf("Error opening configuration file; will instead use the default configuration\n");
usage();
}
}
if (config == 0) {
Resources = glslang::DefaultTBuiltInResource; Resources = glslang::DefaultTBuiltInResource;
return; else {
char* configString = ReadFileData(ConfigFile.c_str());
glslang::DecodeResourceLimits(&Resources, configString);
FreeFileData(configString);
} }
glslang::DecodeResourceLimits(&Resources, config);
if (configStrings)
FreeFileData(configStrings);
else
delete[] config;
} }
int Options = 0; int Options = 0;
@ -594,36 +574,41 @@ void PutsIfNonEmpty(const char* str)
// This prevents erroneous newlines from appearing. // This prevents erroneous newlines from appearing.
void StderrIfNonEmpty(const char* str) void StderrIfNonEmpty(const char* str)
{ {
if (str && str[0]) { if (str && str[0])
fprintf(stderr, "%s\n", str); fprintf(stderr, "%s\n", str);
}
} }
// Simple bundling of what makes a compilation unit for ease in passing around, // Simple bundling of what makes a compilation unit for ease in passing around,
// and separation of handling file IO versus API (programmatic) compilation. // and separation of handling file IO versus API (programmatic) compilation.
struct ShaderCompUnit { struct ShaderCompUnit {
EShLanguage stage; EShLanguage stage;
std::string fileName; static const int maxCount = 1;
char** text; // memory owned/managed externally int count; // live number of strings/names
const char* fileNameList[1]; char* text[maxCount]; // memory owned/managed externally
std::string fileName[maxCount]; // hold's the memory, but...
const char* fileNameList[maxCount]; // downstream interface wants pointers
// Need to have a special constructors to adjust the fileNameList, since back end needs a list of ptrs ShaderCompUnit(EShLanguage stage) : stage(stage), count(0) { }
ShaderCompUnit(EShLanguage istage, std::string &ifileName, char** itext)
{
stage = istage;
fileName = ifileName;
text = itext;
fileNameList[0] = fileName.c_str();
}
ShaderCompUnit(const ShaderCompUnit &rhs) ShaderCompUnit(const ShaderCompUnit& rhs)
{ {
stage = rhs.stage; stage = rhs.stage;
fileName = rhs.fileName; count = rhs.count;
text = rhs.text; for (int i = 0; i < count; ++i) {
fileNameList[0] = fileName.c_str(); fileName[i] = rhs.fileName[i];
text[i] = rhs.text[i];
fileNameList[i] = rhs.fileName[i].c_str();
}
} }
void addString(std::string& ifileName, char* itext)
{
assert(count < maxCount);
fileName[count] = ifileName;
text[count] = itext;
fileNameList[count] = fileName[count].c_str();
++count;
}
}; };
// //
@ -650,7 +635,7 @@ void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
for (auto it = compUnits.cbegin(); it != compUnits.cend(); ++it) { for (auto it = compUnits.cbegin(); it != compUnits.cend(); ++it) {
const auto &compUnit = *it; const auto &compUnit = *it;
glslang::TShader* shader = new glslang::TShader(compUnit.stage); glslang::TShader* shader = new glslang::TShader(compUnit.stage);
shader->setStringsWithLengthsAndNames(compUnit.text, NULL, compUnit.fileNameList, 1); shader->setStringsWithLengthsAndNames(compUnit.text, NULL, compUnit.fileNameList, compUnit.count);
if (entryPointName) // HLSL todo: this needs to be tracked per compUnits if (entryPointName) // HLSL todo: this needs to be tracked per compUnits
shader->setEntryPoint(entryPointName); shader->setEntryPoint(entryPointName);
if (sourceEntryPointName) if (sourceEntryPointName)
@ -701,7 +686,7 @@ void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
if (! (Options & EOptionSuppressInfolog) && if (! (Options & EOptionSuppressInfolog) &&
! (Options & EOptionMemoryLeakMode)) { ! (Options & EOptionMemoryLeakMode)) {
PutsIfNonEmpty(compUnit.fileName.c_str()); PutsIfNonEmpty(compUnit.fileName[0].c_str());
PutsIfNonEmpty(shader->getInfoLog()); PutsIfNonEmpty(shader->getInfoLog());
PutsIfNonEmpty(shader->getInfoDebugLog()); PutsIfNonEmpty(shader->getInfoDebugLog());
} }
@ -802,17 +787,11 @@ void CompileAndLinkShaderFiles(glslang::TWorklist& Worklist)
// they are all getting linked together.) // they are all getting linked together.)
glslang::TWorkItem* workItem; glslang::TWorkItem* workItem;
while (Worklist.remove(workItem)) { while (Worklist.remove(workItem)) {
ShaderCompUnit compUnit( ShaderCompUnit compUnit(FindLanguage(workItem->name));
FindLanguage(workItem->name), char* fileText = ReadFileData(workItem->name.c_str());
workItem->name, if (fileText == nullptr)
ReadFileData(workItem->name.c_str())
);
if (! compUnit.text) {
usage(); usage();
return; compUnit.addString(workItem->name, fileText);
}
compUnits.push_back(compUnit); compUnits.push_back(compUnit);
} }
@ -828,7 +807,7 @@ void CompileAndLinkShaderFiles(glslang::TWorklist& Worklist)
} }
for (auto it = compUnits.begin(); it != compUnits.end(); ++it) for (auto it = compUnits.begin(); it != compUnits.end(); ++it)
FreeFileData(it->text); FreeFileData(it->text[0]);
} }
int C_DECL main(int argc, char* argv[]) int C_DECL main(int argc, char* argv[])
@ -978,21 +957,11 @@ EShLanguage FindLanguage(const std::string& name, bool parseSuffix)
void CompileFile(const char* fileName, ShHandle compiler) void CompileFile(const char* fileName, ShHandle compiler)
{ {
int ret = 0; int ret = 0;
char** shaderStrings = ReadFileData(fileName); char* shaderString = ReadFileData(fileName);
if (! shaderStrings) {
usage();
}
int* lengths = new int[NumShaderStrings];
// move to length-based strings, rather than null-terminated strings // move to length-based strings, rather than null-terminated strings
for (int s = 0; s < NumShaderStrings; ++s) int* lengths = new int[1];
lengths[s] = (int)strlen(shaderStrings[s]); lengths[0] = (int)strlen(shaderString);
if (! shaderStrings) {
CompileFailed = true;
return;
}
EShMessages messages = EShMsgDefault; EShMessages messages = EShMsgDefault;
SetMessageOptions(messages); SetMessageOptions(messages);
@ -1000,7 +969,7 @@ void CompileFile(const char* fileName, ShHandle compiler)
for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) { for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) {
for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j) { for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j) {
// ret = ShCompile(compiler, shaderStrings, NumShaderStrings, lengths, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages); // ret = ShCompile(compiler, shaderStrings, NumShaderStrings, lengths, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
ret = ShCompile(compiler, shaderStrings, NumShaderStrings, nullptr, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages); ret = ShCompile(compiler, &shaderString, 1, nullptr, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
// const char* multi[12] = { "# ve", "rsion", " 300 e", "s", "\n#err", // const char* multi[12] = { "# ve", "rsion", " 300 e", "s", "\n#err",
// "or should be l", "ine 1", "string 5\n", "float glo", "bal", // "or should be l", "ine 1", "string 5\n", "float glo", "bal",
// ";\n#error should be line 2\n void main() {", "global = 2.3;}" }; // ";\n#error should be line 2\n void main() {", "global = 2.3;}" };
@ -1013,7 +982,7 @@ void CompileFile(const char* fileName, ShHandle compiler)
} }
delete [] lengths; delete [] lengths;
FreeFileData(shaderStrings); FreeFileData(shaderString);
if (ret == 0) if (ret == 0)
CompileFailed = true; CompileFailed = true;
@ -1144,76 +1113,33 @@ int fopen_s(
// //
// Malloc a string of sufficient size and read a string into it. // Malloc a string of sufficient size and read a string into it.
// //
char** ReadFileData(const char* fileName) char* ReadFileData(const char* fileName)
{ {
FILE *in = nullptr; FILE *in = nullptr;
int errorCode = fopen_s(&in, fileName, "r"); int errorCode = fopen_s(&in, fileName, "r");
int count = 0;
const int maxSourceStrings = 5; // for testing splitting shader/tokens across multiple strings
char** return_data = (char**)malloc(sizeof(char *) * (maxSourceStrings+1)); // freed in FreeFileData()
if (errorCode || in == nullptr) if (errorCode || in == nullptr)
Error("unable to open input file"); Error("unable to open input file");
int count = 0;
while (fgetc(in) != EOF) while (fgetc(in) != EOF)
count++; count++;
fseek(in, 0, SEEK_SET); fseek(in, 0, SEEK_SET);
char *fdata = (char*)malloc(count+2); // freed before return of this function char* return_data = (char*)malloc(count + 1); // freed in FreeFileData()
if (! fdata) if ((int)fread(return_data, 1, count, in) != count) {
Error("can't allocate memory"); free(return_data);
if ((int)fread(fdata, 1, count, in) != count) {
free(fdata);
Error("can't read input file"); Error("can't read input file");
} }
fdata[count] = '\0'; return_data[count] = '\0';
fclose(in); fclose(in);
if (count == 0) {
// recover from empty file
return_data[0] = (char*)malloc(count+2); // freed in FreeFileData()
return_data[0][0]='\0';
NumShaderStrings = 0;
free(fdata);
return return_data;
} else
NumShaderStrings = 1; // Set to larger than 1 for testing multiple strings
// compute how to split up the file into multiple strings, for testing multiple strings
int len = (int)(ceil)((float)count/(float)NumShaderStrings);
int ptr_len = 0;
int i = 0;
while (count > 0) {
return_data[i] = (char*)malloc(len + 2); // freed in FreeFileData()
memcpy(return_data[i], fdata + ptr_len, len);
return_data[i][len] = '\0';
count -= len;
ptr_len += len;
if (count < len) {
if (count == 0) {
NumShaderStrings = i + 1;
break;
}
len = count;
}
++i;
}
free(fdata);
return return_data; return return_data;
} }
void FreeFileData(char** data) void FreeFileData(char* data)
{ {
for(int i = 0; i < NumShaderStrings; i++)
free(data[i]);
free(data); free(data);
} }