зеркало из https://github.com/stride3d/xkslang.git
Infrastructure: Non-functional: Move to rich description of environment.
This is for input languages, client APIs, code to generate, etc.
This commit is contained in:
Родитель
4fbb8cb45e
Коммит
4be4aebdcd
|
@ -715,9 +715,27 @@ void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
|
|||
if (Options & EOptionAutoMapLocations)
|
||||
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, 100);
|
||||
shader->setEnvClient(glslang::EShClientVulkan, 100);
|
||||
shader->setEnvTarget(glslang::EshTargetSpv, 0x00001000);
|
||||
} else {
|
||||
shader->setEnvInput((Options & EOptionReadHlsl) ? glslang::EShSourceHlsl
|
||||
: glslang::EShSourceGlsl,
|
||||
compUnit.stage, glslang::EShClientOpenGL, 100);
|
||||
shader->setEnvClient(glslang::EShClientOpenGL, 450);
|
||||
shader->setEnvTarget(glslang::EshTargetSpv, 0x00001000);
|
||||
}
|
||||
}
|
||||
|
||||
shaders.push_back(shader);
|
||||
|
||||
const int defaultVersion = Options & EOptionDefaultDesktop? 110: 100;
|
||||
const int defaultVersion = Options & EOptionDefaultDesktop ? 110 : 100;
|
||||
|
||||
DirStackFileIncluder includer;
|
||||
std::for_each(IncludeDirectoryList.rbegin(), IncludeDirectoryList.rend(), [&includer](const std::string& dir) {
|
||||
|
|
|
@ -50,7 +50,8 @@ namespace glslang {
|
|||
TParseContext::TParseContext(TSymbolTable& symbolTable, TIntermediate& interm, bool parsingBuiltins,
|
||||
int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language,
|
||||
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),
|
||||
blockName(nullptr),
|
||||
limits(resources.limits),
|
||||
|
|
|
@ -569,6 +569,73 @@ bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNo
|
|||
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
|
||||
// CompileDeferred.
|
||||
// It takes any callable with a signature of
|
||||
|
@ -599,8 +666,8 @@ bool ProcessDeferred(
|
|||
ProcessingContext& processingContext,
|
||||
bool requireNonempty,
|
||||
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())
|
||||
return false;
|
||||
|
@ -641,6 +708,13 @@ bool ProcessDeferred(
|
|||
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
|
||||
// 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.
|
||||
|
@ -648,11 +722,11 @@ bool ProcessDeferred(
|
|||
int version = 0;
|
||||
EProfile profile = ENoProfile;
|
||||
bool versionNotFirstToken = false;
|
||||
bool versionNotFirst = (messages & EShMsgReadHlsl) ?
|
||||
true :
|
||||
userInput.scanVersion(version, profile, versionNotFirstToken);
|
||||
bool versionNotFirst = (source == EShSourceHlsl)
|
||||
? true
|
||||
: userInput.scanVersion(version, profile, versionNotFirstToken);
|
||||
bool versionNotFound = version == 0;
|
||||
if (forceDefaultVersionAndProfile && (messages & EShMsgReadHlsl) == 0) {
|
||||
if (forceDefaultVersionAndProfile && source == EShSourceGlsl) {
|
||||
if (! (messages & EShMsgSuppressWarnings) && ! versionNotFound &&
|
||||
(version != defaultVersion || profile != defaultProfile)) {
|
||||
compiler->infoSink.info << "Warning, (version, profile) forced to be ("
|
||||
|
@ -669,15 +743,8 @@ bool ProcessDeferred(
|
|||
version = defaultVersion;
|
||||
profile = defaultProfile;
|
||||
}
|
||||
SpvVersion spvVersion;
|
||||
if (messages & EShMsgSpvRules)
|
||||
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(),
|
||||
|
||||
bool goodVersion = DeduceVersionProfile(compiler->infoSink, stage,
|
||||
versionNotFirst, defaultVersion, source, version, profile, spvVersion);
|
||||
bool versionWillBeError = (versionNotFound || (profile == EEsProfile && version >= 300 && versionNotFirst));
|
||||
bool warnVersionNotFirst = false;
|
||||
|
@ -694,7 +761,7 @@ bool ProcessDeferred(
|
|||
intermediate.setSpv(spvVersion);
|
||||
if (spvVersion.vulkan >= 100)
|
||||
intermediate.setOriginUpperLeft();
|
||||
if ((messages & EShMsgHlslOffsets) || (messages & EShMsgReadHlsl))
|
||||
if ((messages & EShMsgHlslOffsets) || source == EShSourceHlsl)
|
||||
intermediate.setHlslOffsets();
|
||||
if (messages & EShMsgDebugInfo) {
|
||||
intermediate.setSourceFile(names[numPre]);
|
||||
|
@ -707,7 +774,7 @@ bool ProcessDeferred(
|
|||
[MapSpvVersionToIndex(spvVersion)]
|
||||
[MapProfileToIndex(profile)]
|
||||
[MapSourceToIndex(source)]
|
||||
[compiler->getLanguage()];
|
||||
[stage];
|
||||
|
||||
// Dynamically allocate the symbol table so we can control when it is deallocated WRT the pool.
|
||||
TSymbolTable* symbolTableMemory = new TSymbolTable;
|
||||
|
@ -718,7 +785,7 @@ bool ProcessDeferred(
|
|||
// Add built-in symbols that are potentially context dependent;
|
||||
// they get popped again further down.
|
||||
if (! AddContextSpecificSymbols(resources, compiler->infoSink, symbolTable, version, profile, spvVersion,
|
||||
compiler->getLanguage(), source))
|
||||
stage, source))
|
||||
return false;
|
||||
|
||||
//
|
||||
|
@ -726,14 +793,14 @@ bool ProcessDeferred(
|
|||
//
|
||||
|
||||
TParseContextBase* parseContext = CreateParseContext(symbolTable, intermediate, version, profile, source,
|
||||
compiler->getLanguage(), compiler->infoSink,
|
||||
stage, compiler->infoSink,
|
||||
spvVersion, forwardCompatible, messages, false, sourceEntryPointName);
|
||||
|
||||
TPpContext ppContext(*parseContext, names[numPre] ? names[numPre] : "", includer);
|
||||
|
||||
// only GLSL (bison triggered, really) needs an externally set scan context
|
||||
glslang::TScanContext scanContext(*parseContext);
|
||||
if ((messages & EShMsgReadHlsl) == 0)
|
||||
if (source == EShSourceGlsl)
|
||||
parseContext->setScanContext(&scanContext);
|
||||
|
||||
parseContext->setPpContext(&ppContext);
|
||||
|
@ -1052,14 +1119,15 @@ bool CompileDeferred(
|
|||
EShMessages messages, // warnings/errors/AST; things to print out
|
||||
TIntermediate& intermediate,// returned tree, etc.
|
||||
TShader::Includer& includer,
|
||||
const std::string sourceEntryPointName = "")
|
||||
const std::string sourceEntryPointName = "",
|
||||
TEnvironment* environment = nullptr)
|
||||
{
|
||||
DoFullParse parser;
|
||||
return ProcessDeferred(compiler, shaderStrings, numStrings, inputLengths, stringNames,
|
||||
preamble, optLevel, resources, defaultVersion,
|
||||
defaultProfile, forceDefaultVersionAndProfile,
|
||||
forwardCompatible, messages, intermediate, parser,
|
||||
true, includer, sourceEntryPointName);
|
||||
true, includer, sourceEntryPointName, environment);
|
||||
}
|
||||
|
||||
} // end anonymous namespace for local functions
|
||||
|
@ -1485,6 +1553,12 @@ TShader::TShader(EShLanguage s)
|
|||
infoSink = new TInfoSink;
|
||||
compiler = new TDeferredCompiler(stage, *infoSink);
|
||||
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()
|
||||
|
@ -1572,7 +1646,8 @@ bool TShader::parse(const TBuiltInResource* builtInResources, int defaultVersion
|
|||
return CompileDeferred(compiler, strings, numStrings, lengths, stringNames,
|
||||
preamble, EShOptNone, builtInResources, defaultVersion,
|
||||
defaultProfile, forceDefaultVersionAndProfile,
|
||||
forwardCompatible, messages, *intermediate, includer, sourceEntryPointName);
|
||||
forwardCompatible, messages, *intermediate, includer, sourceEntryPointName,
|
||||
&environment);
|
||||
}
|
||||
|
||||
// Fill in a string with the result of preprocessing ShaderStrings
|
||||
|
|
|
@ -355,9 +355,9 @@ void TParseVersions::getPreamble(std::string& preamble)
|
|||
// #define VULKAN XXXX
|
||||
const int numberBufSize = 12;
|
||||
char numberBuf[numberBufSize];
|
||||
if (spvVersion.vulkan > 0) {
|
||||
if (spvVersion.vulkanGlsl > 0) {
|
||||
preamble += "#define VULKAN ";
|
||||
snprintf(numberBuf, numberBufSize, "%d", spvVersion.vulkan);
|
||||
snprintf(numberBuf, numberBufSize, "%d", spvVersion.vulkanGlsl);
|
||||
preamble += numberBuf;
|
||||
preamble += "\n";
|
||||
}
|
||||
|
|
|
@ -72,14 +72,19 @@ inline const char* ProfileName(EProfile profile)
|
|||
}
|
||||
|
||||
//
|
||||
// SPIR-V has versions for multiple things; tie them together.
|
||||
// 0 means a target or rule set is not enabled.
|
||||
// What source rules, validation rules, target language, etc. are needed
|
||||
// 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 {
|
||||
SpvVersion() : spv(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
|
||||
int vulkan; // the version of semantics for Vulkan; e.g., for GLSL from KHR_vulkan_glsl "#define VULKAN"
|
||||
int openGl; // the version of semantics for OpenGL; e.g., for GLSL from KHR_vulkan_glsl "#define GL_SPIRV"
|
||||
SpvVersion() : spv(0), vulkanGlsl(0), vulkan(0), openGl(0) {}
|
||||
unsigned int spv; // the version of SPIR-V to target, as defined by "word 1" of the SPIR-V binary header
|
||||
int vulkanGlsl; // the version of GLSL semantics for Vulkan, from GL_KHR_vulkan_glsl, for "#define VULKAN XXX"
|
||||
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"
|
||||
};
|
||||
|
||||
//
|
||||
|
|
|
@ -110,7 +110,44 @@ typedef enum {
|
|||
EShSourceNone,
|
||||
EShSourceGlsl,
|
||||
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);
|
||||
|
||||
|
@ -324,6 +361,25 @@ public:
|
|||
void setNoStorageFormat(bool useUnknownFormat);
|
||||
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.
|
||||
//
|
||||
// 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.
|
||||
std::string sourceEntryPointName;
|
||||
|
||||
TEnvironment environment;
|
||||
|
||||
friend class TProgram;
|
||||
|
||||
private:
|
||||
|
|
Загрузка…
Ссылка в новой задаче