rendering: formalize shader keyword metadata contract

This commit is contained in:
2026-04-06 18:55:26 +08:00
parent 7acc397714
commit a8b4da16a3
16 changed files with 795 additions and 16 deletions

View File

@@ -461,6 +461,17 @@ TEST(ShaderLoader, LoadUnityStyleSingleSourceShaderAuthoringBuildsGenericHlslVar
EXPECT_EQ(pass->tags[1].name, "LightMode");
EXPECT_EQ(pass->tags[1].value, "ForwardLit");
EXPECT_TRUE(pass->resources.Empty());
ASSERT_EQ(pass->keywordDeclarations.Size(), 2u);
EXPECT_EQ(pass->keywordDeclarations[0].type, ShaderKeywordDeclarationType::MultiCompile);
ASSERT_EQ(pass->keywordDeclarations[0].options.Size(), 2u);
EXPECT_EQ(pass->keywordDeclarations[0].options[0], "_");
EXPECT_EQ(pass->keywordDeclarations[0].options[1], "XC_MAIN_LIGHT_SHADOWS");
EXPECT_EQ(pass->keywordDeclarations[1].type, ShaderKeywordDeclarationType::ShaderFeatureLocal);
ASSERT_EQ(pass->keywordDeclarations[1].options.Size(), 2u);
EXPECT_EQ(pass->keywordDeclarations[1].options[1], "XC_ALPHA_TEST");
EXPECT_TRUE(shader->PassDeclaresKeyword("ForwardLit", "XC_MAIN_LIGHT_SHADOWS"));
EXPECT_TRUE(shader->DeclaresKeyword("XC_ALPHA_TEST"));
EXPECT_FALSE(shader->DeclaresKeyword("_"));
ASSERT_EQ(pass->variants.Size(), 2u);
const ShaderStageVariant* vertexVariant =
@@ -526,7 +537,13 @@ TEST(ShaderLoader, LoadUnityStyleSingleSourceShaderAuthoringRejectsBackendPragma
ShaderLoader loader;
LoadResult result = loader.Load(shaderPath.string().c_str());
EXPECT_FALSE(result);
EXPECT_NE(std::string(result.errorMessage.CStr()).find("must not use #pragma backend"), std::string::npos);
const std::string errorMessage = result.errorMessage.CStr();
EXPECT_FALSE(errorMessage.empty());
EXPECT_EQ(errorMessage.find("Failed to read shader authoring"), std::string::npos);
EXPECT_TRUE(
errorMessage.find("backend") != std::string::npos ||
errorMessage.find("unsupported pragma") != std::string::npos);
fs::remove_all(shaderRoot);
}
@@ -707,6 +724,68 @@ TEST(ShaderLoader, AssetDatabaseCreatesShaderArtifactAndLoaderReadsItBack) {
fs::remove_all(projectRoot);
}
TEST(ShaderLoader, AssetDatabaseCreatesShaderArtifactFromSingleSourceAuthoringPreservesKeywords) {
namespace fs = std::filesystem;
const fs::path projectRoot = fs::temp_directory_path() / "xc_shader_single_source_artifact_keywords";
const fs::path shaderDir = projectRoot / "Assets" / "Shaders";
const fs::path shaderPath = shaderDir / "single_source.shader";
fs::remove_all(projectRoot);
fs::create_directories(shaderDir);
WriteTextFile(
shaderPath,
R"(Shader "ArtifactSingleSourceKeywords"
{
SubShader
{
Pass
{
Name "ForwardLit"
HLSLPROGRAM
#pragma target 4.5
#pragma vertex Vert
#pragma fragment Frag
#pragma multi_compile _ XC_MAIN_LIGHT_SHADOWS
#pragma shader_feature_local _ XC_ALPHA_TEST
float4 Vert() : SV_POSITION { return 0; }
float4 Frag() : SV_TARGET { return float4(1.0, 0.0, 0.0, 1.0); }
ENDHLSL
}
}
}
)");
AssetDatabase database;
database.Initialize(projectRoot.string().c_str());
AssetDatabase::ResolvedAsset resolvedAsset;
ASSERT_TRUE(database.EnsureArtifact("Assets/Shaders/single_source.shader", ResourceType::Shader, resolvedAsset));
ASSERT_TRUE(resolvedAsset.artifactReady);
EXPECT_TRUE(fs::exists(resolvedAsset.artifactMainPath.CStr()));
ShaderLoader loader;
LoadResult result = loader.Load(resolvedAsset.artifactMainPath.CStr());
ASSERT_TRUE(result);
ASSERT_NE(result.resource, nullptr);
auto* shader = static_cast<Shader*>(result.resource);
ASSERT_NE(shader, nullptr);
ASSERT_TRUE(shader->DeclaresKeyword("XC_MAIN_LIGHT_SHADOWS"));
ASSERT_TRUE(shader->DeclaresKeyword("XC_ALPHA_TEST"));
const ShaderPass* pass = shader->FindPass("ForwardLit");
ASSERT_NE(pass, nullptr);
ASSERT_EQ(pass->keywordDeclarations.Size(), 2u);
EXPECT_EQ(pass->keywordDeclarations[0].type, ShaderKeywordDeclarationType::MultiCompile);
EXPECT_EQ(pass->keywordDeclarations[1].type, ShaderKeywordDeclarationType::ShaderFeatureLocal);
delete shader;
database.Shutdown();
fs::remove_all(projectRoot);
}
TEST(ShaderLoader, AssetDatabaseCreatesShaderArtifactFromUnityLikeAuthoringAndTracksStageDependencies) {
namespace fs = std::filesystem;
using namespace std::chrono_literals;