234 lines
8.3 KiB
C++
234 lines
8.3 KiB
C++
#include "ShaderAuthoringLoader.h"
|
|
|
|
#include "../ShaderAuthoringParser.h"
|
|
#include "../ShaderSourceUtils.h"
|
|
#include "ShaderAuthoringInternal.h"
|
|
#include "ShaderFileUtils.h"
|
|
#include "ShaderRuntimeBuildUtils.h"
|
|
|
|
#include <XCEngine/Resources/BuiltinResources.h>
|
|
|
|
#include <filesystem>
|
|
#include <unordered_set>
|
|
|
|
namespace XCEngine {
|
|
namespace Resources {
|
|
|
|
namespace {
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
bool CollectShaderAuthoringDependencyPathsRecursive(
|
|
const Containers::String& path,
|
|
const std::string& sourceText,
|
|
std::unordered_set<std::string>& seenShaderPaths,
|
|
std::unordered_set<std::string>& seenDependencyPaths,
|
|
Containers::Array<Containers::String>& outDependencies,
|
|
Containers::String* outError) {
|
|
const fs::path normalizedShaderPath = fs::path(path.CStr()).lexically_normal();
|
|
const std::string shaderKey = normalizedShaderPath.generic_string();
|
|
if (!shaderKey.empty() && !seenShaderPaths.insert(shaderKey).second) {
|
|
return true;
|
|
}
|
|
|
|
ShaderIR shaderIR = {};
|
|
Containers::String parseError;
|
|
if (!ParseShaderAuthoring(path, sourceText, shaderIR, &parseError)) {
|
|
if (outError != nullptr) {
|
|
*outError = parseError;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if (!::XCEngine::Resources::Internal::CollectQuotedIncludeDependencyPaths(
|
|
path,
|
|
shaderIR.sharedProgramSource,
|
|
seenDependencyPaths,
|
|
outDependencies,
|
|
outError)) {
|
|
return false;
|
|
}
|
|
for (const ShaderSubShaderIR& subShader : shaderIR.subShaders) {
|
|
if (!::XCEngine::Resources::Internal::CollectQuotedIncludeDependencyPaths(
|
|
path,
|
|
subShader.sharedProgramSource,
|
|
seenDependencyPaths,
|
|
outDependencies,
|
|
outError)) {
|
|
return false;
|
|
}
|
|
for (const ShaderPassIR& pass : subShader.passes) {
|
|
if (!pass.isUsePass) {
|
|
if (!::XCEngine::Resources::Internal::CollectQuotedIncludeDependencyPaths(
|
|
path,
|
|
pass.sharedProgramSource,
|
|
seenDependencyPaths,
|
|
outDependencies,
|
|
outError) ||
|
|
!::XCEngine::Resources::Internal::CollectQuotedIncludeDependencyPaths(
|
|
path,
|
|
pass.programSource,
|
|
seenDependencyPaths,
|
|
outDependencies,
|
|
outError)) {
|
|
return false;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
Containers::String resolvedUsePassPath;
|
|
if (!ResolveShaderUsePassPath(
|
|
path,
|
|
shaderIR.name,
|
|
pass.usePassShaderName,
|
|
resolvedUsePassPath)) {
|
|
Containers::String builtinShaderPath;
|
|
if (!TryGetBuiltinShaderPathByShaderName(pass.usePassShaderName, builtinShaderPath)) {
|
|
if (outError != nullptr) {
|
|
*outError =
|
|
Containers::String("Failed to resolve shader UsePass: source=") +
|
|
path +
|
|
", requested=" +
|
|
pass.usePassShaderName;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if (!builtinShaderPath.Empty() &&
|
|
seenDependencyPaths.insert(ToStdString(builtinShaderPath)).second) {
|
|
outDependencies.PushBack(builtinShaderPath);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (resolvedUsePassPath.Empty() || resolvedUsePassPath == path) {
|
|
continue;
|
|
}
|
|
|
|
if (IsBuiltinShaderPath(resolvedUsePassPath)) {
|
|
Containers::String builtinAssetPath;
|
|
if (!TryResolveBuiltinShaderAssetPath(resolvedUsePassPath, builtinAssetPath)) {
|
|
if (outError != nullptr) {
|
|
*outError =
|
|
Containers::String("Failed to resolve builtin shader UsePass asset: source=") +
|
|
path +
|
|
", requested=" +
|
|
resolvedUsePassPath;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
const fs::path normalizedBuiltinAssetPath =
|
|
fs::path(builtinAssetPath.CStr()).lexically_normal();
|
|
const Containers::String normalizedBuiltinDependency =
|
|
normalizedBuiltinAssetPath.generic_string().c_str();
|
|
if (!normalizedBuiltinDependency.Empty() &&
|
|
seenDependencyPaths.insert(ToStdString(normalizedBuiltinDependency)).second) {
|
|
outDependencies.PushBack(normalizedBuiltinDependency);
|
|
}
|
|
|
|
Containers::String referencedSourceText;
|
|
if (!ReadShaderTextFile(builtinAssetPath, referencedSourceText)) {
|
|
if (outError != nullptr) {
|
|
*outError =
|
|
Containers::String("Failed to read shader UsePass source: source=") +
|
|
path +
|
|
", requested=" +
|
|
builtinAssetPath;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if (!CollectShaderAuthoringDependencyPathsRecursive(
|
|
builtinAssetPath,
|
|
referencedSourceText.CStr(),
|
|
seenShaderPaths,
|
|
seenDependencyPaths,
|
|
outDependencies,
|
|
outError)) {
|
|
return false;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
const fs::path normalizedDependencyPath =
|
|
fs::path(resolvedUsePassPath.CStr()).lexically_normal();
|
|
const Containers::String normalizedDependency =
|
|
normalizedDependencyPath.generic_string().c_str();
|
|
if (!normalizedDependency.Empty() &&
|
|
seenDependencyPaths.insert(ToStdString(normalizedDependency)).second) {
|
|
outDependencies.PushBack(normalizedDependency);
|
|
}
|
|
|
|
Containers::String referencedSourceText;
|
|
if (!ReadShaderTextFile(resolvedUsePassPath, referencedSourceText)) {
|
|
if (outError != nullptr) {
|
|
*outError =
|
|
Containers::String("Failed to read shader UsePass source: source=") +
|
|
path +
|
|
", requested=" +
|
|
resolvedUsePassPath;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if (!CollectShaderAuthoringDependencyPathsRecursive(
|
|
resolvedUsePassPath,
|
|
referencedSourceText.CStr(),
|
|
seenShaderPaths,
|
|
seenDependencyPaths,
|
|
outDependencies,
|
|
outError)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
bool CollectShaderAuthoringDependencyPaths(
|
|
const Containers::String& path,
|
|
const std::string& sourceText,
|
|
Containers::Array<Containers::String>& outDependencies) {
|
|
return CollectShaderAuthoringDependencyPaths(path, sourceText, outDependencies, nullptr);
|
|
}
|
|
|
|
bool CollectShaderAuthoringDependencyPaths(
|
|
const Containers::String& path,
|
|
const std::string& sourceText,
|
|
Containers::Array<Containers::String>& outDependencies,
|
|
Containers::String* outError) {
|
|
outDependencies.Clear();
|
|
if (outError != nullptr) {
|
|
outError->Clear();
|
|
}
|
|
|
|
std::unordered_set<std::string> seenShaderPaths;
|
|
std::unordered_set<std::string> seenDependencyPaths;
|
|
return CollectShaderAuthoringDependencyPathsRecursive(
|
|
path,
|
|
sourceText,
|
|
seenShaderPaths,
|
|
seenDependencyPaths,
|
|
outDependencies,
|
|
outError);
|
|
}
|
|
|
|
LoadResult LoadShaderAuthoring(
|
|
const Containers::String& path,
|
|
const std::string& sourceText) {
|
|
ShaderIR shaderIR = {};
|
|
Containers::String parseError;
|
|
if (!ParseShaderAuthoring(path, sourceText, shaderIR, &parseError)) {
|
|
return LoadResult(parseError);
|
|
}
|
|
|
|
return BuildShaderFromIR(path, shaderIR);
|
|
}
|
|
|
|
} // namespace Resources
|
|
} // namespace XCEngine
|