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:
John Kessenich
2015-07-12 19:28:10 -06:00
parent b329715caf
commit 68d78fd31e
11 changed files with 159 additions and 97 deletions

View File

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

View File

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

View File

@@ -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];
@@ -895,15 +936,23 @@ void usage()
"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"
" default file name is <stage>.spv (-o overrides this)\n"
" (unless -o is specified, which overrides the default file name)\n"
" -G create SPIR-V binary, under OpenGL semantics; turns on -l;\n"
" default file name is <stage>.spv (-o overrides this)\n"
" -H print human readable form of SPIR-V; turns on -V\n" " -H print human readable form of SPIR-V; turns on -V\n"
" -E print pre-processed GLSL; cannot be used with -V, -H, or -l.\n" " -E print pre-processed GLSL; cannot be used with -l.\n"
" -c configuration dump; use to create default configuration file (redirect to a .conf file)\n" " -c configuration dump;\n"
" -d default to desktop (#version 110) when there is no version in the shader (default is ES version 100)\n" " creates the default configuration file (redirect to a .conf file)\n"
" -d default to desktop (#version 110) when there is no shader #version\n"
" (default is ES version 100)\n"
" -h print this usage message\n"
" -i intermediate tree (glslang AST) is printed out\n" " -i intermediate tree (glslang AST) is printed out\n"
" -l link validation of all input files\n" " -l link all input files together to form a single module\n"
" -m memory leak mode\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" " -q dump reflection query database\n"
" -r relaxed semantic error-checking mode\n" " -r relaxed semantic error-checking mode\n"
" -s silent mode\n" " -s silent mode\n"
@@ -911,6 +960,8 @@ void usage()
" -v print version strings\n" " -v print version strings\n"
" -w suppress warnings (except as required by #extension : warn)\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);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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
}; };
// //