Close shader authoring pipeline and UsePass dependency tracking

This commit is contained in:
2026-04-07 18:49:37 +08:00
parent 2f9b1696cd
commit 901a6ecc26
12 changed files with 565 additions and 319 deletions

View File

@@ -18,6 +18,11 @@
namespace XCEngine {
namespace Resources {
LoadResult BuildShaderFromIRInternal(
const Containers::String& path,
const ShaderIR& shaderIR,
std::unordered_set<std::string>& activeShaderPathKeys);
namespace {
namespace fs = std::filesystem;
@@ -31,6 +36,25 @@ Containers::String ResolveBuiltinShaderPathByAuthoringName(const Containers::Str
return Containers::String();
}
std::string BuildNormalizedShaderPathKey(const Containers::String& shaderPath) {
if (shaderPath.Empty()) {
return std::string();
}
fs::path normalizedPath(shaderPath.CStr());
if (!normalizedPath.is_absolute()) {
const Containers::String& resourceRoot = ResourceManager::Get().GetResourceRoot();
if (!resourceRoot.Empty()) {
normalizedPath = fs::path(resourceRoot.CStr()) / normalizedPath;
} else {
std::error_code ec;
normalizedPath = fs::current_path(ec) / normalizedPath;
}
}
return normalizedPath.lexically_normal().generic_string();
}
void AddUniqueSearchRoot(
const fs::path& candidate,
std::vector<fs::path>& searchRoots,
@@ -241,12 +265,73 @@ ShaderPass BuildConcretePass(
return shaderPass;
}
bool TryLoadReferencedUsePassShader(
const Containers::String& referencedShaderPath,
std::unordered_set<std::string>& activeShaderPathKeys,
std::unique_ptr<Shader>& outShader,
Containers::String& outError) {
Containers::String authoringShaderPath = referencedShaderPath;
if (IsBuiltinShaderPath(authoringShaderPath) &&
!TryResolveBuiltinShaderAssetPath(authoringShaderPath, authoringShaderPath)) {
outError =
Containers::String("UsePass failed to resolve builtin shader asset: ") +
referencedShaderPath;
return false;
}
const std::string shaderPathKey = BuildNormalizedShaderPathKey(authoringShaderPath);
if (shaderPathKey.empty()) {
outError =
Containers::String("UsePass could not normalize referenced shader path: ") +
referencedShaderPath;
return false;
}
if (activeShaderPathKeys.find(shaderPathKey) != activeShaderPathKeys.end()) {
outError =
Containers::String("UsePass detected a cyclic shader reference: ") +
authoringShaderPath;
return false;
}
Containers::String sourceText;
if (!ReadShaderTextFile(authoringShaderPath, sourceText)) {
outError =
Containers::String("UsePass failed to read referenced shader: ") +
authoringShaderPath;
return false;
}
ShaderIR referencedShaderIR = {};
Containers::String parseError;
if (!ParseShaderAuthoring(authoringShaderPath, sourceText.CStr(), referencedShaderIR, &parseError)) {
outError = parseError;
return false;
}
activeShaderPathKeys.insert(shaderPathKey);
LoadResult referencedShaderResult =
BuildShaderFromIRInternal(authoringShaderPath, referencedShaderIR, activeShaderPathKeys);
activeShaderPathKeys.erase(shaderPathKey);
if (!referencedShaderResult || referencedShaderResult.resource == nullptr) {
outError =
!referencedShaderResult.errorMessage.Empty()
? referencedShaderResult.errorMessage
: Containers::String("UsePass failed to build referenced shader: ") + authoringShaderPath;
return false;
}
outShader.reset(static_cast<Shader*>(referencedShaderResult.resource));
return true;
}
bool TryResolveUsePass(
const Containers::String& currentShaderPath,
const Containers::String& currentShaderName,
const Containers::String& referencedShaderName,
const Containers::String& referencedPassName,
const std::unordered_map<std::string, ShaderPass>& localConcretePasses,
std::unordered_set<std::string>& activeShaderPathKeys,
ShaderPass& outPass,
Containers::String& outError) {
if (referencedShaderName == currentShaderName) {
@@ -273,15 +358,15 @@ bool TryResolveUsePass(
return false;
}
ShaderLoader loader;
LoadResult referencedShaderResult = loader.Load(referencedShaderPath);
if (!referencedShaderResult || referencedShaderResult.resource == nullptr) {
outError =
Containers::String("UsePass failed to load referenced shader: ") + referencedShaderName;
std::unique_ptr<Shader> referencedShader;
if (!TryLoadReferencedUsePassShader(
referencedShaderPath,
activeShaderPathKeys,
referencedShader,
outError)) {
return false;
}
std::unique_ptr<Shader> referencedShader(static_cast<Shader*>(referencedShaderResult.resource));
const ShaderPass* referencedPass = referencedShader->FindPass(referencedPassName);
if (referencedPass == nullptr) {
outError =
@@ -411,9 +496,10 @@ bool ResolveShaderUsePassPath(
outResolvedPath);
}
LoadResult BuildShaderFromIR(
LoadResult BuildShaderFromIRInternal(
const Containers::String& path,
const ShaderIR& shaderIR) {
const ShaderIR& shaderIR,
std::unordered_set<std::string>& activeShaderPathKeys) {
auto shader = std::make_unique<Shader>();
IResource::ConstructParams params;
params.path = path;
@@ -457,6 +543,7 @@ LoadResult BuildShaderFromIR(
pass.usePassShaderName,
pass.usePassPassName,
localConcretePasses,
activeShaderPathKeys,
importedPass,
importError)) {
return LoadResult(importError);
@@ -483,5 +570,17 @@ LoadResult BuildShaderFromIR(
return LoadResult(shader.release());
}
LoadResult BuildShaderFromIR(
const Containers::String& path,
const ShaderIR& shaderIR) {
std::unordered_set<std::string> activeShaderPathKeys;
const std::string shaderPathKey = BuildNormalizedShaderPathKey(path);
if (!shaderPathKey.empty()) {
activeShaderPathKeys.insert(shaderPathKey);
}
return BuildShaderFromIRInternal(path, shaderIR, activeShaderPathKeys);
}
} // namespace Resources
} // namespace XCEngine