rendering: add keyword-aware shader variant selection

This commit is contained in:
2026-04-06 19:37:01 +08:00
parent a8b4da16a3
commit 261dd44fd5
26 changed files with 469 additions and 76 deletions

View File

@@ -144,6 +144,88 @@ TEST(Shader, FindsBackendSpecificVariantAndFallsBackToGeneric) {
EXPECT_EQ(openglVariant->sourceCode, "generic fragment");
}
TEST(Shader, FindsMostSpecificKeywordVariantAndPrefersExactBackend) {
Shader shader;
ShaderStageVariant baseFragment = {};
baseFragment.stage = ShaderType::Fragment;
baseFragment.language = ShaderLanguage::GLSL;
baseFragment.backend = ShaderBackend::Generic;
baseFragment.sourceCode = "generic base";
shader.AddPassVariant("ForwardLit", baseFragment);
ShaderStageVariant genericKeywordFragment = {};
genericKeywordFragment.stage = ShaderType::Fragment;
genericKeywordFragment.language = ShaderLanguage::GLSL;
genericKeywordFragment.backend = ShaderBackend::Generic;
genericKeywordFragment.requiredKeywords.enabledKeywords.PushBack("XC_DEBUG");
genericKeywordFragment.requiredKeywords.enabledKeywords.PushBack("XC_ALPHA_TEST");
genericKeywordFragment.requiredKeywords.enabledKeywords.PushBack("XC_DEBUG");
genericKeywordFragment.sourceCode = "generic keyword";
shader.AddPassVariant("ForwardLit", genericKeywordFragment);
ShaderStageVariant d3d12KeywordFragment = {};
d3d12KeywordFragment.stage = ShaderType::Fragment;
d3d12KeywordFragment.language = ShaderLanguage::HLSL;
d3d12KeywordFragment.backend = ShaderBackend::D3D12;
d3d12KeywordFragment.requiredKeywords.enabledKeywords.PushBack("XC_ALPHA_TEST");
d3d12KeywordFragment.sourceCode = "d3d12 keyword";
shader.AddPassVariant("ForwardLit", d3d12KeywordFragment);
ShaderKeywordSet enabledKeywords = {};
enabledKeywords.enabledKeywords.PushBack("XC_ALPHA_TEST");
enabledKeywords.enabledKeywords.PushBack("XC_DEBUG");
const ShaderStageVariant* d3d12Variant =
shader.FindVariant(
"ForwardLit",
ShaderType::Fragment,
ShaderBackend::D3D12,
enabledKeywords);
ASSERT_NE(d3d12Variant, nullptr);
EXPECT_EQ(d3d12Variant->sourceCode, "d3d12 keyword");
const ShaderStageVariant* openglVariant =
shader.FindVariant(
"ForwardLit",
ShaderType::Fragment,
ShaderBackend::OpenGL,
enabledKeywords);
ASSERT_NE(openglVariant, nullptr);
EXPECT_EQ(openglVariant->sourceCode, "generic keyword");
ASSERT_EQ(openglVariant->requiredKeywords.enabledKeywords.Size(), 2u);
EXPECT_EQ(openglVariant->requiredKeywords.enabledKeywords[0], "XC_ALPHA_TEST");
EXPECT_EQ(openglVariant->requiredKeywords.enabledKeywords[1], "XC_DEBUG");
}
TEST(Shader, RejectsVariantWhenRequiredKeywordsAreMissing) {
Shader shader;
ShaderStageVariant keywordFragment = {};
keywordFragment.stage = ShaderType::Fragment;
keywordFragment.language = ShaderLanguage::GLSL;
keywordFragment.backend = ShaderBackend::OpenGL;
keywordFragment.requiredKeywords.enabledKeywords.PushBack("XC_CLIP");
keywordFragment.sourceCode = "clip fragment";
shader.AddPassVariant("ForwardLit", keywordFragment);
EXPECT_EQ(
shader.FindVariant("ForwardLit", ShaderType::Fragment, ShaderBackend::OpenGL),
nullptr);
ShaderKeywordSet enabledKeywords = {};
enabledKeywords.enabledKeywords.PushBack("XC_CLIP");
const ShaderStageVariant* matchedVariant =
shader.FindVariant(
"ForwardLit",
ShaderType::Fragment,
ShaderBackend::OpenGL,
enabledKeywords);
ASSERT_NE(matchedVariant, nullptr);
EXPECT_EQ(matchedVariant->sourceCode, "clip fragment");
}
TEST(Shader, StoresPerPassTags) {
Shader shader;
shader.SetPassTag("ForwardLit", "LightMode", "ForwardBase");