rendering: generate single-source shader keyword variants
This commit is contained in:
@@ -954,6 +954,82 @@ Containers::String StripUnityStyleAuthoringPragmas(const Containers::String& sou
|
||||
return strippedSource.c_str();
|
||||
}
|
||||
|
||||
Containers::String BuildShaderKeywordSetSignature(const ShaderKeywordSet& keywordSet) {
|
||||
ShaderKeywordSet normalizedKeywords = keywordSet;
|
||||
NormalizeShaderKeywordSetInPlace(normalizedKeywords);
|
||||
|
||||
Containers::String signature;
|
||||
for (size_t keywordIndex = 0; keywordIndex < normalizedKeywords.enabledKeywords.Size(); ++keywordIndex) {
|
||||
if (keywordIndex > 0) {
|
||||
signature += ";";
|
||||
}
|
||||
|
||||
signature += normalizedKeywords.enabledKeywords[keywordIndex];
|
||||
}
|
||||
|
||||
return signature;
|
||||
}
|
||||
|
||||
std::vector<ShaderKeywordSet> BuildShaderKeywordVariantSets(
|
||||
const Containers::Array<ShaderKeywordDeclaration>& declarations) {
|
||||
std::vector<ShaderKeywordSet> keywordSets(1);
|
||||
|
||||
for (const ShaderKeywordDeclaration& declaration : declarations) {
|
||||
if (declaration.options.Empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<ShaderKeywordSet> nextKeywordSets;
|
||||
std::unordered_set<std::string> seenSignatures;
|
||||
nextKeywordSets.reserve(keywordSets.size() * declaration.options.Size());
|
||||
|
||||
for (const ShaderKeywordSet& currentKeywordSet : keywordSets) {
|
||||
for (const Containers::String& option : declaration.options) {
|
||||
ShaderKeywordSet nextKeywordSet = currentKeywordSet;
|
||||
const Containers::String normalizedKeyword = NormalizeShaderKeywordToken(option);
|
||||
if (!normalizedKeyword.Empty()) {
|
||||
nextKeywordSet.enabledKeywords.PushBack(normalizedKeyword);
|
||||
}
|
||||
|
||||
NormalizeShaderKeywordSetInPlace(nextKeywordSet);
|
||||
const std::string signature =
|
||||
ToStdString(BuildShaderKeywordSetSignature(nextKeywordSet));
|
||||
if (seenSignatures.insert(signature).second) {
|
||||
nextKeywordSets.push_back(std::move(nextKeywordSet));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!nextKeywordSets.empty()) {
|
||||
keywordSets = std::move(nextKeywordSets);
|
||||
}
|
||||
}
|
||||
|
||||
if (keywordSets.empty()) {
|
||||
keywordSets.emplace_back();
|
||||
}
|
||||
|
||||
return keywordSets;
|
||||
}
|
||||
|
||||
Containers::String BuildSingleSourceVariantSource(
|
||||
const Containers::String& strippedCombinedSource,
|
||||
const ShaderKeywordSet& requiredKeywords) {
|
||||
Containers::String variantSource;
|
||||
for (const Containers::String& keyword : requiredKeywords.enabledKeywords) {
|
||||
variantSource += "#define ";
|
||||
variantSource += keyword;
|
||||
variantSource += " 1\n";
|
||||
}
|
||||
|
||||
if (!variantSource.Empty() && !strippedCombinedSource.Empty()) {
|
||||
variantSource += '\n';
|
||||
}
|
||||
|
||||
variantSource += strippedCombinedSource;
|
||||
return variantSource;
|
||||
}
|
||||
|
||||
bool TryParseShaderKeywordDeclarationPragma(
|
||||
const std::vector<std::string>& pragmaTokens,
|
||||
ShaderKeywordDeclaration& outDeclaration) {
|
||||
@@ -2043,37 +2119,47 @@ LoadResult BuildShaderFromAuthoringDesc(
|
||||
AppendAuthoringSourceBlock(combinedSource, subShader.sharedProgramSource);
|
||||
AppendAuthoringSourceBlock(combinedSource, pass.sharedProgramSource);
|
||||
AppendAuthoringSourceBlock(combinedSource, pass.programSource);
|
||||
combinedSource = StripUnityStyleAuthoringPragmas(combinedSource);
|
||||
const Containers::String strippedCombinedSource =
|
||||
StripUnityStyleAuthoringPragmas(combinedSource);
|
||||
const std::vector<ShaderKeywordSet> keywordSets =
|
||||
BuildShaderKeywordVariantSets(pass.keywordDeclarations);
|
||||
|
||||
ShaderStageVariant vertexVariant = {};
|
||||
vertexVariant.stage = ShaderType::Vertex;
|
||||
vertexVariant.backend = ShaderBackend::Generic;
|
||||
vertexVariant.language = ShaderLanguage::HLSL;
|
||||
vertexVariant.entryPoint =
|
||||
!pass.vertexEntryPoint.Empty()
|
||||
? pass.vertexEntryPoint
|
||||
: GetDefaultEntryPoint(ShaderLanguage::HLSL, ShaderType::Vertex);
|
||||
vertexVariant.profile = GetDefaultProfile(
|
||||
ShaderLanguage::HLSL,
|
||||
ShaderBackend::Generic,
|
||||
ShaderType::Vertex);
|
||||
vertexVariant.sourceCode = combinedSource;
|
||||
shader->AddPassVariant(pass.name, vertexVariant);
|
||||
for (const ShaderKeywordSet& keywordSet : keywordSets) {
|
||||
const Containers::String variantSource =
|
||||
BuildSingleSourceVariantSource(strippedCombinedSource, keywordSet);
|
||||
|
||||
ShaderStageVariant fragmentVariant = {};
|
||||
fragmentVariant.stage = ShaderType::Fragment;
|
||||
fragmentVariant.backend = ShaderBackend::Generic;
|
||||
fragmentVariant.language = ShaderLanguage::HLSL;
|
||||
fragmentVariant.entryPoint =
|
||||
!pass.fragmentEntryPoint.Empty()
|
||||
? pass.fragmentEntryPoint
|
||||
: GetDefaultEntryPoint(ShaderLanguage::HLSL, ShaderType::Fragment);
|
||||
fragmentVariant.profile = GetDefaultProfile(
|
||||
ShaderLanguage::HLSL,
|
||||
ShaderBackend::Generic,
|
||||
ShaderType::Fragment);
|
||||
fragmentVariant.sourceCode = combinedSource;
|
||||
shader->AddPassVariant(pass.name, fragmentVariant);
|
||||
ShaderStageVariant vertexVariant = {};
|
||||
vertexVariant.stage = ShaderType::Vertex;
|
||||
vertexVariant.backend = ShaderBackend::Generic;
|
||||
vertexVariant.language = ShaderLanguage::HLSL;
|
||||
vertexVariant.requiredKeywords = keywordSet;
|
||||
vertexVariant.entryPoint =
|
||||
!pass.vertexEntryPoint.Empty()
|
||||
? pass.vertexEntryPoint
|
||||
: GetDefaultEntryPoint(ShaderLanguage::HLSL, ShaderType::Vertex);
|
||||
vertexVariant.profile = GetDefaultProfile(
|
||||
ShaderLanguage::HLSL,
|
||||
ShaderBackend::Generic,
|
||||
ShaderType::Vertex);
|
||||
vertexVariant.sourceCode = variantSource;
|
||||
shader->AddPassVariant(pass.name, vertexVariant);
|
||||
|
||||
ShaderStageVariant fragmentVariant = {};
|
||||
fragmentVariant.stage = ShaderType::Fragment;
|
||||
fragmentVariant.backend = ShaderBackend::Generic;
|
||||
fragmentVariant.language = ShaderLanguage::HLSL;
|
||||
fragmentVariant.requiredKeywords = keywordSet;
|
||||
fragmentVariant.entryPoint =
|
||||
!pass.fragmentEntryPoint.Empty()
|
||||
? pass.fragmentEntryPoint
|
||||
: GetDefaultEntryPoint(ShaderLanguage::HLSL, ShaderType::Fragment);
|
||||
fragmentVariant.profile = GetDefaultProfile(
|
||||
ShaderLanguage::HLSL,
|
||||
ShaderBackend::Generic,
|
||||
ShaderType::Fragment);
|
||||
fragmentVariant.sourceCode = variantSource;
|
||||
shader->AddPassVariant(pass.name, fragmentVariant);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user