feat: 引入 RenderGraph、Application 框架、ECS 与资产句柄系统

架构分层(自上而下):
  App(SandboxApp) → Application(生命周期+事件) → Scene(ECS) / AssetManager(句柄) → Renderer → RenderGraph → Vulkan 模块

- RenderGraph:声明式帧图。虚拟资源+生成号句柄、死 pass 剔除、
  拓扑排序、资源生命周期、barrier 编译期预算(Synchronization2)、
  物理镜像池按帧槽位隔离(帧间竞争从根上消除)
- 帧同步修复:per-frame-slot 命令缓冲与 UBO ring(原先单份存在
  数据竞争);统一 kMaxFramesInFlight / FrameContext
- Application:生命周期钩子(OnInit/OnUpdate/OnRender/OnShutdown)
  + 事件系统(GLFW 回调 → POD 事件 → 类型化钩子);main 只 new 派生类
- ECS:自研稀疏集 Registry(Entity=(index,generation) 防悬空,
  O(1) 增删查,Each 取最小池遍历);Scene 延迟销毁队列;
  IdComponent{UUID} 稳定外部身份
- Assets:AssetManager + AssetHandle。组件存句柄不存裸指针/Ref
  (单一所有者 + 多使用者),Renderer 删除 LoadModel 改为纯消费
- 修复退出析构:成员析构前 GPU waitIdle(资产层先于 Renderer
  析构导致 VUID-00922 资源销毁时仍在使用)
- 引入 entt 子模块备用

validation 全程零错误零警告(RTX 5060 实测)
This commit is contained in:
2026-09-22 13:46:05 +08:00
parent 7d628f8d8a
commit 8afdd9b245
33 changed files with 3013 additions and 561 deletions
+62
View File
@@ -0,0 +1,62 @@
//
// Created by atdunbg on 2026/9/22.
//
#include <Engine/ECS/Scene.h>
#include <Engine/Core/Log.h>
namespace Engine::ECS {
Entity Scene::CreateEntity(std::string name)
{
Entity e = m_Registry.Create();
// IdComponent 自动挂载:每个实体出生即有稳定 UUID
m_Registry.Add<IdComponent>(e, IdComponent{UUID::New()});
if (!name.empty()) {
m_Registry.Add<NameComponent>(e, NameComponent{std::move(name)});
}
return e;
}
Entity Scene::FindEntityByUUID(UUID uuid)
{
if (!uuid.Valid()) return {};
Entity found{};
m_Registry.Each<IdComponent>([&](Entity e, IdComponent& id) {
if (!found && id.uuid == uuid) found = e;
});
return found;
}
void Scene::DestroyEntity(Entity e)
{
if (!m_Registry.IsAlive(e)) {
ENGINE_FATAL("Scene::DestroyEntity: stale entity ({},{})",
e.index, e.generation);
}
m_PendingDestroy.push_back(e);
}
void Scene::FlushDestroyQueue()
{
if (m_PendingDestroy.empty()) return;
for (Entity e : m_PendingDestroy) {
if (m_Registry.IsAlive(e)) {
m_Registry.Destroy(e);
}
}
m_PendingDestroy.clear();
}
CameraComponent* Scene::GetPrimaryCamera()
{
CameraComponent* found = nullptr;
m_Registry.Each<CameraComponent>([&](Entity, CameraComponent& cc) {
if (!found && cc.primary) found = &cc;
});
return found;
}
} // namespace Engine::ECS