Close shader authoring pipeline and UsePass dependency tracking
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user