Add shader artifact import pipeline
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
#include <XCEngine/Debug/Logger.h>
|
||||
#include <XCEngine/Resources/Material/MaterialLoader.h>
|
||||
#include <XCEngine/Resources/Mesh/MeshLoader.h>
|
||||
#include <XCEngine/Resources/Shader/Shader.h>
|
||||
#include <XCEngine/Resources/Shader/ShaderLoader.h>
|
||||
#include <XCEngine/Resources/Texture/TextureLoader.h>
|
||||
|
||||
#include <algorithm>
|
||||
@@ -406,6 +406,81 @@ bool WriteMaterialArtifactFile(
|
||||
return static_cast<bool>(output);
|
||||
}
|
||||
|
||||
bool WriteShaderArtifactFile(const fs::path& artifactPath, const Shader& shader) {
|
||||
std::ofstream output(artifactPath, std::ios::binary | std::ios::trunc);
|
||||
if (!output.is_open()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ShaderArtifactFileHeader fileHeader;
|
||||
output.write(reinterpret_cast<const char*>(&fileHeader), sizeof(fileHeader));
|
||||
|
||||
WriteString(output, shader.GetName());
|
||||
WriteString(output, NormalizeArtifactPathString(shader.GetPath()));
|
||||
|
||||
ShaderArtifactHeader header;
|
||||
header.propertyCount = static_cast<Core::uint32>(shader.GetProperties().Size());
|
||||
header.passCount = shader.GetPassCount();
|
||||
output.write(reinterpret_cast<const char*>(&header), sizeof(header));
|
||||
|
||||
for (const ShaderPropertyDesc& property : shader.GetProperties()) {
|
||||
WriteString(output, property.name);
|
||||
WriteString(output, property.displayName);
|
||||
WriteString(output, property.defaultValue);
|
||||
WriteString(output, property.semantic);
|
||||
|
||||
ShaderPropertyArtifact propertyArtifact;
|
||||
propertyArtifact.propertyType = static_cast<Core::uint32>(property.type);
|
||||
output.write(reinterpret_cast<const char*>(&propertyArtifact), sizeof(propertyArtifact));
|
||||
}
|
||||
|
||||
for (const ShaderPass& pass : shader.GetPasses()) {
|
||||
WriteString(output, pass.name);
|
||||
|
||||
ShaderPassArtifactHeader passHeader;
|
||||
passHeader.tagCount = static_cast<Core::uint32>(pass.tags.Size());
|
||||
passHeader.resourceCount = static_cast<Core::uint32>(pass.resources.Size());
|
||||
passHeader.variantCount = static_cast<Core::uint32>(pass.variants.Size());
|
||||
output.write(reinterpret_cast<const char*>(&passHeader), sizeof(passHeader));
|
||||
|
||||
for (const ShaderPassTagEntry& tag : pass.tags) {
|
||||
WriteString(output, tag.name);
|
||||
WriteString(output, tag.value);
|
||||
}
|
||||
|
||||
for (const ShaderResourceBindingDesc& resource : pass.resources) {
|
||||
WriteString(output, resource.name);
|
||||
WriteString(output, resource.semantic);
|
||||
|
||||
ShaderResourceArtifact resourceArtifact;
|
||||
resourceArtifact.resourceType = static_cast<Core::uint32>(resource.type);
|
||||
resourceArtifact.set = resource.set;
|
||||
resourceArtifact.binding = resource.binding;
|
||||
output.write(reinterpret_cast<const char*>(&resourceArtifact), sizeof(resourceArtifact));
|
||||
}
|
||||
|
||||
for (const ShaderStageVariant& variant : pass.variants) {
|
||||
ShaderVariantArtifactHeader variantHeader;
|
||||
variantHeader.stage = static_cast<Core::uint32>(variant.stage);
|
||||
variantHeader.language = static_cast<Core::uint32>(variant.language);
|
||||
variantHeader.backend = static_cast<Core::uint32>(variant.backend);
|
||||
variantHeader.compiledBinarySize = static_cast<Core::uint64>(variant.compiledBinary.Size());
|
||||
output.write(reinterpret_cast<const char*>(&variantHeader), sizeof(variantHeader));
|
||||
|
||||
WriteString(output, variant.entryPoint);
|
||||
WriteString(output, variant.profile);
|
||||
WriteString(output, variant.sourceCode);
|
||||
if (!variant.compiledBinary.Empty()) {
|
||||
output.write(
|
||||
reinterpret_cast<const char*>(variant.compiledBinary.Data()),
|
||||
static_cast<std::streamsize>(variant.compiledBinary.Size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return static_cast<bool>(output);
|
||||
}
|
||||
|
||||
bool WriteMeshArtifactFile(const fs::path& artifactPath,
|
||||
const Mesh& mesh,
|
||||
const std::vector<Containers::String>& materialArtifactPaths) {
|
||||
@@ -489,6 +564,7 @@ void AssetDatabase::Initialize(const Containers::String& projectRoot) {
|
||||
LoadSourceAssetDB();
|
||||
LoadArtifactDB();
|
||||
ScanAssets();
|
||||
SaveArtifactDB();
|
||||
}
|
||||
|
||||
void AssetDatabase::Shutdown() {
|
||||
@@ -996,6 +1072,10 @@ Containers::String AssetDatabase::GetImporterNameForPath(const Containers::Strin
|
||||
if (ext == ".obj" || ext == ".fbx" || ext == ".gltf" || ext == ".glb" || ext == ".dae" || ext == ".stl") {
|
||||
return Containers::String("ModelImporter");
|
||||
}
|
||||
if (ext == ".shader" || ext == ".hlsl" || ext == ".glsl" || ext == ".vert" || ext == ".frag" ||
|
||||
ext == ".geom" || ext == ".comp") {
|
||||
return Containers::String("ShaderImporter");
|
||||
}
|
||||
if (ext == ".mat" || ext == ".material" || ext == ".json") {
|
||||
return Containers::String("MaterialImporter");
|
||||
}
|
||||
@@ -1012,6 +1092,9 @@ ResourceType AssetDatabase::GetPrimaryResourceTypeForImporter(const Containers::
|
||||
if (importerName == "MaterialImporter") {
|
||||
return ResourceType::Material;
|
||||
}
|
||||
if (importerName == "ShaderImporter") {
|
||||
return ResourceType::Shader;
|
||||
}
|
||||
return ResourceType::Unknown;
|
||||
}
|
||||
|
||||
@@ -1049,6 +1132,8 @@ bool AssetDatabase::ImportAsset(const SourceAssetRecord& sourceRecord,
|
||||
return ImportMaterialAsset(sourceRecord, outRecord);
|
||||
case ResourceType::Mesh:
|
||||
return ImportModelAsset(sourceRecord, outRecord);
|
||||
case ResourceType::Shader:
|
||||
return ImportShaderAsset(sourceRecord, outRecord);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -1362,6 +1447,59 @@ bool AssetDatabase::ImportModelAsset(const SourceAssetRecord& sourceRecord,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AssetDatabase::ImportShaderAsset(const SourceAssetRecord& sourceRecord,
|
||||
ArtifactRecord& outRecord) {
|
||||
ShaderLoader loader;
|
||||
const Containers::String absolutePath =
|
||||
NormalizePathString(fs::path(m_projectRoot.CStr()) / sourceRecord.relativePath.CStr());
|
||||
LoadResult result = loader.Load(absolutePath);
|
||||
if (!result || result.resource == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Shader* shader = static_cast<Shader*>(result.resource);
|
||||
std::vector<ArtifactDependencyRecord> dependencies;
|
||||
if (!CollectShaderDependencies(sourceRecord, dependencies)) {
|
||||
delete shader;
|
||||
return false;
|
||||
}
|
||||
const Containers::String artifactKey = BuildArtifactKey(sourceRecord, dependencies);
|
||||
const Containers::String artifactDir = BuildArtifactDirectory(artifactKey);
|
||||
const Containers::String mainArtifactPath =
|
||||
NormalizePathString(fs::path(artifactDir.CStr()) / "main.xcshader");
|
||||
|
||||
std::error_code ec;
|
||||
fs::remove_all(fs::path(m_projectRoot.CStr()) / artifactDir.CStr(), ec);
|
||||
ec.clear();
|
||||
fs::create_directories(fs::path(m_projectRoot.CStr()) / artifactDir.CStr(), ec);
|
||||
if (ec) {
|
||||
delete shader;
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool writeOk =
|
||||
WriteShaderArtifactFile(fs::path(m_projectRoot.CStr()) / mainArtifactPath.CStr(), *shader);
|
||||
delete shader;
|
||||
if (!writeOk) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outRecord.artifactKey = artifactKey;
|
||||
outRecord.assetGuid = sourceRecord.guid;
|
||||
outRecord.importerName = sourceRecord.importerName;
|
||||
outRecord.importerVersion = sourceRecord.importerVersion;
|
||||
outRecord.resourceType = ResourceType::Shader;
|
||||
outRecord.artifactDirectory = artifactDir;
|
||||
outRecord.mainArtifactPath = mainArtifactPath;
|
||||
outRecord.sourceHash = sourceRecord.sourceHash;
|
||||
outRecord.metaHash = sourceRecord.metaHash;
|
||||
outRecord.sourceFileSize = sourceRecord.sourceFileSize;
|
||||
outRecord.sourceWriteTime = sourceRecord.sourceWriteTime;
|
||||
outRecord.mainLocalID = kMainAssetLocalID;
|
||||
outRecord.dependencies = std::move(dependencies);
|
||||
return true;
|
||||
}
|
||||
|
||||
Containers::String AssetDatabase::BuildArtifactKey(
|
||||
const AssetDatabase::SourceAssetRecord& sourceRecord,
|
||||
const std::vector<AssetDatabase::ArtifactDependencyRecord>& dependencies) const {
|
||||
@@ -1528,6 +1666,19 @@ bool AssetDatabase::CollectMaterialDependencies(
|
||||
outDependencies.clear();
|
||||
|
||||
std::unordered_set<std::string> seenDependencyPaths;
|
||||
if (material.GetShader() != nullptr) {
|
||||
const Containers::String shaderPath = material.GetShader()->GetPath();
|
||||
if (!shaderPath.Empty() && !HasVirtualPathScheme(shaderPath)) {
|
||||
ArtifactDependencyRecord dependency;
|
||||
if (CaptureDependencyRecord(ResolveDependencyPath(shaderPath), dependency)) {
|
||||
const std::string dependencyKey = ToStdString(dependency.path);
|
||||
if (seenDependencyPaths.insert(dependencyKey).second) {
|
||||
outDependencies.push_back(dependency);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Core::uint32 bindingIndex = 0; bindingIndex < material.GetTextureBindingCount(); ++bindingIndex) {
|
||||
const Containers::String texturePath = material.GetTextureBindingPath(bindingIndex);
|
||||
if (texturePath.Empty()) {
|
||||
@@ -1548,6 +1699,39 @@ bool AssetDatabase::CollectMaterialDependencies(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AssetDatabase::CollectShaderDependencies(
|
||||
const SourceAssetRecord& sourceRecord,
|
||||
std::vector<AssetDatabase::ArtifactDependencyRecord>& outDependencies) const {
|
||||
outDependencies.clear();
|
||||
|
||||
ShaderLoader loader;
|
||||
const Containers::String absolutePath =
|
||||
NormalizePathString(fs::path(m_projectRoot.CStr()) / sourceRecord.relativePath.CStr());
|
||||
Containers::Array<Containers::String> dependencyPaths;
|
||||
if (!loader.CollectSourceDependencies(absolutePath, dependencyPaths)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unordered_set<std::string> seenDependencyPaths;
|
||||
for (const Containers::String& dependencyPath : dependencyPaths) {
|
||||
if (dependencyPath.Empty() || HasVirtualPathScheme(dependencyPath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ArtifactDependencyRecord dependency;
|
||||
if (!CaptureDependencyRecord(ResolveDependencyPath(dependencyPath), dependency)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string dependencyKey = ToStdString(dependency.path);
|
||||
if (seenDependencyPaths.insert(dependencyKey).second) {
|
||||
outDependencies.push_back(dependency);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Containers::String AssetDatabase::BuildArtifactDirectory(const Containers::String& artifactKey) const {
|
||||
if (artifactKey.Length() < 2) {
|
||||
return Containers::String("Library/Artifacts/00/invalid");
|
||||
|
||||
Reference in New Issue
Block a user