rendering: formalize shader keyword metadata contract
This commit is contained in:
@@ -611,6 +611,7 @@ struct AuthoringPassEntry {
|
||||
Containers::String name;
|
||||
std::vector<AuthoringTagEntry> tags;
|
||||
Containers::Array<ShaderResourceBindingDesc> resources;
|
||||
Containers::Array<ShaderKeywordDeclaration> keywordDeclarations;
|
||||
Containers::String vertexEntryPoint;
|
||||
Containers::String fragmentEntryPoint;
|
||||
Containers::String sharedProgramSource;
|
||||
@@ -924,6 +925,31 @@ Containers::String StripUnityStyleAuthoringPragmas(const Containers::String& sou
|
||||
return strippedSource.c_str();
|
||||
}
|
||||
|
||||
bool TryParseShaderKeywordDeclarationPragma(
|
||||
const std::vector<std::string>& pragmaTokens,
|
||||
ShaderKeywordDeclaration& outDeclaration) {
|
||||
outDeclaration = {};
|
||||
if (pragmaTokens.size() < 3u) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pragmaTokens[1] == "multi_compile") {
|
||||
outDeclaration.type = ShaderKeywordDeclarationType::MultiCompile;
|
||||
} else if (pragmaTokens[1] == "shader_feature") {
|
||||
outDeclaration.type = ShaderKeywordDeclarationType::ShaderFeature;
|
||||
} else if (pragmaTokens[1] == "shader_feature_local") {
|
||||
outDeclaration.type = ShaderKeywordDeclarationType::ShaderFeatureLocal;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t tokenIndex = 2; tokenIndex < pragmaTokens.size(); ++tokenIndex) {
|
||||
outDeclaration.options.PushBack(pragmaTokens[tokenIndex].c_str());
|
||||
}
|
||||
|
||||
return !outDeclaration.options.Empty();
|
||||
}
|
||||
|
||||
size_t FindMatchingDelimiter(
|
||||
const std::string& text,
|
||||
size_t openPos,
|
||||
@@ -1703,6 +1729,12 @@ bool ParseUnityStyleSingleSourceShaderAuthoring(
|
||||
(pragmaTokens[1] == "multi_compile" ||
|
||||
pragmaTokens[1] == "shader_feature" ||
|
||||
pragmaTokens[1] == "shader_feature_local")) {
|
||||
ShaderKeywordDeclaration declaration = {};
|
||||
if (!TryParseShaderKeywordDeclarationPragma(pragmaTokens, declaration)) {
|
||||
return fail("keyword pragma must declare at least one option", humanLine);
|
||||
}
|
||||
|
||||
currentPass->keywordDeclarations.PushBack(declaration);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1932,6 +1964,9 @@ LoadResult BuildShaderFromAuthoringDesc(
|
||||
for (const ShaderResourceBindingDesc& resourceBinding : pass.resources) {
|
||||
shader->AddPassResourceBinding(pass.name, resourceBinding);
|
||||
}
|
||||
for (const ShaderKeywordDeclaration& keywordDeclaration : pass.keywordDeclarations) {
|
||||
shader->AddPassKeywordDeclaration(pass.name, keywordDeclaration);
|
||||
}
|
||||
|
||||
if (!pass.backendVariants.empty()) {
|
||||
for (const AuthoringBackendVariantEntry& backendVariant : pass.backendVariants) {
|
||||
@@ -2182,6 +2217,11 @@ size_t CalculateShaderMemorySize(const Shader& shader) {
|
||||
memorySize += binding.name.Length();
|
||||
memorySize += binding.semantic.Length();
|
||||
}
|
||||
for (const ShaderKeywordDeclaration& declaration : pass.keywordDeclarations) {
|
||||
for (const Containers::String& option : declaration.options) {
|
||||
memorySize += option.Length();
|
||||
}
|
||||
}
|
||||
for (const ShaderStageVariant& variant : pass.variants) {
|
||||
memorySize += variant.entryPoint.Length();
|
||||
memorySize += variant.profile.Length();
|
||||
@@ -2439,7 +2479,10 @@ LoadResult LoadShaderArtifact(const Containers::String& path) {
|
||||
}
|
||||
|
||||
const std::string magic(fileHeader.magic, fileHeader.magic + 7);
|
||||
if (magic != "XCSHD01" || fileHeader.schemaVersion != kShaderArtifactSchemaVersion) {
|
||||
const bool isLegacySchema = magic == "XCSHD01" && fileHeader.schemaVersion == 1u;
|
||||
const bool isCurrentSchema =
|
||||
magic == "XCSHD02" && fileHeader.schemaVersion == kShaderArtifactSchemaVersion;
|
||||
if (!isLegacySchema && !isCurrentSchema) {
|
||||
return LoadResult("Invalid shader artifact header: " + path);
|
||||
}
|
||||
|
||||
@@ -2478,17 +2521,40 @@ LoadResult LoadShaderArtifact(const Containers::String& path) {
|
||||
|
||||
for (Core::uint32 passIndex = 0; passIndex < shaderHeader.passCount; ++passIndex) {
|
||||
Containers::String passName;
|
||||
ShaderPassArtifactHeader passHeader;
|
||||
if (!ReadShaderArtifactString(data, offset, passName) ||
|
||||
!ReadShaderArtifactValue(data, offset, passHeader)) {
|
||||
Core::uint32 tagCount = 0;
|
||||
Core::uint32 resourceCount = 0;
|
||||
Core::uint32 keywordDeclarationCount = 0;
|
||||
Core::uint32 variantCount = 0;
|
||||
if (!ReadShaderArtifactString(data, offset, passName)) {
|
||||
return LoadResult("Failed to read shader artifact passes: " + path);
|
||||
}
|
||||
|
||||
if (isLegacySchema) {
|
||||
ShaderPassArtifactHeaderV1 passHeader = {};
|
||||
if (!ReadShaderArtifactValue(data, offset, passHeader)) {
|
||||
return LoadResult("Failed to read shader artifact passes: " + path);
|
||||
}
|
||||
|
||||
tagCount = passHeader.tagCount;
|
||||
resourceCount = passHeader.resourceCount;
|
||||
variantCount = passHeader.variantCount;
|
||||
} else {
|
||||
ShaderPassArtifactHeader passHeader = {};
|
||||
if (!ReadShaderArtifactValue(data, offset, passHeader)) {
|
||||
return LoadResult("Failed to read shader artifact passes: " + path);
|
||||
}
|
||||
|
||||
tagCount = passHeader.tagCount;
|
||||
resourceCount = passHeader.resourceCount;
|
||||
keywordDeclarationCount = passHeader.keywordDeclarationCount;
|
||||
variantCount = passHeader.variantCount;
|
||||
}
|
||||
|
||||
ShaderPass pass = {};
|
||||
pass.name = passName;
|
||||
shader->AddPass(pass);
|
||||
|
||||
for (Core::uint32 tagIndex = 0; tagIndex < passHeader.tagCount; ++tagIndex) {
|
||||
for (Core::uint32 tagIndex = 0; tagIndex < tagCount; ++tagIndex) {
|
||||
Containers::String tagName;
|
||||
Containers::String tagValue;
|
||||
if (!ReadShaderArtifactString(data, offset, tagName) ||
|
||||
@@ -2499,7 +2565,7 @@ LoadResult LoadShaderArtifact(const Containers::String& path) {
|
||||
shader->SetPassTag(passName, tagName, tagValue);
|
||||
}
|
||||
|
||||
for (Core::uint32 resourceIndex = 0; resourceIndex < passHeader.resourceCount; ++resourceIndex) {
|
||||
for (Core::uint32 resourceIndex = 0; resourceIndex < resourceCount; ++resourceIndex) {
|
||||
ShaderResourceBindingDesc binding = {};
|
||||
ShaderResourceArtifact resourceArtifact;
|
||||
if (!ReadShaderArtifactString(data, offset, binding.name) ||
|
||||
@@ -2514,7 +2580,29 @@ LoadResult LoadShaderArtifact(const Containers::String& path) {
|
||||
shader->AddPassResourceBinding(passName, binding);
|
||||
}
|
||||
|
||||
for (Core::uint32 variantIndex = 0; variantIndex < passHeader.variantCount; ++variantIndex) {
|
||||
for (Core::uint32 declarationIndex = 0; declarationIndex < keywordDeclarationCount; ++declarationIndex) {
|
||||
ShaderKeywordDeclaration declaration = {};
|
||||
ShaderKeywordDeclarationArtifactHeader declarationHeader = {};
|
||||
if (!ReadShaderArtifactValue(data, offset, declarationHeader)) {
|
||||
return LoadResult("Failed to read shader artifact pass keywords: " + path);
|
||||
}
|
||||
|
||||
declaration.type =
|
||||
static_cast<ShaderKeywordDeclarationType>(declarationHeader.declarationType);
|
||||
declaration.options.Reserve(declarationHeader.optionCount);
|
||||
for (Core::uint32 optionIndex = 0; optionIndex < declarationHeader.optionCount; ++optionIndex) {
|
||||
Containers::String option;
|
||||
if (!ReadShaderArtifactString(data, offset, option)) {
|
||||
return LoadResult("Failed to read shader artifact keyword options: " + path);
|
||||
}
|
||||
|
||||
declaration.options.PushBack(option);
|
||||
}
|
||||
|
||||
shader->AddPassKeywordDeclaration(passName, declaration);
|
||||
}
|
||||
|
||||
for (Core::uint32 variantIndex = 0; variantIndex < variantCount; ++variantIndex) {
|
||||
ShaderStageVariant variant = {};
|
||||
ShaderVariantArtifactHeader variantHeader;
|
||||
if (!ReadShaderArtifactValue(data, offset, variantHeader) ||
|
||||
|
||||
Reference in New Issue
Block a user