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
-78
View File
@@ -99,14 +99,10 @@ namespace Engine
m_Extent.width, m_Extent.height,
m_Images.size(),
vk::to_string(m_Format));
CreateDepthResources();
}
void Swapchain::Destroy()
{
DestroyDepthResources();
const auto& vkDevice = m_Device.GetDevice();
for (auto view : m_ImageViews)
@@ -181,78 +177,4 @@ namespace Engine
return extent;
}
vk::Format Swapchain::FindDepthFormat()
{
// 优先 D32_SFLOAT,退回 D32_SFLOAT_S8_UINT,再退回 D24_UNORM_S8_UINT
std::array<vk::Format, 3> candidates = {
vk::Format::eD32Sfloat,
vk::Format::eD32SfloatS8Uint,
vk::Format::eD24UnormS8Uint
};
for (auto format : candidates)
{
auto props = m_Device.GetPhysicalDevice().getFormatProperties(format);
if (props.optimalTilingFeatures & vk::FormatFeatureFlagBits::eDepthStencilAttachment)
{
return format;
}
}
ENGINE_FATAL("No depth format supported");
return vk::Format::eD32Sfloat;
}
void Swapchain::CreateDepthResources()
{
m_DepthFormat = FindDepthFormat();
vk::ImageCreateInfo imageInfo;
imageInfo.setImageType(vk::ImageType::e2D)
.setFormat(m_DepthFormat)
.setExtent({m_Extent.width, m_Extent.height, 1})
.setMipLevels(1)
.setArrayLayers(1)
.setSamples(vk::SampleCountFlagBits::e1)
.setTiling(vk::ImageTiling::eOptimal)
.setUsage(vk::ImageUsageFlagBits::eDepthStencilAttachment)
.setSharingMode(vk::SharingMode::eExclusive)
.setInitialLayout(vk::ImageLayout::eUndefined);
m_DepthImage = m_Device.GetDevice().createImage(imageInfo);
auto reqs = m_Device.GetDevice().getImageMemoryRequirements(m_DepthImage);
auto alloc = m_Allocator.Allocate(reqs, vk::MemoryPropertyFlagBits::eDeviceLocal);
m_DepthMemory = alloc.Memory;
m_Device.GetDevice().bindImageMemory(m_DepthImage, m_DepthMemory, alloc.Offset);
vk::ImageViewCreateInfo viewInfo;
viewInfo.setImage(m_DepthImage)
.setViewType(vk::ImageViewType::e2D)
.setFormat(m_DepthFormat)
.setSubresourceRange({
vk::ImageAspectFlagBits::eDepth,
0, 1, 0, 1
});
m_DepthImageView = m_Device.GetDevice().createImageView(viewInfo);
}
void Swapchain::DestroyDepthResources()
{
const auto& vkDevice = m_Device.GetDevice();
if (m_DepthImageView)
{
vkDevice.destroyImageView(m_DepthImageView);
m_DepthImageView = nullptr;
}
if (m_DepthImage)
{
vkDevice.destroyImage(m_DepthImage);
m_DepthImage = nullptr;
}
// 内存由 MemoryAllocator 统一释放
}
} // namespace Engine