Updated command-line options, adding -o for saving binaries, -G for OpenGL SPIR-V validation, -v etc.
Old uses should still work as they did before. Also encapsulated use of these flags during parsing, for the parse context. Added SPIR-V version to -v.
This commit is contained in:
@@ -2543,13 +2543,18 @@ spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangT
|
|||||||
|
|
||||||
namespace glslang {
|
namespace glslang {
|
||||||
|
|
||||||
|
void GetSpirvVersion(std::string& version)
|
||||||
|
{
|
||||||
|
char buf[10];
|
||||||
|
snprintf(buf, "0.%d", spv::Version);
|
||||||
|
version = buf;
|
||||||
|
}
|
||||||
|
|
||||||
// Write SPIR-V out to a binary file
|
// Write SPIR-V out to a binary file
|
||||||
void OutputSpv(const std::vector<unsigned int>& spirv, const char* baseName)
|
void OutputSpv(const std::vector<unsigned int>& spirv, const char* baseName)
|
||||||
{
|
{
|
||||||
std::ofstream out;
|
std::ofstream out;
|
||||||
std::string fileName(baseName);
|
out.open(baseName, std::ios::binary | std::ios::out);
|
||||||
fileName.append(".spv");
|
|
||||||
out.open(fileName.c_str(), std::ios::binary | std::ios::out);
|
|
||||||
for (int i = 0; i < (int)spirv.size(); ++i) {
|
for (int i = 0; i < (int)spirv.size(); ++i) {
|
||||||
unsigned int word = spirv[i];
|
unsigned int word = spirv[i];
|
||||||
out.write((const char*)&word, 4);
|
out.write((const char*)&word, 4);
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
|
|
||||||
namespace glslang {
|
namespace glslang {
|
||||||
|
|
||||||
|
void GetSpirvVersion(std::string&);
|
||||||
void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv);
|
void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv);
|
||||||
void OutputSpv(const std::vector<unsigned int>& spirv, const char* baseName);
|
void OutputSpv(const std::vector<unsigned int>& spirv, const char* baseName);
|
||||||
|
|
||||||
|
|||||||
@@ -70,12 +70,13 @@ enum TOptions {
|
|||||||
EOptionDumpVersions = 0x0400,
|
EOptionDumpVersions = 0x0400,
|
||||||
EOptionSpv = 0x0800,
|
EOptionSpv = 0x0800,
|
||||||
EOptionHumanReadableSpv = 0x1000,
|
EOptionHumanReadableSpv = 0x1000,
|
||||||
EOptionDefaultDesktop = 0x2000,
|
EOptionVulkanRules = 0x2000,
|
||||||
EOptionOutputPreprocessed = 0x4000,
|
EOptionDefaultDesktop = 0x4000,
|
||||||
|
EOptionOutputPreprocessed = 0x8000,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// Return codes from main.
|
// Return codes from main/exit().
|
||||||
//
|
//
|
||||||
enum TFailCode {
|
enum TFailCode {
|
||||||
ESuccess = 0,
|
ESuccess = 0,
|
||||||
@@ -88,18 +89,8 @@ enum TFailCode {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// Just placeholders for testing purposes. The stand-alone environment
|
// Forward declarations.
|
||||||
// can't actually do a full link without something specifying real
|
|
||||||
// attribute bindings.
|
|
||||||
//
|
//
|
||||||
ShBinding FixedAttributeBindings[] = {
|
|
||||||
{ "gl_Vertex", 15 },
|
|
||||||
{ "gl_Color", 10 },
|
|
||||||
{ "gl_Normal", 7 },
|
|
||||||
};
|
|
||||||
|
|
||||||
ShBindingTable FixedAttributeTable = { 3, FixedAttributeBindings };
|
|
||||||
|
|
||||||
EShLanguage FindLanguage(const std::string& name);
|
EShLanguage FindLanguage(const std::string& name);
|
||||||
void CompileFile(const char* fileName, ShHandle);
|
void CompileFile(const char* fileName, ShHandle);
|
||||||
void usage();
|
void usage();
|
||||||
@@ -112,6 +103,7 @@ bool CompileFailed = false;
|
|||||||
bool LinkFailed = false;
|
bool LinkFailed = false;
|
||||||
|
|
||||||
// Use to test breaking up a single shader file into multiple strings.
|
// Use to test breaking up a single shader file into multiple strings.
|
||||||
|
// Set in ReadFileData().
|
||||||
int NumShaderStrings;
|
int NumShaderStrings;
|
||||||
|
|
||||||
TBuiltInResource Resources;
|
TBuiltInResource Resources;
|
||||||
@@ -452,7 +444,30 @@ glslang::TWorkItem** Work = 0;
|
|||||||
int NumWorkItems = 0;
|
int NumWorkItems = 0;
|
||||||
|
|
||||||
int Options = 0;
|
int Options = 0;
|
||||||
const char* ExecutableName;
|
const char* ExecutableName = nullptr;
|
||||||
|
const char* binaryFileName = nullptr;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Create the default name for saving a binary if -o is not provided.
|
||||||
|
//
|
||||||
|
const char* GetBinaryName(EShLanguage stage)
|
||||||
|
{
|
||||||
|
const char* name;
|
||||||
|
if (binaryFileName == nullptr) {
|
||||||
|
switch (stage) {
|
||||||
|
case EShLangVertex: name = "vert.spv"; break;
|
||||||
|
case EShLangTessControl: name = "tesc.spv"; break;
|
||||||
|
case EShLangTessEvaluation: name = "tese.spv"; break;
|
||||||
|
case EShLangGeometry: name = "geom.spv"; break;
|
||||||
|
case EShLangFragment: name = "frag.spv"; break;
|
||||||
|
case EShLangCompute: name = "comp.spv"; break;
|
||||||
|
default: name = "unknown"; break;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
name = binaryFileName;
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// *.conf => this is a config file that can set limits/resources
|
// *.conf => this is a config file that can set limits/resources
|
||||||
@@ -470,23 +485,43 @@ bool SetConfigFile(const std::string& name)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProcessArguments(int argc, char* argv[])
|
//
|
||||||
|
// Give error and exit with failure code.
|
||||||
|
//
|
||||||
|
void Error(const char* message)
|
||||||
|
{
|
||||||
|
printf("%s: Error %s (use -h for usage)\n", ExecutableName, message);
|
||||||
|
exit(EFailUsage);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Do all command-line argument parsing. This includes building up the work-items
|
||||||
|
// to be processed later, and saving all the command-line options.
|
||||||
|
//
|
||||||
|
// Does not return (it exits) if command-line is fatally flawed.
|
||||||
|
//
|
||||||
|
void ProcessArguments(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
ExecutableName = argv[0];
|
ExecutableName = argv[0];
|
||||||
NumWorkItems = argc; // will include some empties where the '-' options were, but it doesn't matter, they'll be 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 = new glslang::TWorkItem*[NumWorkItems];
|
||||||
Work[0] = 0;
|
for (int w = 0; w < NumWorkItems; ++w)
|
||||||
|
Work[w] = 0;
|
||||||
|
|
||||||
argc--;
|
argc--;
|
||||||
argv++;
|
argv++;
|
||||||
for (; argc >= 1; argc--, argv++) {
|
for (; argc >= 1; argc--, argv++) {
|
||||||
Work[argc] = 0;
|
|
||||||
if (argv[0][0] == '-') {
|
if (argv[0][0] == '-') {
|
||||||
switch (argv[0][1]) {
|
switch (argv[0][1]) {
|
||||||
case 'H':
|
case 'H':
|
||||||
Options |= EOptionHumanReadableSpv;
|
Options |= EOptionHumanReadableSpv;
|
||||||
// fall through to -V
|
// fall through to -V
|
||||||
case 'V':
|
case 'V':
|
||||||
|
Options |= EOptionSpv;
|
||||||
|
Options |= EOptionVulkanRules;
|
||||||
|
Options |= EOptionLinkProgram;
|
||||||
|
break;
|
||||||
|
case 'G':
|
||||||
Options |= EOptionSpv;
|
Options |= EOptionSpv;
|
||||||
Options |= EOptionLinkProgram;
|
Options |= EOptionLinkProgram;
|
||||||
break;
|
break;
|
||||||
@@ -499,6 +534,9 @@ bool ProcessArguments(int argc, char* argv[])
|
|||||||
case 'd':
|
case 'd':
|
||||||
Options |= EOptionDefaultDesktop;
|
Options |= EOptionDefaultDesktop;
|
||||||
break;
|
break;
|
||||||
|
case 'h':
|
||||||
|
usage();
|
||||||
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
Options |= EOptionIntermediate;
|
Options |= EOptionIntermediate;
|
||||||
break;
|
break;
|
||||||
@@ -508,6 +546,14 @@ bool ProcessArguments(int argc, char* argv[])
|
|||||||
case 'm':
|
case 'm':
|
||||||
Options |= EOptionMemoryLeakMode;
|
Options |= EOptionMemoryLeakMode;
|
||||||
break;
|
break;
|
||||||
|
case 'o':
|
||||||
|
binaryFileName = argv[1];
|
||||||
|
if (argc > 0) {
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
} else
|
||||||
|
Error("no <file> provided for -o");
|
||||||
|
break;
|
||||||
case 'q':
|
case 'q':
|
||||||
Options |= EOptionDumpReflection;
|
Options |= EOptionDumpReflection;
|
||||||
break;
|
break;
|
||||||
@@ -529,7 +575,8 @@ bool ProcessArguments(int argc, char* argv[])
|
|||||||
Options |= EOptionSuppressWarnings;
|
Options |= EOptionSuppressWarnings;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
usage();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
std::string name(argv[0]);
|
std::string name(argv[0]);
|
||||||
@@ -540,16 +587,18 @@ bool ProcessArguments(int argc, char* argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that -E is not specified alongside -V -H or -l.
|
// Make sure that -E is not specified alongside linking (which includes SPV generation)
|
||||||
if (Options & EOptionOutputPreprocessed &&
|
if ((Options & EOptionOutputPreprocessed) && (Options & EOptionLinkProgram))
|
||||||
((Options &
|
Error("can't use -E when linking is selected");
|
||||||
(EOptionSpv | EOptionHumanReadableSpv | EOptionLinkProgram)))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
// -o makes no sense if there is no target binary
|
||||||
|
if (binaryFileName && (Options & EOptionSpv) == 0)
|
||||||
|
Error("no binary generation requested (e.g., -V)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Translate the meaningful subset of command-line options to parser-behavior options.
|
||||||
|
//
|
||||||
void SetMessageOptions(EShMessages& messages)
|
void SetMessageOptions(EShMessages& messages)
|
||||||
{
|
{
|
||||||
if (Options & EOptionRelaxedErrors)
|
if (Options & EOptionRelaxedErrors)
|
||||||
@@ -558,8 +607,13 @@ void SetMessageOptions(EShMessages& messages)
|
|||||||
messages = (EShMessages)(messages | EShMsgAST);
|
messages = (EShMessages)(messages | EShMsgAST);
|
||||||
if (Options & EOptionSuppressWarnings)
|
if (Options & EOptionSuppressWarnings)
|
||||||
messages = (EShMessages)(messages | EShMsgSuppressWarnings);
|
messages = (EShMessages)(messages | EShMsgSuppressWarnings);
|
||||||
|
if (Options & EOptionSpv)
|
||||||
|
messages = (EShMessages)(messages | EShMsgSpvRules);
|
||||||
|
if (Options & EOptionVulkanRules)
|
||||||
|
messages = (EShMessages)(messages | EShMsgVulkanRules);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
// Thread entry point, for non-linking asynchronous mode.
|
// Thread entry point, for non-linking asynchronous mode.
|
||||||
//
|
//
|
||||||
// Return 0 for failure, 1 for success.
|
// Return 0 for failure, 1 for success.
|
||||||
@@ -658,7 +712,7 @@ void CompileAndLinkShaders()
|
|||||||
// Program-level processing...
|
// Program-level processing...
|
||||||
//
|
//
|
||||||
|
|
||||||
if (!(Options & EOptionOutputPreprocessed) && ! program.link(messages))
|
if (! (Options & EOptionOutputPreprocessed) && ! program.link(messages))
|
||||||
LinkFailed = true;
|
LinkFailed = true;
|
||||||
|
|
||||||
if (! (Options & EOptionSuppressInfolog)) {
|
if (! (Options & EOptionSuppressInfolog)) {
|
||||||
@@ -673,23 +727,13 @@ void CompileAndLinkShaders()
|
|||||||
|
|
||||||
if (Options & EOptionSpv) {
|
if (Options & EOptionSpv) {
|
||||||
if (CompileFailed || LinkFailed)
|
if (CompileFailed || LinkFailed)
|
||||||
printf("SPIRV is not generated for failed compile or link\n");
|
printf("SPIR-V is not generated for failed compile or link\n");
|
||||||
else {
|
else {
|
||||||
for (int stage = 0; stage < EShLangCount; ++stage) {
|
for (int stage = 0; stage < EShLangCount; ++stage) {
|
||||||
if (program.getIntermediate((EShLanguage)stage)) {
|
if (program.getIntermediate((EShLanguage)stage)) {
|
||||||
std::vector<unsigned int> spirv;
|
std::vector<unsigned int> spirv;
|
||||||
glslang::GlslangToSpv(*program.getIntermediate((EShLanguage)stage), spirv);
|
glslang::GlslangToSpv(*program.getIntermediate((EShLanguage)stage), spirv);
|
||||||
const char* name;
|
glslang::OutputSpv(spirv, GetBinaryName((EShLanguage)stage));
|
||||||
switch (stage) {
|
|
||||||
case EShLangVertex: name = "vert"; break;
|
|
||||||
case EShLangTessControl: name = "tesc"; break;
|
|
||||||
case EShLangTessEvaluation: name = "tese"; break;
|
|
||||||
case EShLangGeometry: name = "geom"; break;
|
|
||||||
case EShLangFragment: name = "frag"; break;
|
|
||||||
case EShLangCompute: name = "comp"; break;
|
|
||||||
default: name = "unknown"; break;
|
|
||||||
}
|
|
||||||
glslang::OutputSpv(spirv, name);
|
|
||||||
if (Options & EOptionHumanReadableSpv) {
|
if (Options & EOptionHumanReadableSpv) {
|
||||||
spv::Parameterize();
|
spv::Parameterize();
|
||||||
GLSL_STD_450::GetDebugNames(GlslStd450DebugNames);
|
GLSL_STD_450::GetDebugNames(GlslStd450DebugNames);
|
||||||
@@ -713,10 +757,7 @@ void CompileAndLinkShaders()
|
|||||||
|
|
||||||
int C_DECL main(int argc, char* argv[])
|
int C_DECL main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
if (! ProcessArguments(argc, argv)) {
|
ProcessArguments(argc, argv);
|
||||||
usage();
|
|
||||||
return EFailUsage;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Options & EOptionDumpConfig) {
|
if (Options & EOptionDumpConfig) {
|
||||||
printf("%s", DefaultConfig);
|
printf("%s", DefaultConfig);
|
||||||
@@ -727,13 +768,15 @@ int C_DECL main(int argc, char* argv[])
|
|||||||
if (Options & EOptionDumpVersions) {
|
if (Options & EOptionDumpVersions) {
|
||||||
printf("ESSL Version: %s\n", glslang::GetEsslVersionString());
|
printf("ESSL Version: %s\n", glslang::GetEsslVersionString());
|
||||||
printf("GLSL Version: %s\n", glslang::GetGlslVersionString());
|
printf("GLSL Version: %s\n", glslang::GetGlslVersionString());
|
||||||
|
std::string spirvVersion;
|
||||||
|
glslang::GetSpirvVersion(spirvVersion);
|
||||||
|
printf("SPIR-V Version %s\n", spirvVersion.c_str()); // TODO: move to consume source-generated data
|
||||||
if (Worklist.empty())
|
if (Worklist.empty())
|
||||||
return ESuccess;
|
return ESuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Worklist.empty()) {
|
if (Worklist.empty()) {
|
||||||
usage();
|
usage();
|
||||||
return EFailUsage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessConfigFile();
|
ProcessConfigFile();
|
||||||
@@ -835,8 +878,6 @@ void CompileFile(const char* fileName, ShHandle compiler)
|
|||||||
char** shaderStrings = ReadFileData(fileName);
|
char** shaderStrings = ReadFileData(fileName);
|
||||||
if (! shaderStrings) {
|
if (! shaderStrings) {
|
||||||
usage();
|
usage();
|
||||||
CompileFailed = true;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int* lengths = new int[NumShaderStrings];
|
int* lengths = new int[NumShaderStrings];
|
||||||
@@ -883,34 +924,44 @@ void usage()
|
|||||||
printf("Usage: glslangValidator [option]... [file]...\n"
|
printf("Usage: glslangValidator [option]... [file]...\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Where: each 'file' ends in .<stage>, where <stage> is one of\n"
|
"Where: each 'file' ends in .<stage>, where <stage> is one of\n"
|
||||||
" .conf to provide an optional config file that replaces the default configuration\n"
|
" .conf to provide an optional config file that replaces the default configuration\n"
|
||||||
" (see -c option below for generating a template)\n"
|
" (see -c option below for generating a template)\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"
|
||||||
" .tese for a tessellation evaluation shader\n"
|
" .tese for a tessellation evaluation shader\n"
|
||||||
" .geom for a geometry shader\n"
|
" .geom for a geometry shader\n"
|
||||||
" .frag for a fragment shader\n"
|
" .frag for a fragment shader\n"
|
||||||
" .comp for a compute shader\n"
|
" .comp for a compute shader\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Compilation warnings and errors will be printed to stdout.\n"
|
"Compilation warnings and errors will be printed to stdout.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"To get other information, use one of the following options:\n"
|
"To get other information, use one of the following options:\n"
|
||||||
"(Each option must be specified separately, but can go anywhere in the command line.)\n"
|
"Each option must be specified separately.\n"
|
||||||
" -V create SPIR-V in file <stage>.spv\n"
|
" -V create SPIR-V binary, under Vulkan semantics; turns on -l;\n"
|
||||||
" -H print human readable form of SPIR-V; turns on -V\n"
|
" default file name is <stage>.spv (-o overrides this)\n"
|
||||||
" -E print pre-processed GLSL; cannot be used with -V, -H, or -l.\n"
|
" (unless -o is specified, which overrides the default file name)\n"
|
||||||
" -c configuration dump; use to create default configuration file (redirect to a .conf file)\n"
|
" -G create SPIR-V binary, under OpenGL semantics; turns on -l;\n"
|
||||||
" -d default to desktop (#version 110) when there is no version in the shader (default is ES version 100)\n"
|
" default file name is <stage>.spv (-o overrides this)\n"
|
||||||
" -i intermediate tree (glslang AST) is printed out\n"
|
" -H print human readable form of SPIR-V; turns on -V\n"
|
||||||
" -l link validation of all input files\n"
|
" -E print pre-processed GLSL; cannot be used with -l.\n"
|
||||||
" -m memory leak mode\n"
|
" -c configuration dump;\n"
|
||||||
" -q dump reflection query database\n"
|
" creates the default configuration file (redirect to a .conf file)\n"
|
||||||
" -r relaxed semantic error-checking mode\n"
|
" -d default to desktop (#version 110) when there is no shader #version\n"
|
||||||
" -s silent mode\n"
|
" (default is ES version 100)\n"
|
||||||
" -t multi-threaded mode\n"
|
" -h print this usage message\n"
|
||||||
" -v print version strings\n"
|
" -i intermediate tree (glslang AST) is printed out\n"
|
||||||
" -w suppress warnings (except as required by #extension : warn)\n"
|
" -l link all input files together to form a single module\n"
|
||||||
|
" -m memory leak mode\n"
|
||||||
|
" -o <file> save binary into <file>, requires a binary option (e.g., -V)\n"
|
||||||
|
" -q dump reflection query database\n"
|
||||||
|
" -r relaxed semantic error-checking mode\n"
|
||||||
|
" -s silent mode\n"
|
||||||
|
" -t multi-threaded mode\n"
|
||||||
|
" -v print version strings\n"
|
||||||
|
" -w suppress warnings (except as required by #extension : warn)\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
exit(EFailUsage);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined _MSC_VER && !defined MINGW_HAS_SECURE_API
|
#if !defined _MSC_VER && !defined MINGW_HAS_SECURE_API
|
||||||
@@ -954,10 +1005,8 @@ char** ReadFileData(const char* fileName)
|
|||||||
const int maxSourceStrings = 5; // for testing splitting shader/tokens across multiple strings
|
const int maxSourceStrings = 5; // for testing splitting shader/tokens across multiple strings
|
||||||
char** return_data = (char**)malloc(sizeof(char *) * (maxSourceStrings+1)); // freed in FreeFileData()
|
char** return_data = (char**)malloc(sizeof(char *) * (maxSourceStrings+1)); // freed in FreeFileData()
|
||||||
|
|
||||||
if (errorCode || in == nullptr) {
|
if (errorCode || in == nullptr)
|
||||||
printf("Error: unable to open input file: %s\n", fileName);
|
Error("unable to open input file");
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (fgetc(in) != EOF)
|
while (fgetc(in) != EOF)
|
||||||
count++;
|
count++;
|
||||||
@@ -965,15 +1014,14 @@ char** ReadFileData(const char* fileName)
|
|||||||
fseek(in, 0, SEEK_SET);
|
fseek(in, 0, SEEK_SET);
|
||||||
|
|
||||||
char *fdata = (char*)malloc(count+2); // freed before return of this function
|
char *fdata = (char*)malloc(count+2); // freed before return of this function
|
||||||
if (! fdata) {
|
if (! fdata)
|
||||||
printf("Error allocating memory\n");
|
Error("can't allocate memory");
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
if ((int)fread(fdata, 1, count, in) != count) {
|
if ((int)fread(fdata, 1, count, in) != count) {
|
||||||
printf("Error reading input file: %s\n", fileName);
|
|
||||||
free(fdata);
|
free(fdata);
|
||||||
return nullptr;
|
Error("can't read input file");
|
||||||
}
|
}
|
||||||
|
|
||||||
fdata[count] = '\0';
|
fdata[count] = '\0';
|
||||||
fclose(in);
|
fclose(in);
|
||||||
|
|
||||||
|
|||||||
@@ -50,10 +50,10 @@ namespace glslang {
|
|||||||
TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, bool pb, int v, EProfile p, EShLanguage L, TInfoSink& is,
|
TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, bool pb, int v, EProfile p, EShLanguage L, TInfoSink& is,
|
||||||
bool fc, EShMessages m) :
|
bool fc, EShMessages m) :
|
||||||
intermediate(interm), symbolTable(symt), infoSink(is), language(L),
|
intermediate(interm), symbolTable(symt), infoSink(is), language(L),
|
||||||
version(v), profile(p), forwardCompatible(fc), messages(m),
|
version(v), profile(p), forwardCompatible(fc),
|
||||||
contextPragma(true, false), loopNestingLevel(0), structNestingLevel(0), controlFlowNestingLevel(0), statementNestingLevel(0),
|
contextPragma(true, false), loopNestingLevel(0), structNestingLevel(0), controlFlowNestingLevel(0), statementNestingLevel(0),
|
||||||
postMainReturn(false),
|
postMainReturn(false),
|
||||||
tokensBeforeEOF(false), limits(resources.limits), currentScanner(0),
|
tokensBeforeEOF(false), limits(resources.limits), messages(m), currentScanner(0),
|
||||||
numErrors(0), parsingBuiltins(pb), afterEOF(false),
|
numErrors(0), parsingBuiltins(pb), afterEOF(false),
|
||||||
atomicUintOffsets(0), anyIndexLimits(false)
|
atomicUintOffsets(0), anyIndexLimits(false)
|
||||||
{
|
{
|
||||||
@@ -364,7 +364,7 @@ void C_DECL TParseContext::error(TSourceLoc loc, const char* szReason, const cha
|
|||||||
void C_DECL TParseContext::warn(TSourceLoc loc, const char* szReason, const char* szToken,
|
void C_DECL TParseContext::warn(TSourceLoc loc, const char* szReason, const char* szToken,
|
||||||
const char* szExtraInfoFormat, ...)
|
const char* szExtraInfoFormat, ...)
|
||||||
{
|
{
|
||||||
if (messages & EShMsgSuppressWarnings)
|
if (suppressWarnings())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const int maxSize = GlslangMaxTokenLength + 200;
|
const int maxSize = GlslangMaxTokenLength + 200;
|
||||||
@@ -1852,7 +1852,7 @@ bool TParseContext::lineContinuationCheck(TSourceLoc loc, bool endOfComment)
|
|||||||
return lineContinuationAllowed;
|
return lineContinuationAllowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (messages & EShMsgRelaxedErrors) {
|
if (relaxedErrors()) {
|
||||||
if (! lineContinuationAllowed)
|
if (! lineContinuationAllowed)
|
||||||
warn(loc, "not allowed in this version", message, "");
|
warn(loc, "not allowed in this version", message, "");
|
||||||
return true;
|
return true;
|
||||||
@@ -2347,7 +2347,7 @@ void TParseContext::precisionQualifierCheck(TSourceLoc loc, TBasicType baseType,
|
|||||||
|
|
||||||
if (baseType == EbtFloat || baseType == EbtUint || baseType == EbtInt || baseType == EbtSampler || baseType == EbtAtomicUint) {
|
if (baseType == EbtFloat || baseType == EbtUint || baseType == EbtInt || baseType == EbtSampler || baseType == EbtAtomicUint) {
|
||||||
if (qualifier.precision == EpqNone) {
|
if (qualifier.precision == EpqNone) {
|
||||||
if (messages & EShMsgRelaxedErrors)
|
if (relaxedErrors())
|
||||||
warn(loc, "type requires declaration of default precision qualifier", TType::getBasicString(baseType), "substituting 'mediump'");
|
warn(loc, "type requires declaration of default precision qualifier", TType::getBasicString(baseType), "substituting 'mediump'");
|
||||||
else
|
else
|
||||||
error(loc, "type requires declaration of default precision qualifier", TType::getBasicString(baseType), "");
|
error(loc, "type requires declaration of default precision qualifier", TType::getBasicString(baseType), "");
|
||||||
@@ -4265,7 +4265,7 @@ TIntermNode* TParseContext::executeInitializer(TSourceLoc loc, TIntermTyped* ini
|
|||||||
// qualifier any initializer must be a constant expression."
|
// qualifier any initializer must be a constant expression."
|
||||||
if (symbolTable.atGlobalLevel() && initializer->getType().getQualifier().storage != EvqConst) {
|
if (symbolTable.atGlobalLevel() && initializer->getType().getQualifier().storage != EvqConst) {
|
||||||
const char* initFeature = "non-constant global initializer";
|
const char* initFeature = "non-constant global initializer";
|
||||||
if (messages & EShMsgRelaxedErrors)
|
if (relaxedErrors())
|
||||||
warn(loc, "not allowed in this version", initFeature, "");
|
warn(loc, "not allowed in this version", initFeature, "");
|
||||||
else
|
else
|
||||||
requireProfile(loc, ~EEsProfile, initFeature);
|
requireProfile(loc, ~EEsProfile, initFeature);
|
||||||
@@ -5211,7 +5211,7 @@ TIntermNode* TParseContext::addSwitch(TSourceLoc loc, TIntermTyped* expression,
|
|||||||
// "it is an error to have no statement between a label and the end of the switch statement."
|
// "it is an error to have no statement between a label and the end of the switch statement."
|
||||||
// The specifications were updated to remove this (being ill-defined what a "statement" was),
|
// The specifications were updated to remove this (being ill-defined what a "statement" was),
|
||||||
// so, this became a warning. However, 3.0 tests still check for the error.
|
// so, this became a warning. However, 3.0 tests still check for the error.
|
||||||
if (profile == EEsProfile && version <= 300 && (messages & EShMsgRelaxedErrors) == 0)
|
if (profile == EEsProfile && version <= 300 && ! relaxedErrors())
|
||||||
error(loc, "last case/default label not followed by statements", "switch", "");
|
error(loc, "last case/default label not followed by statements", "switch", "");
|
||||||
else
|
else
|
||||||
warn(loc, "last case/default label not followed by statements", "switch", "");
|
warn(loc, "last case/default label not followed by statements", "switch", "");
|
||||||
|
|||||||
@@ -78,6 +78,12 @@ public:
|
|||||||
const char* szExtraInfoFormat, ...);
|
const char* szExtraInfoFormat, ...);
|
||||||
void C_DECL warn(TSourceLoc, const char* szReason, const char* szToken,
|
void C_DECL warn(TSourceLoc, const char* szReason, const char* szToken,
|
||||||
const char* szExtraInfoFormat, ...);
|
const char* szExtraInfoFormat, ...);
|
||||||
|
|
||||||
|
bool relaxedErrors() const { return (messages & EShMsgRelaxedErrors) != 0; }
|
||||||
|
bool suppressWarnings() const { return (messages & EShMsgSuppressWarnings) != 0; }
|
||||||
|
bool vulkanRules() const { return (messages & EShMsgVulkanRules) != 0; }
|
||||||
|
bool spirvRules() const { return (messages & EShMsgSpvRules) != 0; }
|
||||||
|
|
||||||
void reservedErrorCheck(TSourceLoc, const TString&);
|
void reservedErrorCheck(TSourceLoc, const TString&);
|
||||||
void reservedPpErrorCheck(TSourceLoc, const char* name, const char* op);
|
void reservedPpErrorCheck(TSourceLoc, const char* name, const char* op);
|
||||||
bool lineContinuationCheck(TSourceLoc, bool endOfComment);
|
bool lineContinuationCheck(TSourceLoc, bool endOfComment);
|
||||||
@@ -258,7 +264,6 @@ public:
|
|||||||
int version; // version, updated by #version in the shader
|
int version; // version, updated by #version in the shader
|
||||||
EProfile profile; // the declared profile in the shader (core by default)
|
EProfile profile; // the declared profile in the shader (core by default)
|
||||||
bool forwardCompatible; // true if errors are to be given for use of deprecated features
|
bool forwardCompatible; // true if errors are to be given for use of deprecated features
|
||||||
EShMessages messages; // errors/warnings
|
|
||||||
|
|
||||||
// Current state of parsing
|
// Current state of parsing
|
||||||
struct TPragma contextPragma;
|
struct TPragma contextPragma;
|
||||||
@@ -284,6 +289,7 @@ protected:
|
|||||||
TParseContext(TParseContext&);
|
TParseContext(TParseContext&);
|
||||||
TParseContext& operator=(TParseContext&);
|
TParseContext& operator=(TParseContext&);
|
||||||
|
|
||||||
|
EShMessages messages; // errors/warnings/rule-sets
|
||||||
TScanContext* scanContext;
|
TScanContext* scanContext;
|
||||||
TPpContext* ppContext;
|
TPpContext* ppContext;
|
||||||
TInputScanner* currentScanner;
|
TInputScanner* currentScanner;
|
||||||
|
|||||||
@@ -897,7 +897,7 @@ int TScanContext::tokenizeIdentifier()
|
|||||||
if (parseContext.profile == EEsProfile)
|
if (parseContext.profile == EEsProfile)
|
||||||
reservedWord();
|
reservedWord();
|
||||||
else if (parseContext.version < 140 && ! parseContext.symbolTable.atBuiltInLevel() && ! parseContext.extensionsTurnedOn(1, &E_GL_ARB_texture_rectangle)) {
|
else if (parseContext.version < 140 && ! parseContext.symbolTable.atBuiltInLevel() && ! parseContext.extensionsTurnedOn(1, &E_GL_ARB_texture_rectangle)) {
|
||||||
if (parseContext.messages & EShMsgRelaxedErrors)
|
if (parseContext.relaxedErrors())
|
||||||
parseContext.requireExtensions(loc, 1, &E_GL_ARB_texture_rectangle, "texture-rectangle sampler keyword");
|
parseContext.requireExtensions(loc, 1, &E_GL_ARB_texture_rectangle, "texture-rectangle sampler keyword");
|
||||||
else
|
else
|
||||||
reservedWord();
|
reservedWord();
|
||||||
|
|||||||
@@ -505,7 +505,7 @@ bool ProcessDeferred(
|
|||||||
bool versionNotFirst = userInput.scanVersion(version, profile, versionNotFirstToken);
|
bool versionNotFirst = userInput.scanVersion(version, profile, versionNotFirstToken);
|
||||||
bool versionNotFound = version == 0;
|
bool versionNotFound = version == 0;
|
||||||
if (forceDefaultVersionAndProfile) {
|
if (forceDefaultVersionAndProfile) {
|
||||||
if (!(messages & EShMsgSuppressWarnings) && !versionNotFound &&
|
if (! (messages & EShMsgSuppressWarnings) && ! versionNotFound &&
|
||||||
(version != defaultVersion || profile != defaultProfile)) {
|
(version != defaultVersion || profile != defaultProfile)) {
|
||||||
compiler->infoSink.info << "Warning, (version, profile) forced to be ("
|
compiler->infoSink.info << "Warning, (version, profile) forced to be ("
|
||||||
<< defaultVersion << ", " << ProfileName(defaultProfile)
|
<< defaultVersion << ", " << ProfileName(defaultProfile)
|
||||||
|
|||||||
@@ -377,7 +377,7 @@ void TParseContext::checkDeprecated(TSourceLoc loc, int profileMask, int depVers
|
|||||||
if (version >= depVersion) {
|
if (version >= depVersion) {
|
||||||
if (forwardCompatible)
|
if (forwardCompatible)
|
||||||
error(loc, "deprecated, may be removed in future release", featureDesc, "");
|
error(loc, "deprecated, may be removed in future release", featureDesc, "");
|
||||||
else if (! (messages & EShMsgSuppressWarnings))
|
else if (! suppressWarnings())
|
||||||
infoSink.info.message(EPrefixWarning, (TString(featureDesc) + " deprecated in version " +
|
infoSink.info.message(EPrefixWarning, (TString(featureDesc) + " deprecated in version " +
|
||||||
String(depVersion) + "; may be removed in future release").c_str(), loc);
|
String(depVersion) + "; may be removed in future release").c_str(), loc);
|
||||||
}
|
}
|
||||||
@@ -417,7 +417,7 @@ void TParseContext::requireExtensions(TSourceLoc loc, int numExtensions, const c
|
|||||||
bool warned = false;
|
bool warned = false;
|
||||||
for (int i = 0; i < numExtensions; ++i) {
|
for (int i = 0; i < numExtensions; ++i) {
|
||||||
TExtensionBehavior behavior = getExtensionBehavior(extensions[i]);
|
TExtensionBehavior behavior = getExtensionBehavior(extensions[i]);
|
||||||
if (behavior == EBhDisable && (messages & EShMsgRelaxedErrors)) {
|
if (behavior == EBhDisable && relaxedErrors()) {
|
||||||
infoSink.info.message(EPrefixWarning, "The following extension must be enabled to use this feature:", loc);
|
infoSink.info.message(EPrefixWarning, "The following extension must be enabled to use this feature:", loc);
|
||||||
behavior = EBhWarn;
|
behavior = EBhWarn;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -357,7 +357,7 @@ int TPpContext::extraTokenCheck(int atom, TPpToken* ppToken, int token)
|
|||||||
else
|
else
|
||||||
label = "";
|
label = "";
|
||||||
|
|
||||||
if (parseContext.messages & EShMsgRelaxedErrors)
|
if (parseContext.relaxedErrors())
|
||||||
parseContext.warn(ppToken->loc, message, label, "");
|
parseContext.warn(ppToken->loc, message, label, "");
|
||||||
else
|
else
|
||||||
parseContext.error(ppToken->loc, message, label, "");
|
parseContext.error(ppToken->loc, message, label, "");
|
||||||
@@ -553,7 +553,7 @@ int TPpContext::evalToToken(int token, bool shortCircuit, int& res, bool& err, T
|
|||||||
if (! shortCircuit && parseContext.profile == EEsProfile) {
|
if (! shortCircuit && parseContext.profile == EEsProfile) {
|
||||||
const char* message = "undefined macro in expression not allowed in es profile";
|
const char* message = "undefined macro in expression not allowed in es profile";
|
||||||
const char* name = GetAtomString(ppToken->atom);
|
const char* name = GetAtomString(ppToken->atom);
|
||||||
if (parseContext.messages & EShMsgRelaxedErrors)
|
if (parseContext.relaxedErrors())
|
||||||
parseContext.warn(ppToken->loc, message, "preprocessor evaluation", name);
|
parseContext.warn(ppToken->loc, message, "preprocessor evaluation", name);
|
||||||
else
|
else
|
||||||
parseContext.error(ppToken->loc, message, "preprocessor evaluation", name);
|
parseContext.error(ppToken->loc, message, "preprocessor evaluation", name);
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken)
|
|||||||
}
|
}
|
||||||
} else if (ch == 'f' || ch == 'F') {
|
} else if (ch == 'f' || ch == 'F') {
|
||||||
parseContext.profileRequires(ppToken->loc, EEsProfile, 300, nullptr, "floating-point suffix");
|
parseContext.profileRequires(ppToken->loc, EEsProfile, 300, nullptr, "floating-point suffix");
|
||||||
if ((parseContext.messages & EShMsgRelaxedErrors) == 0)
|
if (! parseContext.relaxedErrors())
|
||||||
parseContext.profileRequires(ppToken->loc, ~EEsProfile, 120, nullptr, "floating-point suffix");
|
parseContext.profileRequires(ppToken->loc, ~EEsProfile, 120, nullptr, "floating-point suffix");
|
||||||
if (! HasDecimalOrExponent)
|
if (! HasDecimalOrExponent)
|
||||||
parseContext.error(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
|
parseContext.error(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
|
||||||
|
|||||||
@@ -129,6 +129,8 @@ enum EShMessages {
|
|||||||
EShMsgRelaxedErrors = (1 << 0), // be liberal in accepting input
|
EShMsgRelaxedErrors = (1 << 0), // be liberal in accepting input
|
||||||
EShMsgSuppressWarnings = (1 << 1), // suppress all warnings, except those required by the specification
|
EShMsgSuppressWarnings = (1 << 1), // suppress all warnings, except those required by the specification
|
||||||
EShMsgAST = (1 << 2), // print the AST intermediate representation
|
EShMsgAST = (1 << 2), // print the AST intermediate representation
|
||||||
|
EShMsgSpvRules = (1 << 3), // issue messages for SPIR-V generation
|
||||||
|
EShMsgVulkanRules = (1 << 4), // issue messages for Vulkan-requirements of GLSL for SPIR-V
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
Reference in New Issue
Block a user