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:
@@ -5,32 +5,40 @@
|
||||
#ifndef HELLOVULKAN_COMMANDMANAGER_H
|
||||
#define HELLOVULKAN_COMMANDMANAGER_H
|
||||
|
||||
#include <Engine/Core/Types.h>
|
||||
#include <Engine/Core/FrameContext.h>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace Engine {
|
||||
|
||||
class Device;
|
||||
|
||||
// 每个帧槽位独立命令缓冲。
|
||||
//
|
||||
// 关键正确性约束:kMaxFramesInFlight 帧并发时,第 N 帧录制时第 N-1 帧的
|
||||
// 命令缓冲可能仍在 GPU 上执行,因此绝不能共享/复用同一个 command buffer。
|
||||
// 每个 frameSlot 一个 buffer,reset 只发生在"该槽位 fence 已确认完成"之后。
|
||||
class CommandManager {
|
||||
public:
|
||||
CommandManager(Device& device);
|
||||
CommandManager(Device& device, u32 frameCount);
|
||||
~CommandManager();
|
||||
|
||||
CommandManager(const CommandManager&) = delete;
|
||||
CommandManager& operator=(const CommandManager&) = delete;
|
||||
|
||||
// 开始录制
|
||||
vk::CommandBuffer BeginFrame();
|
||||
// 开始录制指定帧槽位的命令缓冲
|
||||
vk::CommandBuffer BeginFrame(u32 frameSlot);
|
||||
|
||||
// 结束录制
|
||||
void EndFrame();
|
||||
void EndFrame(u32 frameSlot);
|
||||
|
||||
vk::CommandBuffer GetBuffer() const { return m_Buffer; }
|
||||
vk::CommandBuffer GetBuffer(u32 frameSlot) const { return m_Buffers[frameSlot]; }
|
||||
|
||||
private:
|
||||
Device& m_Device;
|
||||
vk::CommandPool m_Pool;
|
||||
vk::CommandBuffer m_Buffer;
|
||||
std::vector<vk::CommandBuffer> m_Buffers;
|
||||
};
|
||||
|
||||
} // namespace Engine
|
||||
|
||||
@@ -34,6 +34,11 @@ public:
|
||||
|
||||
uint32_t FindMemoryType(uint32_t typeFilter, vk::MemoryPropertyFlags props) const;
|
||||
|
||||
// 在候选列表中找到第一个满足 tiling+features 的格式,找不到则 FATAL
|
||||
vk::Format FindSupportedFormat(const std::vector<vk::Format>& candidates,
|
||||
vk::ImageTiling tiling,
|
||||
vk::FormatFeatureFlags features) const;
|
||||
|
||||
// 1.4 特性查询
|
||||
bool IsDynamicRenderingSupported() const { return m_DynamicRenderingSupported; }
|
||||
bool IsShaderObjectSupported() const { return m_ShaderObjectSupported; }
|
||||
|
||||
@@ -33,10 +33,8 @@ namespace Engine
|
||||
const std::vector<vk::Image>& GetImages() const { return m_Images; }
|
||||
const std::vector<vk::ImageView>& GetImageViews() const { return m_ImageViews; }
|
||||
|
||||
vk::ImageView GetDepthImageView() const { return m_DepthImageView; }
|
||||
vk::Format GetDepthFormat() const { return m_DepthFormat; }
|
||||
vk::Image GetDepthImage() const { return m_DepthImage; }
|
||||
|
||||
// 深度图不在 Swapchain 管理——渲染目标(含深度)统一由 RenderGraph 创建。
|
||||
// Swapchain 只负责"呈现"这一件事。
|
||||
void Recreate(Window& window);
|
||||
|
||||
private:
|
||||
@@ -47,10 +45,6 @@ namespace Engine
|
||||
vk::PresentModeKHR ChoosePresentMode(const std::vector<vk::PresentModeKHR>& modes);
|
||||
vk::Extent2D ChooseExtent(const vk::SurfaceCapabilitiesKHR& caps, Window& window);
|
||||
|
||||
void CreateDepthResources();
|
||||
void DestroyDepthResources();
|
||||
vk::Format FindDepthFormat();
|
||||
|
||||
|
||||
Device& m_Device;
|
||||
|
||||
@@ -58,11 +52,6 @@ namespace Engine
|
||||
std::vector<vk::Image> m_Images;
|
||||
std::vector<vk::ImageView> m_ImageViews;
|
||||
|
||||
vk::Image m_DepthImage;
|
||||
vk::DeviceMemory m_DepthMemory;
|
||||
vk::ImageView m_DepthImageView;
|
||||
vk::Format m_DepthFormat;
|
||||
|
||||
MemoryAllocator& m_Allocator;
|
||||
|
||||
vk::Format m_Format;
|
||||
|
||||
@@ -5,33 +5,42 @@
|
||||
#ifndef HELLOVULKAN_UNIFORMBUFFER_H
|
||||
#define HELLOVULKAN_UNIFORMBUFFER_H
|
||||
|
||||
|
||||
#include <Engine/Core/Types.h>
|
||||
#include <Engine/Core/FrameContext.h>
|
||||
#include <Engine/Vulkan/Buffer.h>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace Engine {
|
||||
|
||||
class Device;
|
||||
class MemoryAllocator;
|
||||
|
||||
// Per-frame UBO ring:每个帧槽位一个独立 buffer。
|
||||
//
|
||||
// 正确性:CPU 在第 N 帧写 UBO 时,GPU 可能仍在读取第 N-1 帧的同槽位数据。
|
||||
// 共享单个 buffer 会产生数据竞争;ring 化后每槽位的写入严格发生在
|
||||
// 该槽位 fence 确认完成之后。
|
||||
// 后续演进方向:单个大 ring buffer + 动态 offset(省描述符、省内存),
|
||||
// 接口已按"写入哪个槽位"设计,届时只是内部实现替换。
|
||||
class UniformBuffer {
|
||||
public:
|
||||
UniformBuffer(Device& device, MemoryAllocator& allocator, u64 size);
|
||||
~UniformBuffer();
|
||||
UniformBuffer(Device& device, MemoryAllocator& allocator,
|
||||
u64 size, u32 frameCount);
|
||||
~UniformBuffer() = default;
|
||||
|
||||
UniformBuffer(const UniformBuffer&) = delete;
|
||||
UniformBuffer& operator=(const UniformBuffer&) = delete;
|
||||
|
||||
vk::Buffer Get() const { return m_Buffer->Get(); }
|
||||
vk::Buffer Get(u32 frameSlot) const { return m_Buffers[frameSlot]->Get(); }
|
||||
u64 GetSize() const { return m_Size; }
|
||||
|
||||
// 每帧更新数据
|
||||
void Update(const void* data, u64 size);
|
||||
// 写入指定帧槽位的 UBO(仅在该槽位 fence 确认完成后调用)
|
||||
void Update(u32 frameSlot, const void* data, u64 size);
|
||||
|
||||
private:
|
||||
Scope<Buffer> m_Buffer;
|
||||
u64 m_Size;
|
||||
std::vector<Scope<Buffer>> m_Buffers;
|
||||
u64 m_Size = 0;
|
||||
};
|
||||
|
||||
} // namespace Engine
|
||||
|
||||
Reference in New Issue
Block a user