refactor: 解耦重构——还清四处架构债(对齐 UE/Unity 分层)

- SceneRenderer:场景→渲染数据翻译层(UE FSceneRenderer / Unity CullingResults
  模式),收口相机/灯光/光空间矩阵/双视图剔除,Renderer 只编排
- pass 对象化(Unity ScriptableRenderPass 模式):8 个 pass lambda 拆为
  Passes::{Shadow,Forward,Bloom,Tonemap,ImGui,Present},BuildGraph 超级函数消失;
  SceneGpu/FullscreenGpu 承接共享装配
- 中性 AssetRef(Core 层):ECS 组件不再依赖 Assets 模块(Unity InstanceID 思路)
- IAssetUploader 接口:AssetManager 不感知 Vulkan 具体类,上传服务由渲染层
  VulkanAssetUploader 提供
- Renderer 公共 API 不变(App 层零改动),编译零错误 validation 零警告
This commit is contained in:
2026-09-23 12:02:49 +08:00
parent 91880d88fe
commit 718a658f5d
30 changed files with 1777 additions and 1054 deletions
@@ -1,37 +0,0 @@
//
// Created by atdunbg on 2026/9/22.
//
// AssetHandle:资产句柄 = (池内索引, 生成号),与 Entity/RG 句柄同一哲学。
//
// 组件、场景数据只存句柄;所有权归 AssetManager。
// 悬空句柄(generation 不匹配)会被 Get 显式拒绝,杜绝 use-after-free。
//
#ifndef HELLOVULKAN_ASSETHANDLE_H
#define HELLOVULKAN_ASSETHANDLE_H
#include <Engine/Core/Types.h>
// Model 前向声明(句柄不依赖完整类型)
namespace Engine { class Model; }
namespace Engine::Assets {
inline constexpr u32 kInvalidAssetIndex = 0xFFFFFFFF;
template<typename T>
struct AssetHandle {
u32 index = kInvalidAssetIndex;
u32 generation = 0;
bool Valid() const { return index != kInvalidAssetIndex; }
explicit operator bool() const { return Valid(); }
bool operator==(const AssetHandle& o) const = default;
};
// 常用别名
using ModelHandle = AssetHandle<Engine::Model>;
} // namespace Engine::Assets
#endif //HELLOVULKAN_ASSETHANDLE_H
+19 -33
View File
@@ -3,14 +3,9 @@
//
// AssetManager:引擎资产层。
//
// 职责划分(对照 Renderer):
// - 资产层:路径 → 解析/加载 → 缓存去重 → 句柄分发 + 生命周期管理
// - 渲染层:拿已解析资产创建/绑定 GPU 资源
//
// Model 的构造仍需要 GPU 上下文(buffer/image upload),这是现阶段的
// 折中:资产层"使用"GPU 层的接口,但 Renderer 不再知道磁盘和缓存。
// 后续演进:把 Model 拆成 CPU 解析数据 + GPU 上传两段,实现真正的
// 异步加载(IO 线程解析 → 主线程/上传队列提交),本文件结构已为此留好位置。
// 职责:路径 → 解析/加载 → 缓存去重 → 句柄分发 + 生命周期管理。
// GPU 创建不在这里:经 IAssetUploader 接口(渲染层提供实现)完成,
// 本类不感知 Vulkan——依赖方向 Assets → 接口,实现由组合根注入。
//
// 组件存句柄不存指针的理由:
// shared_ptr 会引入共享所有权 → 原子引用计数(swap-remove 拷贝时)
@@ -23,7 +18,8 @@
#include <Engine/Core/Types.h>
#include <Engine/Core/Log.h>
#include <Engine/Assets/AssetHandle.h>
#include <Engine/Core/AssetRef.h>
#include <Engine/Assets/IAssetUploader.h>
#include <Engine/Renderer/Model.h>
#include <functional>
@@ -32,11 +28,6 @@
#include <vector>
namespace Engine {
class Device;
class MemoryAllocator;
class DescriptorManager;
namespace Assets {
// ---------- 通用资产缓存(不感知 Vulkan / 磁盘细节由 loader 决定) ----------
@@ -48,7 +39,7 @@ namespace Engine {
using LoaderFn = std::function<Scope<T>(const std::string&)>;
// 加载(带路径去重)。失败返回无效句柄。
AssetHandle<T> Load(const std::string& path, const LoaderFn& loader)
AssetRef<T> Load(const std::string& path, const LoaderFn& loader)
{
if (auto it = m_ByPath.find(path); it != m_ByPath.end()) {
return it->second;
@@ -60,7 +51,7 @@ namespace Engine {
return {};
}
AssetHandle<T> h;
AssetRef<T> h;
if (!m_Free.empty()) {
h.index = m_Free.back();
m_Free.pop_back();
@@ -77,7 +68,7 @@ namespace Engine {
}
// 句柄 → 资产指针。悬空句柄 FATAL(bug 信号);已卸载返回 nullptr。
T* Get(AssetHandle<T> h) const
T* Get(AssetRef<T> h) const
{
if (!h.Valid() || h.index >= m_Entries.size()) {
ENGINE_FATAL("AssetCache::Get: invalid handle (index={}, gen={})",
@@ -94,7 +85,7 @@ namespace Engine {
// 卸载:句柄即刻失效(generation 递增),路径缓存清除。
// 注意:GPU 侧何时安全释放由上层(Renderer fence)保证——
// 本类只管所有权,不管 GPU 生命周期。
void Unload(AssetHandle<T> h)
void Unload(AssetRef<T> h)
{
if (!h.Valid() || h.index >= m_Entries.size()) return;
@@ -109,7 +100,7 @@ namespace Engine {
m_Free.push_back(h.index);
}
const std::string& Path(AssetHandle<T> h) const
const std::string& Path(AssetRef<T> h) const
{
static const std::string kEmpty;
if (!h.Valid() || h.index >= m_Entries.size()) return kEmpty;
@@ -132,29 +123,27 @@ namespace Engine {
std::vector<Entry> m_Entries;
std::vector<u32> m_Free;
std::unordered_map<std::string, AssetHandle<T>> m_ByPath;
std::unordered_map<std::string, AssetRef<T>> m_ByPath;
};
// ---------- AssetManager:全引擎资产入口 ----------
// (ModelHandle 别名来自 AssetHandle.h)
class AssetManager {
public:
// GPU 上下文由组合根(Application)在 Renderer 装配完成后注入
AssetManager(Device& device, MemoryAllocator& allocator,
DescriptorManager& descriptors,
vk::DescriptorSetLayout textureLayout);
// 上传服务由组合根(Application)注入:渲染层实现接口,
// 资产层不感知 Vulkan 具体类
explicit AssetManager(IAssetUploader& uploader);
~AssetManager() = default;
AssetManager(const AssetManager&) = delete;
AssetManager& operator=(const AssetManager&) = delete;
ModelHandle LoadModel(const std::string& path);
Model* GetModel(ModelHandle h) const { return m_Models.Get(h); }
void UnloadModel(ModelHandle h) { m_Models.Unload(h); }
ModelRef LoadModel(const std::string& path);
Model* GetModel(ModelRef h) const { return m_Models.Get(h); }
void UnloadModel(ModelRef h) { m_Models.Unload(h); }
// 程序化平面(纯色贴图):size 为半边长。带缓存,同参数共享一份。
ModelHandle CreatePlane(f32 halfSize, u8 r, u8 g, u8 b);
ModelRef CreatePlane(f32 halfSize, u8 r, u8 g, u8 b);
AssetCache<Model>& Models() { return m_Models; }
@@ -162,10 +151,7 @@ namespace Engine {
// 各自一个 AssetCache<T> + 便捷方法,模式与 Model 完全一致。
private:
Device& m_Device;
MemoryAllocator& m_Allocator;
DescriptorManager& m_Descriptors;
vk::DescriptorSetLayout m_TextureLayout;
IAssetUploader& m_Uploader;
AssetCache<Model> m_Models;
};
@@ -0,0 +1,38 @@
//
// Created by atdunbg on 2026/9/23.
//
// IAssetUploader:资产层 → GPU 的上传接口。
//
// 资产层(AssetManager/AssetCache)只认这个接口,不感知 Vulkan 具体类
// (Device/Allocator/DescriptorManager)。实现由渲染层提供
// (VulkanAssetUploader),组合根(Renderer)装配后注入。
//
// 对齐 UE:资产系统(AssetManager/StreamableManager)与渲染资源创建
// (rendering thread / RHI)分离,资产层只拿到"可用的渲染资源"。
//
// 后续演进点:接口加返回 future / 回调即为异步加载
// (IO 线程解析 → 上传队列提交),本接口已是正确的接缝。
//
#ifndef HELLOVULKAN_IASSETUPLOADER_H
#define HELLOVULKAN_IASSETUPLOADER_H
#include <Engine/Core/Types.h>
#include <Engine/Renderer/Model.h>
namespace Engine::Assets {
class IAssetUploader {
public:
virtual ~IAssetUploader() = default;
// 磁盘模型 → 解析 + GPU 上传(失败返回 nullptr)
virtual Scope<Model> LoadModel(const std::string& path) = 0;
// 程序化纯色平面(size 为半边长)
virtual Scope<Model> CreatePlane(f32 halfSize, u8 r, u8 g, u8 b) = 0;
};
} // namespace Engine::Assets
#endif //HELLOVULKAN_IASSETUPLOADER_H