Merge pull request #948 from KhronosGroup/env-control
Compilation-environment control
This commit is contained in:
commit
a8a8320451
@ -148,6 +148,10 @@ const char* sourceEntryPointName = nullptr;
|
|||||||
const char* shaderStageName = nullptr;
|
const char* shaderStageName = nullptr;
|
||||||
const char* variableName = nullptr;
|
const char* variableName = nullptr;
|
||||||
std::vector<std::string> IncludeDirectoryList;
|
std::vector<std::string> IncludeDirectoryList;
|
||||||
|
int ClientInputSemanticsVersion = 100; // maps to, say, #define VULKAN 100
|
||||||
|
int VulkanClientVersion = 100; // would map to, say, Vulkan 1.0
|
||||||
|
int OpenGLClientVersion = 450; // doesn't influence anything yet, but maps to OpenGL 4.50
|
||||||
|
unsigned int TargetVersion = 0x00001000; // maps to, say, SPIR-V 1.0
|
||||||
|
|
||||||
std::array<unsigned int, EShLangCount> baseSamplerBinding;
|
std::array<unsigned int, EShLangCount> baseSamplerBinding;
|
||||||
std::array<unsigned int, EShLangCount> baseTextureBinding;
|
std::array<unsigned int, EShLangCount> baseTextureBinding;
|
||||||
@ -157,7 +161,6 @@ std::array<unsigned int, EShLangCount> baseSsboBinding;
|
|||||||
std::array<unsigned int, EShLangCount> baseUavBinding;
|
std::array<unsigned int, EShLangCount> baseUavBinding;
|
||||||
std::array<std::vector<std::string>, EShLangCount> baseResourceSetBinding;
|
std::array<std::vector<std::string>, EShLangCount> baseResourceSetBinding;
|
||||||
|
|
||||||
|
|
||||||
// Add things like "#define ..." to a preamble to use in the beginning of the shader.
|
// Add things like "#define ..." to a preamble to use in the beginning of the shader.
|
||||||
class TPreamble {
|
class TPreamble {
|
||||||
public:
|
public:
|
||||||
@ -337,6 +340,14 @@ void ProcessArguments(std::vector<std::unique_ptr<glslang::TWorkItem>>& workItem
|
|||||||
ExecutableName = argv[0];
|
ExecutableName = argv[0];
|
||||||
workItems.reserve(argc);
|
workItems.reserve(argc);
|
||||||
|
|
||||||
|
const auto bumpArg = [&]() {
|
||||||
|
if (argc > 0) {
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// read a string directly attached to a single-letter option
|
||||||
const auto getStringOperand = [&](const char* desc) {
|
const auto getStringOperand = [&](const char* desc) {
|
||||||
if (argv[0][2] == 0) {
|
if (argv[0][2] == 0) {
|
||||||
printf("%s must immediately follow option (no spaces)\n", desc);
|
printf("%s must immediately follow option (no spaces)\n", desc);
|
||||||
@ -345,9 +356,32 @@ void ProcessArguments(std::vector<std::unique_ptr<glslang::TWorkItem>>& workItem
|
|||||||
return argv[0] + 2;
|
return argv[0] + 2;
|
||||||
};
|
};
|
||||||
|
|
||||||
argc--;
|
// read a number attached to a single-letter option
|
||||||
argv++;
|
const auto getAttachedNumber = [&](const char* desc) {
|
||||||
for (; argc >= 1; argc--, argv++) {
|
int num = atoi(argv[0] + 2);
|
||||||
|
if (num == 0) {
|
||||||
|
printf("%s: expected attached non-0 number\n", desc);
|
||||||
|
exit(EFailUsage);
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
};
|
||||||
|
|
||||||
|
// minimum needed (without overriding something else) to target Vulkan SPIR-V
|
||||||
|
const auto setVulkanSpv = []() {
|
||||||
|
Options |= EOptionSpv;
|
||||||
|
Options |= EOptionVulkanRules;
|
||||||
|
Options |= EOptionLinkProgram;
|
||||||
|
};
|
||||||
|
|
||||||
|
// minimum needed (without overriding something else) to target OpenGL SPIR-V
|
||||||
|
const auto setOpenGlSpv = []() {
|
||||||
|
Options |= EOptionSpv;
|
||||||
|
Options |= EOptionLinkProgram;
|
||||||
|
// undo a -H default to Vulkan
|
||||||
|
Options &= ~EOptionVulkanRules;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (bumpArg(); argc >= 1; bumpArg()) {
|
||||||
if (argv[0][0] == '-') {
|
if (argv[0][0] == '-') {
|
||||||
switch (argv[0][1]) {
|
switch (argv[0][1]) {
|
||||||
case '-':
|
case '-':
|
||||||
@ -363,6 +397,16 @@ void ProcessArguments(std::vector<std::unique_ptr<glslang::TWorkItem>>& workItem
|
|||||||
} else if (lowerword == "auto-map-locations" || // synonyms
|
} else if (lowerword == "auto-map-locations" || // synonyms
|
||||||
lowerword == "aml") {
|
lowerword == "aml") {
|
||||||
Options |= EOptionAutoMapLocations;
|
Options |= EOptionAutoMapLocations;
|
||||||
|
} else if (lowerword == "client") {
|
||||||
|
if (argc > 1) {
|
||||||
|
if (strcmp(argv[1], "vulkan100") == 0)
|
||||||
|
setVulkanSpv();
|
||||||
|
else if (strcmp(argv[1], "opengl100") == 0)
|
||||||
|
setOpenGlSpv();
|
||||||
|
else
|
||||||
|
Error("--client expects vulkan100 or opengl100");
|
||||||
|
}
|
||||||
|
bumpArg();
|
||||||
} else if (lowerword == "flatten-uniform-arrays" || // synonyms
|
} else if (lowerword == "flatten-uniform-arrays" || // synonyms
|
||||||
lowerword == "flatten-uniform-array" ||
|
lowerword == "flatten-uniform-array" ||
|
||||||
lowerword == "fua") {
|
lowerword == "fua") {
|
||||||
@ -412,22 +456,30 @@ void ProcessArguments(std::vector<std::unique_ptr<glslang::TWorkItem>>& workItem
|
|||||||
ProcessBindingBase(argc, argv, baseSsboBinding);
|
ProcessBindingBase(argc, argv, baseSsboBinding);
|
||||||
} else if (lowerword == "source-entrypoint" || // synonyms
|
} else if (lowerword == "source-entrypoint" || // synonyms
|
||||||
lowerword == "sep") {
|
lowerword == "sep") {
|
||||||
sourceEntryPointName = argv[1];
|
if (argc <= 1)
|
||||||
if (argc > 0) {
|
|
||||||
argc--;
|
|
||||||
argv++;
|
|
||||||
} else
|
|
||||||
Error("no <entry-point> provided for --source-entrypoint");
|
Error("no <entry-point> provided for --source-entrypoint");
|
||||||
|
sourceEntryPointName = argv[1];
|
||||||
|
bumpArg();
|
||||||
break;
|
break;
|
||||||
|
} else if (lowerword == "target-env") {
|
||||||
|
if (argc > 1) {
|
||||||
|
if (strcmp(argv[1], "vulkan1.0") == 0) {
|
||||||
|
setVulkanSpv();
|
||||||
|
VulkanClientVersion = 100;
|
||||||
|
} else if (strcmp(argv[1], "opengl") == 0) {
|
||||||
|
setOpenGlSpv();
|
||||||
|
OpenGLClientVersion = 450;
|
||||||
|
} else
|
||||||
|
Error("--target-env expected vulkan1.0 or opengl");
|
||||||
|
}
|
||||||
|
bumpArg();
|
||||||
} else if (lowerword == "variable-name" || // synonyms
|
} else if (lowerword == "variable-name" || // synonyms
|
||||||
lowerword == "vn") {
|
lowerword == "vn") {
|
||||||
Options |= EOptionOutputHexadecimal;
|
Options |= EOptionOutputHexadecimal;
|
||||||
variableName = argv[1];
|
if (argc <= 1)
|
||||||
if (argc > 0) {
|
|
||||||
argc--;
|
|
||||||
argv++;
|
|
||||||
} else
|
|
||||||
Error("no <C-variable-name> provided for --variable-name");
|
Error("no <C-variable-name> provided for --variable-name");
|
||||||
|
variableName = argv[1];
|
||||||
|
bumpArg();
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
usage();
|
usage();
|
||||||
@ -447,38 +499,34 @@ void ProcessArguments(std::vector<std::unique_ptr<glslang::TWorkItem>>& workItem
|
|||||||
Options |= EOptionOutputPreprocessed;
|
Options |= EOptionOutputPreprocessed;
|
||||||
break;
|
break;
|
||||||
case 'G':
|
case 'G':
|
||||||
Options |= EOptionSpv;
|
// OpenGL Client
|
||||||
Options |= EOptionLinkProgram;
|
setOpenGlSpv();
|
||||||
// undo a -H default to Vulkan
|
if (argv[0][2] != 0)
|
||||||
Options &= ~EOptionVulkanRules;
|
ClientInputSemanticsVersion = getAttachedNumber("-G<num> client input semantics");
|
||||||
break;
|
break;
|
||||||
case 'H':
|
case 'H':
|
||||||
Options |= EOptionHumanReadableSpv;
|
Options |= EOptionHumanReadableSpv;
|
||||||
if ((Options & EOptionSpv) == 0) {
|
if ((Options & EOptionSpv) == 0) {
|
||||||
// default to Vulkan
|
// default to Vulkan
|
||||||
Options |= EOptionSpv;
|
setVulkanSpv();
|
||||||
Options |= EOptionVulkanRules;
|
|
||||||
Options |= EOptionLinkProgram;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'I':
|
case 'I':
|
||||||
IncludeDirectoryList.push_back(getStringOperand("-I<dir> include path"));
|
IncludeDirectoryList.push_back(getStringOperand("-I<dir> include path"));
|
||||||
break;
|
break;
|
||||||
case 'S':
|
case 'S':
|
||||||
shaderStageName = argv[1];
|
if (argc <= 1)
|
||||||
if (argc > 0) {
|
|
||||||
argc--;
|
|
||||||
argv++;
|
|
||||||
} else
|
|
||||||
Error("no <stage> specified for -S");
|
Error("no <stage> specified for -S");
|
||||||
|
shaderStageName = argv[1];
|
||||||
|
bumpArg();
|
||||||
break;
|
break;
|
||||||
case 'U':
|
case 'U':
|
||||||
UserPreamble.addUndef(getStringOperand("-U<macro>: macro name"));
|
UserPreamble.addUndef(getStringOperand("-U<macro>: macro name"));
|
||||||
break;
|
break;
|
||||||
case 'V':
|
case 'V':
|
||||||
Options |= EOptionSpv;
|
setVulkanSpv();
|
||||||
Options |= EOptionVulkanRules;
|
if (argv[0][2] != 0)
|
||||||
Options |= EOptionLinkProgram;
|
ClientInputSemanticsVersion = getAttachedNumber("-G<num> client input semantics");
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
Options |= EOptionDumpConfig;
|
Options |= EOptionDumpConfig;
|
||||||
@ -490,11 +538,9 @@ void ProcessArguments(std::vector<std::unique_ptr<glslang::TWorkItem>>& workItem
|
|||||||
// HLSL todo: entry point handle needs much more sophistication.
|
// HLSL todo: entry point handle needs much more sophistication.
|
||||||
// This is okay for one compilation unit with one entry point.
|
// This is okay for one compilation unit with one entry point.
|
||||||
entryPointName = argv[1];
|
entryPointName = argv[1];
|
||||||
if (argc > 0) {
|
if (argc <= 1)
|
||||||
argc--;
|
|
||||||
argv++;
|
|
||||||
} else
|
|
||||||
Error("no <entry-point> provided for -e");
|
Error("no <entry-point> provided for -e");
|
||||||
|
bumpArg();
|
||||||
break;
|
break;
|
||||||
case 'g':
|
case 'g':
|
||||||
Options |= EOptionDebug;
|
Options |= EOptionDebug;
|
||||||
@ -512,12 +558,10 @@ void ProcessArguments(std::vector<std::unique_ptr<glslang::TWorkItem>>& workItem
|
|||||||
Options |= EOptionMemoryLeakMode;
|
Options |= EOptionMemoryLeakMode;
|
||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
binaryFileName = argv[1];
|
if (argc <= 1)
|
||||||
if (argc > 0) {
|
|
||||||
argc--;
|
|
||||||
argv++;
|
|
||||||
} else
|
|
||||||
Error("no <file> provided for -o");
|
Error("no <file> provided for -o");
|
||||||
|
binaryFileName = argv[1];
|
||||||
|
bumpArg();
|
||||||
break;
|
break;
|
||||||
case 'q':
|
case 'q':
|
||||||
Options |= EOptionDumpReflection;
|
Options |= EOptionDumpReflection;
|
||||||
@ -715,6 +759,24 @@ void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
|
|||||||
if (Options & EOptionAutoMapLocations)
|
if (Options & EOptionAutoMapLocations)
|
||||||
shader->setAutoMapLocations(true);
|
shader->setAutoMapLocations(true);
|
||||||
|
|
||||||
|
// Set up the environment, some subsettings take precedence over earlier
|
||||||
|
// ways of setting things.
|
||||||
|
if (Options & EOptionSpv) {
|
||||||
|
if (Options & EOptionVulkanRules) {
|
||||||
|
shader->setEnvInput((Options & EOptionReadHlsl) ? glslang::EShSourceHlsl
|
||||||
|
: glslang::EShSourceGlsl,
|
||||||
|
compUnit.stage, glslang::EShClientVulkan, ClientInputSemanticsVersion);
|
||||||
|
shader->setEnvClient(glslang::EShClientVulkan, VulkanClientVersion);
|
||||||
|
shader->setEnvTarget(glslang::EshTargetSpv, TargetVersion);
|
||||||
|
} else {
|
||||||
|
shader->setEnvInput((Options & EOptionReadHlsl) ? glslang::EShSourceHlsl
|
||||||
|
: glslang::EShSourceGlsl,
|
||||||
|
compUnit.stage, glslang::EShClientOpenGL, ClientInputSemanticsVersion);
|
||||||
|
shader->setEnvClient(glslang::EShClientOpenGL, OpenGLClientVersion);
|
||||||
|
shader->setEnvTarget(glslang::EshTargetSpv, TargetVersion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
shaders.push_back(shader);
|
shaders.push_back(shader);
|
||||||
|
|
||||||
const int defaultVersion = Options & EOptionDefaultDesktop ? 110 : 100;
|
const int defaultVersion = Options & EOptionDefaultDesktop ? 110 : 100;
|
||||||
@ -1072,16 +1134,24 @@ void usage()
|
|||||||
" -D<macro> define a pre-processor macro\n"
|
" -D<macro> define a pre-processor macro\n"
|
||||||
" -E print pre-processed GLSL; cannot be used with -l;\n"
|
" -E print pre-processed GLSL; cannot be used with -l;\n"
|
||||||
" errors will appear on stderr.\n"
|
" errors will appear on stderr.\n"
|
||||||
" -G create SPIR-V binary, under OpenGL semantics; turns on -l;\n"
|
" -G[ver] create SPIR-V binary, under OpenGL semantics; turns on -l;\n"
|
||||||
" default file name is <stage>.spv (-o overrides this)\n"
|
" default file name is <stage>.spv (-o overrides this)\n"
|
||||||
|
" 'ver', when present, is the version of the input semantics,\n"
|
||||||
|
" which will appear in #define GL_SPIRV ver\n"
|
||||||
|
" '--client opengl100' is the same as -G100\n"
|
||||||
|
" a '--target-env' for OpenGL will also imply '-G'\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"
|
||||||
" -I<dir> add dir to the include search path; includer's directory\n"
|
" -I<dir> add dir to the include search path; includer's directory\n"
|
||||||
" is searched first, followed by left-to-right order of -I\n"
|
" is searched first, followed by left-to-right order of -I\n"
|
||||||
" -S <stage> uses specified stage rather than parsing the file extension\n"
|
" -S <stage> uses specified stage rather than parsing the file extension\n"
|
||||||
" choices for <stage> are vert, tesc, tese, geom, frag, or comp\n"
|
" choices for <stage> are vert, tesc, tese, geom, frag, or comp\n"
|
||||||
" -U<macro> undefine a pre-precossor macro\n"
|
" -U<macro> undefine a pre-processor macro\n"
|
||||||
" -V create SPIR-V binary, under Vulkan semantics; turns on -l;\n"
|
" -V[ver] create SPIR-V binary, under Vulkan semantics; turns on -l;\n"
|
||||||
" default file name is <stage>.spv (-o overrides this)\n"
|
" default file name is <stage>.spv (-o overrides this)\n"
|
||||||
|
" 'ver', when present, is the version of the input semantics,\n"
|
||||||
|
" which will appear in #define VULKAN ver\n"
|
||||||
|
" '--client vulkan100' is the same as -V100\n"
|
||||||
|
" a '--target-env' for Vulkan will also imply '-V'\n"
|
||||||
" -c configuration dump;\n"
|
" -c configuration dump;\n"
|
||||||
" creates the default configuration file (redirect to a .conf file)\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"
|
" -d default to desktop (#version 110) when there is no shader #version\n"
|
||||||
@ -1104,12 +1174,12 @@ void usage()
|
|||||||
" without explicit bindings.\n"
|
" without explicit bindings.\n"
|
||||||
" --amb synonym for --auto-map-bindings\n"
|
" --amb synonym for --auto-map-bindings\n"
|
||||||
" --auto-map-locations automatically locate input/output lacking\n"
|
" --auto-map-locations automatically locate input/output lacking\n"
|
||||||
" 'location'\n (fragile, not cross stage)\n"
|
" 'location' (fragile, not cross stage)\n"
|
||||||
" --aml synonym for --auto-map-locations\n"
|
" --aml synonym for --auto-map-locations\n"
|
||||||
|
" --client {vulkan<ver>|opengl<ver>} see -V and -G\n"
|
||||||
" --flatten-uniform-arrays flatten uniform texture/sampler arrays to\n"
|
" --flatten-uniform-arrays flatten uniform texture/sampler arrays to\n"
|
||||||
" scalars\n"
|
" scalars\n"
|
||||||
" --fua synonym for --flatten-uniform-arrays\n"
|
" --fua synonym for --flatten-uniform-arrays\n"
|
||||||
"\n"
|
|
||||||
" --hlsl-offsets Allow block offsets to follow HLSL rules\n"
|
" --hlsl-offsets Allow block offsets to follow HLSL rules\n"
|
||||||
" Works independently of source language\n"
|
" Works independently of source language\n"
|
||||||
" --hlsl-iomap Perform IO mapping in HLSL register space\n"
|
" --hlsl-iomap Perform IO mapping in HLSL register space\n"
|
||||||
@ -1135,6 +1205,11 @@ void usage()
|
|||||||
" --source-entrypoint name the given shader source function is\n"
|
" --source-entrypoint name the given shader source function is\n"
|
||||||
" renamed to be the entry point given in -e\n"
|
" renamed to be the entry point given in -e\n"
|
||||||
" --sep synonym for --source-entrypoint\n"
|
" --sep synonym for --source-entrypoint\n"
|
||||||
|
" --target-env {vulkan1.0|opengl} set the execution environment the generated\n"
|
||||||
|
" code will execute in (as opposed to language\n"
|
||||||
|
" semantics selected by --client)\n"
|
||||||
|
" default is 'vulkan1.0' under '--client vulkan'\n"
|
||||||
|
" default is 'opengl' under '--client opengl'\n"
|
||||||
" --variable-name <name> Creates a C header file that contains a\n"
|
" --variable-name <name> Creates a C header file that contains a\n"
|
||||||
" uint32_t array named <name>\n"
|
" uint32_t array named <name>\n"
|
||||||
" initialized with the shader binary code.\n"
|
" initialized with the shader binary code.\n"
|
||||||
|
|||||||
@ -127,6 +127,16 @@ diff -b $BASEDIR/glsl.-D-U.frag.out $TARGETDIR/glsl.-D-U.frag.out || HASERROR=1
|
|||||||
$EXE -D -e main -V -i -DUNDEFED -UIN_SHADER -DFOO=200 -UUNDEFED hlsl.-D-U.frag > $TARGETDIR/hlsl.-D-U.frag.out
|
$EXE -D -e main -V -i -DUNDEFED -UIN_SHADER -DFOO=200 -UUNDEFED hlsl.-D-U.frag > $TARGETDIR/hlsl.-D-U.frag.out
|
||||||
diff -b $BASEDIR/hlsl.-D-U.frag.out $TARGETDIR/hlsl.-D-U.frag.out || HASERROR=1
|
diff -b $BASEDIR/hlsl.-D-U.frag.out $TARGETDIR/hlsl.-D-U.frag.out || HASERROR=1
|
||||||
|
|
||||||
|
#
|
||||||
|
# Test --client and --target-env
|
||||||
|
#
|
||||||
|
$EXE --client vulkan100 spv.targetVulkan.vert || HASERROR=1
|
||||||
|
$EXE --client opengl100 spv.targetOpenGL.vert || HASERROR=1
|
||||||
|
$EXE --target-env vulkan1.0 spv.targetVulkan.vert || HASERROR=1
|
||||||
|
$EXE --target-env opengl spv.targetOpenGL.vert || HASERROR=1
|
||||||
|
$EXE -V100 spv.targetVulkan.vert || HASERROR=1
|
||||||
|
$EXE -G100 spv.targetOpenGL.vert || HASERROR=1
|
||||||
|
|
||||||
#
|
#
|
||||||
# Final checking
|
# Final checking
|
||||||
#
|
#
|
||||||
|
|||||||
9
Test/spv.targetOpenGL.vert
Executable file
9
Test/spv.targetOpenGL.vert
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(constant_id = 3) const int a = 2;
|
||||||
|
|
||||||
|
uniform float f;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
}
|
||||||
9
Test/spv.targetVulkan.vert
Executable file
9
Test/spv.targetVulkan.vert
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(constant_id = 3) const int a = 2;
|
||||||
|
|
||||||
|
layout(push_constant) uniform pc { float f; };
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
}
|
||||||
@ -50,7 +50,8 @@ namespace glslang {
|
|||||||
TParseContext::TParseContext(TSymbolTable& symbolTable, TIntermediate& interm, bool parsingBuiltins,
|
TParseContext::TParseContext(TSymbolTable& symbolTable, TIntermediate& interm, bool parsingBuiltins,
|
||||||
int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language,
|
int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language,
|
||||||
TInfoSink& infoSink, bool forwardCompatible, EShMessages messages) :
|
TInfoSink& infoSink, bool forwardCompatible, EShMessages messages) :
|
||||||
TParseContextBase(symbolTable, interm, parsingBuiltins, version, profile, spvVersion, language, infoSink, forwardCompatible, messages),
|
TParseContextBase(symbolTable, interm, parsingBuiltins, version, profile, spvVersion, language,
|
||||||
|
infoSink, forwardCompatible, messages),
|
||||||
inMain(false),
|
inMain(false),
|
||||||
blockName(nullptr),
|
blockName(nullptr),
|
||||||
limits(resources.limits),
|
limits(resources.limits),
|
||||||
|
|||||||
@ -569,6 +569,73 @@ bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNo
|
|||||||
return correct;
|
return correct;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// There are multiple paths in for setting environment stuff.
|
||||||
|
// TEnvironment takes precedence, for what it sets, so sort all this out.
|
||||||
|
// Ideally, the internal code could be made to use TEnvironment, but for
|
||||||
|
// now, translate it to the historically used parameters.
|
||||||
|
void TranslateEnvironment(const TEnvironment* environment, EShMessages& messages, EShSource& source,
|
||||||
|
EShLanguage& stage, SpvVersion& spvVersion)
|
||||||
|
{
|
||||||
|
// Set up environmental defaults, first ignoring 'environment'.
|
||||||
|
if (messages & EShMsgSpvRules)
|
||||||
|
spvVersion.spv = 0x00010000;
|
||||||
|
if (messages & EShMsgVulkanRules) {
|
||||||
|
spvVersion.vulkan = 100;
|
||||||
|
spvVersion.vulkanGlsl = 100;
|
||||||
|
} else if (spvVersion.spv != 0)
|
||||||
|
spvVersion.openGl = 100;
|
||||||
|
|
||||||
|
// Now, override, based on any content set in 'environment'.
|
||||||
|
// 'environment' must be cleared to ESh*None settings when items
|
||||||
|
// are not being set.
|
||||||
|
if (environment != nullptr) {
|
||||||
|
// input language
|
||||||
|
if (environment->input.languageFamily != EShSourceNone) {
|
||||||
|
stage = environment->input.stage;
|
||||||
|
switch (environment->input.dialect) {
|
||||||
|
case EShClientNone:
|
||||||
|
break;
|
||||||
|
case EShClientVulkan:
|
||||||
|
spvVersion.vulkanGlsl = environment->input.dialectVersion;
|
||||||
|
break;
|
||||||
|
case EShClientOpenGL:
|
||||||
|
spvVersion.openGl = environment->input.dialectVersion;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (environment->input.languageFamily) {
|
||||||
|
case EShSourceNone:
|
||||||
|
break;
|
||||||
|
case EShSourceGlsl:
|
||||||
|
source = EShSourceGlsl;
|
||||||
|
messages = static_cast<EShMessages>(messages & ~EShMsgReadHlsl);
|
||||||
|
break;
|
||||||
|
case EShSourceHlsl:
|
||||||
|
source = EShSourceHlsl;
|
||||||
|
messages = static_cast<EShMessages>(messages | EShMsgReadHlsl);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// client
|
||||||
|
switch (environment->client.client) {
|
||||||
|
case EShClientVulkan:
|
||||||
|
spvVersion.vulkan = environment->client.version;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// generated code
|
||||||
|
switch (environment->target.language) {
|
||||||
|
case EshTargetSpv:
|
||||||
|
spvVersion.spv = environment->target.version;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This is the common setup and cleanup code for PreprocessDeferred and
|
// This is the common setup and cleanup code for PreprocessDeferred and
|
||||||
// CompileDeferred.
|
// CompileDeferred.
|
||||||
// It takes any callable with a signature of
|
// It takes any callable with a signature of
|
||||||
@ -599,8 +666,8 @@ bool ProcessDeferred(
|
|||||||
ProcessingContext& processingContext,
|
ProcessingContext& processingContext,
|
||||||
bool requireNonempty,
|
bool requireNonempty,
|
||||||
TShader::Includer& includer,
|
TShader::Includer& includer,
|
||||||
const std::string sourceEntryPointName = ""
|
const std::string sourceEntryPointName = "",
|
||||||
)
|
const TEnvironment* environment = nullptr) // optional way of fully setting all versions, overriding the above
|
||||||
{
|
{
|
||||||
if (! InitThread())
|
if (! InitThread())
|
||||||
return false;
|
return false;
|
||||||
@ -641,6 +708,13 @@ bool ProcessDeferred(
|
|||||||
names[s + numPre] = nullptr;
|
names[s + numPre] = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get all the stages, languages, clients, and other environment
|
||||||
|
// stuff sorted out.
|
||||||
|
EShSource source = (messages & EShMsgReadHlsl) != 0 ? EShSourceHlsl : EShSourceGlsl;
|
||||||
|
SpvVersion spvVersion;
|
||||||
|
EShLanguage stage = compiler->getLanguage();
|
||||||
|
TranslateEnvironment(environment, messages, source, stage, spvVersion);
|
||||||
|
|
||||||
// First, without using the preprocessor or parser, find the #version, so we know what
|
// First, without using the preprocessor or parser, find the #version, so we know what
|
||||||
// symbol tables, processing rules, etc. to set up. This does not need the extra strings
|
// symbol tables, processing rules, etc. to set up. This does not need the extra strings
|
||||||
// outlined above, just the user shader, after the system and user preambles.
|
// outlined above, just the user shader, after the system and user preambles.
|
||||||
@ -648,11 +722,11 @@ bool ProcessDeferred(
|
|||||||
int version = 0;
|
int version = 0;
|
||||||
EProfile profile = ENoProfile;
|
EProfile profile = ENoProfile;
|
||||||
bool versionNotFirstToken = false;
|
bool versionNotFirstToken = false;
|
||||||
bool versionNotFirst = (messages & EShMsgReadHlsl) ?
|
bool versionNotFirst = (source == EShSourceHlsl)
|
||||||
true :
|
? true
|
||||||
userInput.scanVersion(version, profile, versionNotFirstToken);
|
: userInput.scanVersion(version, profile, versionNotFirstToken);
|
||||||
bool versionNotFound = version == 0;
|
bool versionNotFound = version == 0;
|
||||||
if (forceDefaultVersionAndProfile && (messages & EShMsgReadHlsl) == 0) {
|
if (forceDefaultVersionAndProfile && source == EShSourceGlsl) {
|
||||||
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 ("
|
||||||
@ -669,15 +743,8 @@ bool ProcessDeferred(
|
|||||||
version = defaultVersion;
|
version = defaultVersion;
|
||||||
profile = defaultProfile;
|
profile = defaultProfile;
|
||||||
}
|
}
|
||||||
SpvVersion spvVersion;
|
|
||||||
if (messages & EShMsgSpvRules)
|
bool goodVersion = DeduceVersionProfile(compiler->infoSink, stage,
|
||||||
spvVersion.spv = 0x00010000; // TODO: eventually have this come from the outside
|
|
||||||
EShSource source = (messages & EShMsgReadHlsl) ? EShSourceHlsl : EShSourceGlsl;
|
|
||||||
if (messages & EShMsgVulkanRules)
|
|
||||||
spvVersion.vulkan = 100; // TODO: eventually have this come from the outside
|
|
||||||
else if (spvVersion.spv != 0)
|
|
||||||
spvVersion.openGl = 100; // TODO: eventually have this come from the outside
|
|
||||||
bool goodVersion = DeduceVersionProfile(compiler->infoSink, compiler->getLanguage(),
|
|
||||||
versionNotFirst, defaultVersion, source, version, profile, spvVersion);
|
versionNotFirst, defaultVersion, source, version, profile, spvVersion);
|
||||||
bool versionWillBeError = (versionNotFound || (profile == EEsProfile && version >= 300 && versionNotFirst));
|
bool versionWillBeError = (versionNotFound || (profile == EEsProfile && version >= 300 && versionNotFirst));
|
||||||
bool warnVersionNotFirst = false;
|
bool warnVersionNotFirst = false;
|
||||||
@ -694,7 +761,7 @@ bool ProcessDeferred(
|
|||||||
intermediate.setSpv(spvVersion);
|
intermediate.setSpv(spvVersion);
|
||||||
if (spvVersion.vulkan >= 100)
|
if (spvVersion.vulkan >= 100)
|
||||||
intermediate.setOriginUpperLeft();
|
intermediate.setOriginUpperLeft();
|
||||||
if ((messages & EShMsgHlslOffsets) || (messages & EShMsgReadHlsl))
|
if ((messages & EShMsgHlslOffsets) || source == EShSourceHlsl)
|
||||||
intermediate.setHlslOffsets();
|
intermediate.setHlslOffsets();
|
||||||
if (messages & EShMsgDebugInfo) {
|
if (messages & EShMsgDebugInfo) {
|
||||||
intermediate.setSourceFile(names[numPre]);
|
intermediate.setSourceFile(names[numPre]);
|
||||||
@ -707,7 +774,7 @@ bool ProcessDeferred(
|
|||||||
[MapSpvVersionToIndex(spvVersion)]
|
[MapSpvVersionToIndex(spvVersion)]
|
||||||
[MapProfileToIndex(profile)]
|
[MapProfileToIndex(profile)]
|
||||||
[MapSourceToIndex(source)]
|
[MapSourceToIndex(source)]
|
||||||
[compiler->getLanguage()];
|
[stage];
|
||||||
|
|
||||||
// Dynamically allocate the symbol table so we can control when it is deallocated WRT the pool.
|
// Dynamically allocate the symbol table so we can control when it is deallocated WRT the pool.
|
||||||
TSymbolTable* symbolTableMemory = new TSymbolTable;
|
TSymbolTable* symbolTableMemory = new TSymbolTable;
|
||||||
@ -718,7 +785,7 @@ bool ProcessDeferred(
|
|||||||
// Add built-in symbols that are potentially context dependent;
|
// Add built-in symbols that are potentially context dependent;
|
||||||
// they get popped again further down.
|
// they get popped again further down.
|
||||||
if (! AddContextSpecificSymbols(resources, compiler->infoSink, symbolTable, version, profile, spvVersion,
|
if (! AddContextSpecificSymbols(resources, compiler->infoSink, symbolTable, version, profile, spvVersion,
|
||||||
compiler->getLanguage(), source))
|
stage, source))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -726,14 +793,14 @@ bool ProcessDeferred(
|
|||||||
//
|
//
|
||||||
|
|
||||||
TParseContextBase* parseContext = CreateParseContext(symbolTable, intermediate, version, profile, source,
|
TParseContextBase* parseContext = CreateParseContext(symbolTable, intermediate, version, profile, source,
|
||||||
compiler->getLanguage(), compiler->infoSink,
|
stage, compiler->infoSink,
|
||||||
spvVersion, forwardCompatible, messages, false, sourceEntryPointName);
|
spvVersion, forwardCompatible, messages, false, sourceEntryPointName);
|
||||||
|
|
||||||
TPpContext ppContext(*parseContext, names[numPre] ? names[numPre] : "", includer);
|
TPpContext ppContext(*parseContext, names[numPre] ? names[numPre] : "", includer);
|
||||||
|
|
||||||
// only GLSL (bison triggered, really) needs an externally set scan context
|
// only GLSL (bison triggered, really) needs an externally set scan context
|
||||||
glslang::TScanContext scanContext(*parseContext);
|
glslang::TScanContext scanContext(*parseContext);
|
||||||
if ((messages & EShMsgReadHlsl) == 0)
|
if (source == EShSourceGlsl)
|
||||||
parseContext->setScanContext(&scanContext);
|
parseContext->setScanContext(&scanContext);
|
||||||
|
|
||||||
parseContext->setPpContext(&ppContext);
|
parseContext->setPpContext(&ppContext);
|
||||||
@ -1052,14 +1119,15 @@ bool CompileDeferred(
|
|||||||
EShMessages messages, // warnings/errors/AST; things to print out
|
EShMessages messages, // warnings/errors/AST; things to print out
|
||||||
TIntermediate& intermediate,// returned tree, etc.
|
TIntermediate& intermediate,// returned tree, etc.
|
||||||
TShader::Includer& includer,
|
TShader::Includer& includer,
|
||||||
const std::string sourceEntryPointName = "")
|
const std::string sourceEntryPointName = "",
|
||||||
|
TEnvironment* environment = nullptr)
|
||||||
{
|
{
|
||||||
DoFullParse parser;
|
DoFullParse parser;
|
||||||
return ProcessDeferred(compiler, shaderStrings, numStrings, inputLengths, stringNames,
|
return ProcessDeferred(compiler, shaderStrings, numStrings, inputLengths, stringNames,
|
||||||
preamble, optLevel, resources, defaultVersion,
|
preamble, optLevel, resources, defaultVersion,
|
||||||
defaultProfile, forceDefaultVersionAndProfile,
|
defaultProfile, forceDefaultVersionAndProfile,
|
||||||
forwardCompatible, messages, intermediate, parser,
|
forwardCompatible, messages, intermediate, parser,
|
||||||
true, includer, sourceEntryPointName);
|
true, includer, sourceEntryPointName, environment);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end anonymous namespace for local functions
|
} // end anonymous namespace for local functions
|
||||||
@ -1485,6 +1553,12 @@ TShader::TShader(EShLanguage s)
|
|||||||
infoSink = new TInfoSink;
|
infoSink = new TInfoSink;
|
||||||
compiler = new TDeferredCompiler(stage, *infoSink);
|
compiler = new TDeferredCompiler(stage, *infoSink);
|
||||||
intermediate = new TIntermediate(s);
|
intermediate = new TIntermediate(s);
|
||||||
|
|
||||||
|
// clear environment (avoid constructors in them for use in a C interface)
|
||||||
|
environment.input.languageFamily = EShSourceNone;
|
||||||
|
environment.input.dialect = EShClientNone;
|
||||||
|
environment.client.client = EShClientNone;
|
||||||
|
environment.target.language = EShTargetNone;
|
||||||
}
|
}
|
||||||
|
|
||||||
TShader::~TShader()
|
TShader::~TShader()
|
||||||
@ -1572,7 +1646,8 @@ bool TShader::parse(const TBuiltInResource* builtInResources, int defaultVersion
|
|||||||
return CompileDeferred(compiler, strings, numStrings, lengths, stringNames,
|
return CompileDeferred(compiler, strings, numStrings, lengths, stringNames,
|
||||||
preamble, EShOptNone, builtInResources, defaultVersion,
|
preamble, EShOptNone, builtInResources, defaultVersion,
|
||||||
defaultProfile, forceDefaultVersionAndProfile,
|
defaultProfile, forceDefaultVersionAndProfile,
|
||||||
forwardCompatible, messages, *intermediate, includer, sourceEntryPointName);
|
forwardCompatible, messages, *intermediate, includer, sourceEntryPointName,
|
||||||
|
&environment);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill in a string with the result of preprocessing ShaderStrings
|
// Fill in a string with the result of preprocessing ShaderStrings
|
||||||
|
|||||||
@ -355,9 +355,9 @@ void TParseVersions::getPreamble(std::string& preamble)
|
|||||||
// #define VULKAN XXXX
|
// #define VULKAN XXXX
|
||||||
const int numberBufSize = 12;
|
const int numberBufSize = 12;
|
||||||
char numberBuf[numberBufSize];
|
char numberBuf[numberBufSize];
|
||||||
if (spvVersion.vulkan > 0) {
|
if (spvVersion.vulkanGlsl > 0) {
|
||||||
preamble += "#define VULKAN ";
|
preamble += "#define VULKAN ";
|
||||||
snprintf(numberBuf, numberBufSize, "%d", spvVersion.vulkan);
|
snprintf(numberBuf, numberBufSize, "%d", spvVersion.vulkanGlsl);
|
||||||
preamble += numberBuf;
|
preamble += numberBuf;
|
||||||
preamble += "\n";
|
preamble += "\n";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -72,14 +72,19 @@ inline const char* ProfileName(EProfile profile)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// SPIR-V has versions for multiple things; tie them together.
|
// What source rules, validation rules, target language, etc. are needed
|
||||||
// 0 means a target or rule set is not enabled.
|
// desired for SPIR-V?
|
||||||
|
//
|
||||||
|
// 0 means a target or rule set is not enabled (ignore rules from that entity).
|
||||||
|
// Non-0 means to apply semantic rules arising from that version of its rule set.
|
||||||
|
// The union of all requested rule sets will be applied.
|
||||||
//
|
//
|
||||||
struct SpvVersion {
|
struct SpvVersion {
|
||||||
SpvVersion() : spv(0), vulkan(0), openGl(0) {}
|
SpvVersion() : spv(0), vulkanGlsl(0), vulkan(0), openGl(0) {}
|
||||||
unsigned int spv; // the version of the targeted SPIR-V, as defined by SPIR-V in word 1 of the SPIR-V binary header
|
unsigned int spv; // the version of SPIR-V to target, as defined by "word 1" of the SPIR-V binary header
|
||||||
int vulkan; // the version of semantics for Vulkan; e.g., for GLSL from KHR_vulkan_glsl "#define VULKAN"
|
int vulkanGlsl; // the version of GLSL semantics for Vulkan, from GL_KHR_vulkan_glsl, for "#define VULKAN XXX"
|
||||||
int openGl; // the version of semantics for OpenGL; e.g., for GLSL from KHR_vulkan_glsl "#define GL_SPIRV"
|
int vulkan; // the version of Vulkan, for which SPIR-V execution environment rules to use (100 means 1.0)
|
||||||
|
int openGl; // the version of GLSL semantics for OpenGL, from GL_ARB_gl_spirv, for "#define GL_SPIRV XXX"
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@ -112,6 +112,43 @@ typedef enum {
|
|||||||
EShSourceHlsl,
|
EShSourceHlsl,
|
||||||
} EShSource; // if EShLanguage were EShStage, this could be EShLanguage instead
|
} EShSource; // if EShLanguage were EShStage, this could be EShLanguage instead
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EShClientNone,
|
||||||
|
EShClientVulkan,
|
||||||
|
EShClientOpenGL,
|
||||||
|
} EShClient;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EShTargetNone,
|
||||||
|
EshTargetSpv,
|
||||||
|
} EShTargetLanguage;
|
||||||
|
|
||||||
|
struct TInputLanguage {
|
||||||
|
EShSource languageFamily; // redundant information with other input, this one overrides when not EShSourceNone
|
||||||
|
EShLanguage stage; // redundant information with other input, this one overrides when not EShSourceNone
|
||||||
|
EShClient dialect;
|
||||||
|
int dialectVersion; // version of client's language definition, not the client (when not EShClientNone)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TClient {
|
||||||
|
EShClient client;
|
||||||
|
int version; // version of client itself (not the client's input dialect)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TTarget {
|
||||||
|
EShTargetLanguage language;
|
||||||
|
unsigned int version; // the version to target, if SPIR-V, defined by "word 1" of the SPIR-V binary header
|
||||||
|
};
|
||||||
|
|
||||||
|
// All source/client/target versions and settings.
|
||||||
|
// Can override previous methods of setting, when items are set here.
|
||||||
|
// Expected to grow, as more are added, rather than growing parameter lists.
|
||||||
|
struct TEnvironment {
|
||||||
|
TInputLanguage input; // definition of the input language
|
||||||
|
TClient client; // what client is the overall compilation being done for?
|
||||||
|
TTarget target; // what to generate
|
||||||
|
};
|
||||||
|
|
||||||
const char* StageName(EShLanguage);
|
const char* StageName(EShLanguage);
|
||||||
|
|
||||||
} // end namespace glslang
|
} // end namespace glslang
|
||||||
@ -324,6 +361,25 @@ public:
|
|||||||
void setNoStorageFormat(bool useUnknownFormat);
|
void setNoStorageFormat(bool useUnknownFormat);
|
||||||
void setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode);
|
void setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode);
|
||||||
|
|
||||||
|
// For setting up the environment (initialized in the constructor):
|
||||||
|
void setEnvInput(EShSource lang, EShLanguage stage, EShClient client, int version)
|
||||||
|
{
|
||||||
|
environment.input.languageFamily = lang;
|
||||||
|
environment.input.stage = stage;
|
||||||
|
environment.input.dialect = client;
|
||||||
|
environment.input.dialectVersion = version;
|
||||||
|
}
|
||||||
|
void setEnvClient(EShClient client, int version)
|
||||||
|
{
|
||||||
|
environment.client.client = client;
|
||||||
|
environment.client.version = version;
|
||||||
|
}
|
||||||
|
void setEnvTarget(EShTargetLanguage lang, unsigned int version)
|
||||||
|
{
|
||||||
|
environment.target.language = lang;
|
||||||
|
environment.target.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
// Interface to #include handlers.
|
// Interface to #include handlers.
|
||||||
//
|
//
|
||||||
// To support #include, a client of Glslang does the following:
|
// To support #include, a client of Glslang does the following:
|
||||||
@ -463,6 +519,8 @@ protected:
|
|||||||
// a function in the source string can be renamed FROM this TO the name given in setEntryPoint.
|
// a function in the source string can be renamed FROM this TO the name given in setEntryPoint.
|
||||||
std::string sourceEntryPointName;
|
std::string sourceEntryPointName;
|
||||||
|
|
||||||
|
TEnvironment environment;
|
||||||
|
|
||||||
friend class TProgram;
|
friend class TProgram;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user