Remove legacy shader pass and artifact fallbacks

This commit is contained in:
2026-04-08 04:59:49 +08:00
parent 2c1c815072
commit efdd6bd68f
9 changed files with 186 additions and 273 deletions

View File

@@ -447,9 +447,15 @@ TEST(RenderSceneExtractor_Test, FallsBackToEmbeddedMeshMaterialsWhenRendererHasN
delete mesh;
}
TEST(RenderMaterialUtility_Test, MaterialsWithoutShaderMetadataUseImplicitForwardFallback) {
TEST(RenderMaterialUtility_Test, NullMaterialsDoNotMatchBuiltinSurfacePasses) {
EXPECT_FALSE(MatchesBuiltinPass(nullptr, BuiltinMaterialPass::ForwardLit));
EXPECT_FALSE(MatchesBuiltinPass(nullptr, BuiltinMaterialPass::Unlit));
}
TEST(RenderMaterialUtility_Test, MaterialsWithoutShaderMetadataDoNotMatchBuiltinSurfacePasses) {
Material noMetadataMaterial;
EXPECT_TRUE(MatchesBuiltinPass(&noMetadataMaterial, BuiltinMaterialPass::ForwardLit));
EXPECT_FALSE(MatchesBuiltinPass(&noMetadataMaterial, BuiltinMaterialPass::ForwardLit));
EXPECT_FALSE(MatchesBuiltinPass(&noMetadataMaterial, BuiltinMaterialPass::Unlit));
}
TEST(RenderMaterialUtility_Test, ShaderPassMetadataSupportsUnlitDepthAndObjectId) {
@@ -527,7 +533,7 @@ TEST(RenderMaterialUtility_Test, ShaderMetadataOverridesConflictingMaterialTags)
EXPECT_FALSE(MatchesBuiltinPass(&material, BuiltinMaterialPass::DepthOnly));
}
TEST(RenderMaterialUtility_Test, MaterialTagsDoNotOverrideImplicitForwardFallbackWithoutShaderMetadata) {
TEST(RenderMaterialUtility_Test, MaterialTagsDoNotOverrideMissingShaderMetadata) {
Material material;
auto* shader = new Shader();
@@ -538,11 +544,11 @@ TEST(RenderMaterialUtility_Test, MaterialTagsDoNotOverrideImplicitForwardFallbac
material.SetShader(ResourceHandle<Shader>(shader));
material.SetTag("LightMode", "ShadowCaster");
EXPECT_TRUE(MatchesBuiltinPass(&material, BuiltinMaterialPass::ForwardLit));
EXPECT_FALSE(MatchesBuiltinPass(&material, BuiltinMaterialPass::ForwardLit));
EXPECT_FALSE(MatchesBuiltinPass(&material, BuiltinMaterialPass::ShadowCaster));
}
TEST(RenderMaterialUtility_Test, ShadersWithoutBuiltinMetadataKeepImplicitForwardFallback) {
TEST(RenderMaterialUtility_Test, ShadersWithoutBuiltinMetadataDoNotMatchBuiltinSurfacePasses) {
Material material;
auto* shader = new Shader();
@@ -552,7 +558,7 @@ TEST(RenderMaterialUtility_Test, ShadersWithoutBuiltinMetadataKeepImplicitForwar
material.SetShader(ResourceHandle<Shader>(shader));
EXPECT_TRUE(MatchesBuiltinPass(&material, BuiltinMaterialPass::ForwardLit));
EXPECT_FALSE(MatchesBuiltinPass(&material, BuiltinMaterialPass::ForwardLit));
EXPECT_FALSE(MatchesBuiltinPass(&material, BuiltinMaterialPass::Unlit));
}

View File

@@ -1,5 +1,6 @@
#include <gtest/gtest.h>
#include <XCEngine/Core/Asset/AssetDatabase.h>
#include <XCEngine/Core/Asset/ArtifactFormats.h>
#include <XCEngine/Resources/BuiltinResources.h>
#include <XCEngine/Core/Asset/ResourceManager.h>
#include <XCEngine/Resources/Shader/ShaderLoader.h>
@@ -7,6 +8,7 @@
#include <XCEngine/Core/Containers/Array.h>
#include <chrono>
#include <cstring>
#include <cstdio>
#include <filesystem>
#include <fstream>
@@ -24,6 +26,15 @@ void WriteTextFile(const std::filesystem::path& path, const std::string& content
ASSERT_TRUE(static_cast<bool>(output));
}
ShaderArtifactFileHeader ReadShaderArtifactFileHeader(const std::filesystem::path& path) {
ShaderArtifactFileHeader header = {};
std::ifstream input(path, std::ios::binary);
EXPECT_TRUE(input.is_open());
input.read(reinterpret_cast<char*>(&header), sizeof(header));
EXPECT_TRUE(static_cast<bool>(input));
return header;
}
const ShaderPassTagEntry* FindPassTag(const ShaderPass* pass, const char* name) {
if (pass == nullptr || name == nullptr) {
return nullptr;
@@ -71,6 +82,34 @@ TEST(ShaderLoader, LoadInvalidPath) {
EXPECT_FALSE(result);
}
TEST(ShaderLoader, RejectsLegacyShaderArtifactSchemaHeaders) {
namespace fs = std::filesystem;
const fs::path artifactPath = fs::temp_directory_path() / "xc_shader_loader_legacy_schema.xcshader";
fs::remove(artifactPath);
ShaderArtifactFileHeader header = {};
std::memcpy(header.magic, "XCSHD04", 7);
header.magic[7] = '\0';
header.schemaVersion = 4u;
{
std::ofstream output(artifactPath, std::ios::binary | std::ios::trunc);
ASSERT_TRUE(output.is_open());
output.write(reinterpret_cast<const char*>(&header), sizeof(header));
ASSERT_TRUE(static_cast<bool>(output));
}
ShaderLoader loader;
LoadResult result = loader.Load(artifactPath.string().c_str());
EXPECT_FALSE(result);
EXPECT_NE(
std::string(result.errorMessage.CStr()).find("Invalid shader artifact header"),
std::string::npos);
fs::remove(artifactPath);
}
TEST(ShaderLoader, RejectsLegacySingleStageShaderSourceFiles) {
namespace fs = std::filesystem;
@@ -1663,6 +1702,80 @@ TEST(ShaderLoader, AssetDatabaseCreatesShaderArtifactFromAuthoringAndLoaderReads
fs::remove_all(projectRoot);
}
TEST(ShaderLoader, AssetDatabaseReimportsLegacyShaderArtifactHeaderBeforeLoad) {
namespace fs = std::filesystem;
const fs::path projectRoot = fs::temp_directory_path() / "xc_shader_legacy_artifact_reimport";
const fs::path shaderDir = projectRoot / "Assets" / "Shaders";
const fs::path shaderPath = shaderDir / "lit.shader";
fs::remove_all(projectRoot);
fs::create_directories(shaderDir);
WriteTextFile(
shaderPath,
R"(Shader "ArtifactSchemaReimportShader"
{
SubShader
{
Pass
{
Name "ForwardLit"
Tags { "LightMode" = "ForwardBase" }
HLSLPROGRAM
#pragma vertex MainVS
#pragma fragment MainPS
float4 MainVS() : SV_POSITION
{
return 0;
}
float4 MainPS() : SV_TARGET
{
return 1;
}
ENDHLSL
}
}
}
)");
AssetDatabase database;
database.Initialize(projectRoot.string().c_str());
AssetDatabase::ResolvedAsset firstResolve;
ASSERT_TRUE(database.EnsureArtifact("Assets/Shaders/lit.shader", ResourceType::Shader, firstResolve));
ASSERT_TRUE(firstResolve.artifactReady);
ASSERT_TRUE(fs::exists(firstResolve.artifactMainPath.CStr()));
ShaderArtifactFileHeader legacyHeader = ReadShaderArtifactFileHeader(firstResolve.artifactMainPath.CStr());
std::memcpy(legacyHeader.magic, "XCSHD04", 7);
legacyHeader.magic[7] = '\0';
legacyHeader.schemaVersion = 4u;
{
std::fstream output(firstResolve.artifactMainPath.CStr(), std::ios::binary | std::ios::in | std::ios::out);
ASSERT_TRUE(output.is_open());
output.write(reinterpret_cast<const char*>(&legacyHeader), sizeof(legacyHeader));
ASSERT_TRUE(static_cast<bool>(output));
}
AssetDatabase::ResolvedAsset secondResolve;
ASSERT_TRUE(database.EnsureArtifact("Assets/Shaders/lit.shader", ResourceType::Shader, secondResolve));
EXPECT_TRUE(secondResolve.imported);
ASSERT_TRUE(secondResolve.artifactReady);
const ShaderArtifactFileHeader currentHeader = ReadShaderArtifactFileHeader(secondResolve.artifactMainPath.CStr());
EXPECT_EQ(std::string(currentHeader.magic, currentHeader.magic + 7), std::string("XCSHD05"));
EXPECT_EQ(currentHeader.schemaVersion, kShaderArtifactSchemaVersion);
ShaderLoader loader;
LoadResult result = loader.Load(secondResolve.artifactMainPath.CStr());
ASSERT_TRUE(result);
ASSERT_NE(result.resource, nullptr);
delete static_cast<Shader*>(result.resource);
database.Shutdown();
fs::remove_all(projectRoot);
}
TEST(ShaderLoader, AssetDatabaseCreatesShaderArtifactFromAuthoringPreservesKeywords) {
namespace fs = std::filesystem;