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
+64
View File
@@ -0,0 +1,64 @@
//
// Created by atdunbg on 2026/9/22.
//
#include <Engine/Renderer/Camera.h>
#include <Engine/Core/Window.h>
#include <glm/gtc/matrix_transform.hpp>
#include "GLFW/glfw3.h"
namespace Engine {
void Camera::Update(Window& window, f32 deltaTime)
{
// 鼠标旋转(需显式启用,配合 cursor capture 使用)
if (m_MouseLookEnabled)
{
f32 mouseDX = 0, mouseDY = 0;
window.GetMouseDelta(mouseDX, mouseDY);
if (mouseDX != 0 || mouseDY != 0)
{
m_Yaw += mouseDX * m_MouseSensitivity;
m_Pitch -= mouseDY * m_MouseSensitivity;
m_Pitch = glm::clamp(m_Pitch, -89.0f, 89.0f);
}
}
UpdateBasis();
f32 speed = m_MoveSpeed * deltaTime;
if (window.IsKeyPressed(GLFW_KEY_W)) m_Position += m_Forward * speed;
if (window.IsKeyPressed(GLFW_KEY_S)) m_Position -= m_Forward * speed;
if (window.IsKeyPressed(GLFW_KEY_A)) m_Position -= m_Right * speed;
if (window.IsKeyPressed(GLFW_KEY_D)) m_Position += m_Right * speed;
if (window.IsKeyPressed(GLFW_KEY_SPACE)) m_Position.y += speed;
if (window.IsKeyPressed(GLFW_KEY_LEFT_SHIFT)) m_Position.y -= speed;
}
void Camera::UpdateBasis()
{
m_Forward.x = cosf(glm::radians(m_Yaw)) * cosf(glm::radians(m_Pitch));
m_Forward.y = sinf(glm::radians(m_Pitch));
m_Forward.z = sinf(glm::radians(m_Yaw)) * cosf(glm::radians(m_Pitch));
m_Forward = glm::normalize(m_Forward);
m_Right = glm::normalize(glm::cross(m_Forward, glm::vec3(0, 1, 0)));
m_Up = glm::normalize(glm::cross(m_Right, m_Forward));
}
glm::mat4 Camera::GetView() const
{
return glm::lookAt(m_Position, m_Position + m_Forward, m_Up);
}
glm::mat4 Camera::GetProjection(f32 aspect, f32 nearZ, f32 farZ) const
{
auto proj = glm::perspective(glm::radians(45.0f), aspect, nearZ, farZ);
proj[1][1] *= -1.0f; // Vulkan Y 翻转
return proj;
}
} // namespace Engine
+287 -373
View File
@@ -4,6 +4,11 @@
#include <Engine/Renderer/Renderer.h>
#include <Engine/Renderer/Material.h>
#include <Engine/Renderer/Model.h>
#include <Engine/Renderer/Vertex.h>
#include <Engine/ECS/Scene.h>
#include <Engine/ECS/Components.h>
#include <Engine/Assets/AssetManager.h>
#include <Engine/Vulkan/Device.h>
#include <Engine/Vulkan/MemoryAllocator.h>
#include <Engine/Vulkan/DescriptorManager.h>
@@ -20,26 +25,30 @@
#include <array>
#include <limits>
#include <vector>
#include "Engine/Core/Stats.h"
#include "GLFW/glfw3.h"
namespace Engine
{
using namespace ECS; // TransformComponent / Entity 等直接使用
struct Light {
glm::vec4 direction;
glm::vec4 color; // rgb = 颜色,a = 强度
};
namespace
{
struct Light {
glm::vec4 direction; // xyz = 方向,w 未用
glm::vec4 color; // rgb = 颜色,a = 强度
};
struct UniformBufferObject {
glm::mat4 view;
glm::mat4 proj;
glm::vec4 ambientColor;
Light lights[4];
};
struct UniformBufferObject {
glm::mat4 view;
glm::mat4 proj;
glm::vec4 ambientColor;
Light lights[4];
};
constexpr u32 kUboBinding = 0;
constexpr u32 kUBOSetIndex = 0;
constexpr u32 kTextureSetIndex = 1;
constexpr u32 kMaxLights = 4;
}
Renderer::Renderer(Window& window)
: m_Window(window)
@@ -55,7 +64,8 @@ namespace Engine
// 4. Set 0: UBO
std::vector<DescriptorBinding> uboBindings = {
{0, vk::DescriptorType::eUniformBuffer, vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment },
{kUboBinding, vk::DescriptorType::eUniformBuffer,
vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment},
};
m_UBOSetLayout = m_DescriptorManager->CreateLayout(uboBindings);
@@ -66,277 +76,350 @@ namespace Engine
m_TextureSetLayout = m_DescriptorManager->CreateLayout(texBindings);
// 6. PipelineLayout:两个 set
std::vector<vk::DescriptorSetLayout> layouts = {
m_UBOSetLayout, m_TextureSetLayout
};
m_PipelineLayout = m_DescriptorManager->CreatePipelineLayout(
layouts, sizeof(glm::mat4));
{m_UBOSetLayout, m_TextureSetLayout}, sizeof(glm::mat4));
// 7. ShaderManager
// 7. ShaderManager(VK_EXT_shader_object)
m_ShaderManager = CreateScope<ShaderManager>(*m_Device);
std::string shaderDir = "shaders/";
auto vert = m_ShaderManager->CreateFromFile(
shaderDir + "simple_shader.vert.spv",
vk::ShaderStageFlagBits::eVertex,
layouts, sizeof(glm::mat4));
{m_UBOSetLayout, m_TextureSetLayout}, sizeof(glm::mat4));
auto frag = m_ShaderManager->CreateFromFile(
shaderDir + "simple_shader.frag.spv",
vk::ShaderStageFlagBits::eFragment,
layouts, sizeof(glm::mat4));
{m_UBOSetLayout, m_TextureSetLayout}, sizeof(glm::mat4));
m_VertShader = vert.Handle;
m_FragShader = frag.Handle;
if (!m_VertShader || !m_FragShader)
{
if (!m_VertShader || !m_FragShader) {
ENGINE_FATAL("Failed to create shader objects");
}
// 8. Swapchain
m_Swapchain = CreateScope<Swapchain>(*m_Device, *m_Allocator, window);
// 8. Swapchain(只管呈现;深度图由 RenderGraph 创建)
m_Swapchain = CreateScope<Swapchain>(*m_Device, *m_Allocator, m_Window);
m_Extent = m_Swapchain->GetExtent();
m_Format = m_Swapchain->GetFormat();
// 9. SyncManager
m_SyncManager = CreateScope<SyncManager>(*m_Device, kMaxFramesInFlight, m_Swapchain->GetImageCount());
// 9. Sync / Command(per-frame)
m_SyncManager = CreateScope<SyncManager>(
*m_Device, kMaxFramesInFlight, m_Swapchain->GetImageCount());
m_CommandManager = CreateScope<CommandManager>(*m_Device, kMaxFramesInFlight);
// 10. CommandManager
m_CommandManager = CreateScope<CommandManager>(*m_Device);
// 11. Uniform Buffer
// 10. Per-frame UBO ring + 每槽位的 UBO descriptor set
m_UniformBuffer = CreateScope<UniformBuffer>(
*m_Device, *m_Allocator, sizeof(UniformBufferObject));
*m_Device, *m_Allocator, sizeof(UniformBufferObject), kMaxFramesInFlight);
// 12. UBO DescriptorSet
m_UBODescriptorSet = m_DescriptorManager->AllocateDescriptorSet(m_UBOSetLayout);
m_DescriptorManager->UpdateUniformBuffer(
m_UBODescriptorSet, 0, m_UniformBuffer->Get(), m_UniformBuffer->GetSize());
// 13. Model(模型自己加载纹理)
m_Model = CreateScope<Model>(
*m_Device, *m_Allocator, *m_DescriptorManager,
m_TextureSetLayout,
"assets/models/backpack/backpack.obj");
// 14. 创建几个物体,摆一排
for (int i = 0; i < 3; ++i) {
Object obj;
obj.model = m_Model.get();
obj.transform = glm::translate(
glm::mat4(1.0f),
glm::vec3((i - 1) * 1.5f, 0.0f, 0.0f));
m_Objects.push_back(obj);
m_UBODescriptorSets.resize(kMaxFramesInFlight);
for (u32 slot = 0; slot < kMaxFramesInFlight; ++slot) {
m_UBODescriptorSets[slot] =
m_DescriptorManager->AllocateDescriptorSet(m_UBOSetLayout);
m_DescriptorManager->UpdateUniformBuffer(
m_UBODescriptorSets[slot], kUboBinding,
m_UniformBuffer->Get(slot), m_UniformBuffer->GetSize());
}
m_StartTime = std::chrono::steady_clock::now();
// 11. RenderGraph:声明 + 编译(场景在 Render(Scene&) 时按帧绑定)
BuildGraph();
ENGINE_INFO("Renderer initialized");
}
Renderer::~Renderer()
{
m_Device->GetDevice().waitIdle();
if (m_VertShader)
{
if (m_VertShader) {
m_Device->GetDevice().destroyShaderEXT(m_VertShader);
}
if (m_FragShader)
{
if (m_FragShader) {
m_Device->GetDevice().destroyShaderEXT(m_FragShader);
}
m_Device->GetDevice().destroyPipelineLayout(m_PipelineLayout);
m_Device->GetDevice().destroyDescriptorSetLayout(m_UBOSetLayout);
m_Device->GetDevice().destroyDescriptorSetLayout(m_TextureSetLayout);
}
void Renderer::Render()
void Renderer::BuildGraph()
{
m_RenderGraph = CreateScope<RG::RenderGraph>(
*m_Device, *m_Allocator, kMaxFramesInFlight);
if (m_Window.WasResized())
{
// 导入 swapchain 颜色附件
m_Backbuffer = m_RenderGraph->ImportSwapchain(
"Backbuffer", m_Swapchain->GetFormat());
// 深度图:目标尺寸,格式由 Device 能力决定
const vk::Format depthFormat = m_Device->FindSupportedFormat(
{vk::Format::eD32Sfloat, vk::Format::eD32SfloatS8Uint,
vk::Format::eD24UnormS8Uint},
vk::ImageTiling::eOptimal,
vk::FormatFeatureFlagBits::eDepthStencilAttachment);
m_Depth = m_RenderGraph->CreateTexture(
"MainDepth", RG::TextureDesc{depthFormat});
// ---- Forward pass:直接渲染到 swapchain ----
// 场景数据每帧经 m_BoundScene 从 ECS 读取
m_RenderGraph->AddPass("Forward",
[this](RG::RenderGraphContext& ctx) {
const vk::CommandBuffer cmd = ctx.cmd;
vk::ClearValue clearValue;
clearValue.color = vk::ClearColorValue(
std::array<float, 4>{0.1f, 0.1f, 0.1f, 1.0f});
vk::RenderingAttachmentInfo colorAttachment;
colorAttachment.setImageView(ctx.View(m_Backbuffer))
.setImageLayout(vk::ImageLayout::eColorAttachmentOptimal)
.setLoadOp(vk::AttachmentLoadOp::eClear)
.setStoreOp(vk::AttachmentStoreOp::eStore)
.setClearValue(clearValue);
vk::RenderingAttachmentInfo depthAttachment;
depthAttachment.setImageView(ctx.View(m_Depth))
.setImageLayout(vk::ImageLayout::eDepthAttachmentOptimal)
.setLoadOp(vk::AttachmentLoadOp::eClear)
.setStoreOp(vk::AttachmentStoreOp::eDontCare)
.setClearValue(vk::ClearValue(
vk::ClearDepthStencilValue(1.0f, 0)));
vk::RenderingInfo renderingInfo;
renderingInfo.setRenderArea({{0, 0}, ctx.extent})
.setLayerCount(1)
.setColorAttachments(colorAttachment)
.setPDepthAttachment(&depthAttachment);
cmd.beginRendering(renderingInfo);
// 绑定 shader object
std::array<vk::ShaderStageFlagBits, 2> stages = {
vk::ShaderStageFlagBits::eVertex,
vk::ShaderStageFlagBits::eFragment
};
std::array<vk::ShaderEXT, 2> shaders = {m_VertShader, m_FragShader};
cmd.bindShadersEXT(stages, shaders);
// Set 0:本帧槽位的 UBO
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics,
m_PipelineLayout, kUBOSetIndex,
m_UBODescriptorSets[ctx.frame.frameSlot], {});
// ---- 动态状态 ----
cmd.setRasterizerDiscardEnable(VK_FALSE);
cmd.setDepthTestEnable(VK_TRUE);
cmd.setDepthWriteEnable(VK_TRUE);
cmd.setDepthCompareOp(vk::CompareOp::eLess);
cmd.setDepthBoundsTestEnable(VK_FALSE);
cmd.setStencilTestEnable(VK_FALSE);
cmd.setDepthBiasEnable(VK_FALSE);
cmd.setPolygonModeEXT(vk::PolygonMode::eFill);
cmd.setCullMode(vk::CullModeFlagBits::eNone);
cmd.setFrontFace(vk::FrontFace::eCounterClockwise);
cmd.setPrimitiveTopology(vk::PrimitiveTopology::eTriangleList);
cmd.setPrimitiveRestartEnable(VK_FALSE);
auto binding = Vertex::GetBindingDescription();
auto attributes = Vertex::GetAttributeDescriptions();
cmd.setVertexInputEXT(binding, attributes);
cmd.setRasterizationSamplesEXT(vk::SampleCountFlagBits::e1);
vk::SampleMask sampleMask = 0xFFFFFFFF;
cmd.setSampleMaskEXT(vk::SampleCountFlagBits::e1, sampleMask);
cmd.setAlphaToCoverageEnableEXT(VK_FALSE);
cmd.setAlphaToOneEnableEXT(VK_FALSE);
vk::Viewport viewport(0.0f, 0.0f,
static_cast<float>(ctx.extent.width),
static_cast<float>(ctx.extent.height),
0.0f, 1.0f);
cmd.setViewportWithCount(viewport);
vk::Rect2D scissor({0, 0}, ctx.extent);
cmd.setScissorWithCount(scissor);
vk::Bool32 blendEnable = VK_FALSE;
cmd.setColorBlendEnableEXT(0, blendEnable);
vk::ColorBlendEquationEXT blendEquation;
blendEquation.setSrcColorBlendFactor(vk::BlendFactor::eOne)
.setDstColorBlendFactor(vk::BlendFactor::eZero)
.setColorBlendOp(vk::BlendOp::eAdd)
.setSrcAlphaBlendFactor(vk::BlendFactor::eOne)
.setDstAlphaBlendFactor(vk::BlendFactor::eZero)
.setAlphaBlendOp(vk::BlendOp::eAdd);
cmd.setColorBlendEquationEXT(0, blendEquation);
vk::ColorComponentFlags colorWriteMask =
vk::ColorComponentFlagBits::eR |
vk::ColorComponentFlagBits::eG |
vk::ColorComponentFlagBits::eB |
vk::ColorComponentFlagBits::eA;
cmd.setColorWriteMaskEXT(0, colorWriteMask);
// ---- 绘制:遍历 ECS 渲染体 ----
// Each 以 Transform/MeshRenderer 中较小的池为主表——
// 大场景下遍历开销与最小池规模成正比
m_BoundScene->Each<TransformComponent, MeshRendererComponent>(
[&](Entity, TransformComponent& transform,
MeshRendererComponent& meshRenderer) {
// 句柄 → 资产(悬空句柄会被 AssetCache FATAL 拦截)
Model* model = m_BoundAssets->GetModel(meshRenderer.model);
if (!model) return;
cmd.pushConstants(m_PipelineLayout,
vk::ShaderStageFlagBits::eVertex,
0, sizeof(glm::mat4), &transform.world);
for (auto& mesh : model->GetMeshes()) {
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics,
m_PipelineLayout, kTextureSetIndex,
mesh->GetMaterial()->GetDescriptorSet(), {});
mesh->Draw(cmd);
}
});
cmd.endRendering();
})
.Write(m_Backbuffer, RG::ResourceUse::ColorAttachment)
.Write(m_Depth, RG::ResourceUse::DepthAttachment);
// ---- Present pass:transition 到 ePresentSrcKHR ----
m_RenderGraph->AddPass("Present",
[](RG::RenderGraphContext&) {
// present 的 layout 转换由 RG 的 barrier 完成,
// 实际 vkQueuePresentKHR 由 Renderer 驱动。
})
.Read(m_Backbuffer, RG::ResourceUse::Present);
m_RenderGraph->SetTargetExtent(m_Extent); // 触发首次 Compile
}
void Renderer::HandleResize()
{
m_Device->GetDevice().waitIdle();
m_Swapchain->Recreate(m_Window);
m_Extent = m_Swapchain->GetExtent();
// image 数量可能变化
m_SyncManager = CreateScope<SyncManager>(
*m_Device, kMaxFramesInFlight, m_Swapchain->GetImageCount());
// RG 重编译:物理镜像按新尺寸轮换
m_RenderGraph->SetTargetExtent(m_Extent);
}
void Renderer::Render(ECS::Scene& scene, Assets::AssetManager& assets)
{
m_BoundScene = &scene;
m_BoundAssets = &assets;
if (m_Window.WasResized()) {
m_Window.ResetResizedFlag();
m_Device->GetDevice().waitIdle();
m_Swapchain->Recreate(m_Window);
m_Extent = m_Swapchain->GetExtent();
m_SyncManager = CreateScope<SyncManager>(
*m_Device, kMaxFramesInFlight, m_Swapchain->GetImageCount());
HandleResize();
}
u32 frameIndex = m_CurrentFrame;
const u32 frameSlot = m_CurrentFrame;
const auto& vkDevice = m_Device->GetDevice();
// 1. 更新 MVP 矩阵
auto now = std::chrono::steady_clock::now();
float currentTime = std::chrono::duration<float>(now - m_StartTime).count();
m_DeltaTime = currentTime - m_LastFrameTime;
m_LastFrameTime = currentTime;
// 更新每个物体的 transform
for (size_t i = 0; i < m_Objects.size(); ++i) {
float angle = currentTime * glm::radians(60.0f) + i * 0.7f;
glm::mat4 t = glm::translate(
glm::mat4(1.0f),
glm::vec3((static_cast<float>(i) - 1.0f) * 1.5f, 0.0f, 0.0f));
glm::mat4 r = glm::rotate(glm::mat4(1.0f), angle, glm::vec3(0.0f, 1.0f, 0.0f));
m_Objects[i].transform = t * r;
// 1. UBO:从 ECS 场景组装(primary 相机 + 灯光 + 环境色)
auto* cameraComp = scene.GetPrimaryCamera();
if (!cameraComp) {
// 无相机:跳过本帧(正常场景必有相机,这里只是安全网)
return;
}
// 鼠标控制方向
/*
float mouseDX = 0, mouseDY = 0;
m_Window.GetMouseDelta(mouseDX, mouseDY);
if (mouseDX != 0 || mouseDY != 0)
{
m_CameraYaw += mouseDX * m_MouseSensitivity;
m_CameraPitch -= mouseDY * m_MouseSensitivity;
m_CameraPitch = glm::clamp(m_CameraPitch, -89.0f, 89.0f);
}
*/
// 相机前方向量
glm::vec3 forward;
forward.x = cosf(glm::radians(m_CameraYaw)) * cos(glm::radians(m_CameraPitch));
forward.y = sinf(glm::radians(m_CameraPitch));
forward.z = sinf(glm::radians(m_CameraYaw)) * cos(glm::radians(m_CameraPitch));
forward = glm::normalize(forward);
glm::vec3 right = glm::normalize(glm::cross(forward, glm::vec3(0, 1, 0)));
glm::vec3 up = glm::normalize(glm::cross(right, forward));
// WASD 移动
float speed = m_CameraSpeed * m_DeltaTime;
if (m_Window.IsKeyPressed(GLFW_KEY_W)) m_CameraPos += forward * speed;
if (m_Window.IsKeyPressed(GLFW_KEY_S)) m_CameraPos -= forward * speed;
if (m_Window.IsKeyPressed(GLFW_KEY_A)) m_CameraPos -= right * speed;
if (m_Window.IsKeyPressed(GLFW_KEY_D)) m_CameraPos += right * speed;
if (m_Window.IsKeyPressed(GLFW_KEY_SPACE)) m_CameraPos.y += speed;
if (m_Window.IsKeyPressed(GLFW_KEY_LEFT_SHIFT)) m_CameraPos.y -= speed;
auto view = glm::lookAt(m_CameraPos,
m_CameraPos + forward,
up);
const Camera& camera = cameraComp->camera;
float aspect = static_cast<f32>(m_Extent.width) /
static_cast<f32>(m_Extent.height);
auto proj = glm::perspective(glm::radians(45.0f), aspect, 0.1f, 100.0f);
proj[1][1] *= -1.0f; // Vulkan Y 翻转
static_cast<f32>(m_Extent.height);
UniformBufferObject ubo{};
ubo.view = view;
ubo.proj = proj;
ubo.view = camera.GetView();
ubo.proj = camera.GetProjection(aspect, 0.1f, 100.0f);
ubo.ambientColor = scene.GetSettings().ambientColor;
ubo.ambientColor = glm::vec4(0.15f, 0.15f, 0.2f, 0.0f);
u32 lightCount = 0;
scene.Each<LightComponent>([&](Entity, LightComponent& light) {
if (lightCount >= kMaxLights) return;
ubo.lights[lightCount].direction =
glm::length(light.direction) > 0.0f
? glm::vec4(glm::normalize(light.direction), 0.0f)
: glm::vec4(0.0f);
ubo.lights[lightCount].color = light.color;
++lightCount;
});
for (u32 i = lightCount; i < kMaxLights; ++i) {
ubo.lights[i].direction = glm::vec4(0.0f);
ubo.lights[i].color = glm::vec4(0.0f);
}
// 主光:暖色,从左上方照下
ubo.lights[0].direction = glm::vec4(glm::normalize(glm::vec3(-0.5f, -1.0f, -0.3f)), 0.0f);
ubo.lights[0].color = glm::vec4(1.0f, 0.95f, 0.9f, 1.0f);
// 此时本槽位的 fence 尚未 reset——先等它(保证 GPU 已完成本槽位上一轮),
// 再写 UBO,写-读竞争关闭。
m_SyncManager->WaitFence(frameSlot);
m_UniformBuffer->Update(frameSlot, &ubo, sizeof(ubo));
m_SyncManager->ResetFence(frameSlot);
// 补光:冷色,从右下方照上
ubo.lights[1].direction = glm::vec4(glm::normalize(glm::vec3(0.5f, -0.5f, 0.3f)), 0.0f);
ubo.lights[1].color = glm::vec4(0.3f, 0.5f, 1.0f, 0.8f);
// 未使用:强度 0
ubo.lights[2].direction = glm::vec4(0.0f, 0.0f, 0.0f, 0.0f);
ubo.lights[2].color = glm::vec4(0.0f, 0.0f, 0.0f, 0.0f);
ubo.lights[3].direction = glm::vec4(0.0f, 0.0f, 0.0f, 0.0f);
ubo.lights[3].color = glm::vec4(0.0f, 0.0f, 0.0f, 0.0f);
m_UniformBuffer->Update(&ubo, sizeof(ubo));
// 等待这一帧上一次完成
m_SyncManager->WaitFence(frameIndex);
// 2. 获取交换链 image
// 2. acquire swapchain image
u32 imageIndex = 0;
try
{
try {
const auto result = vkDevice.acquireNextImageKHR(
m_Swapchain->Get(),
std::numeric_limits<u64>::max(),
m_SyncManager->GetImageAvailable(frameIndex));
m_SyncManager->GetImageAvailable(frameSlot));
if (result.result == vk::Result::eErrorOutOfDateKHR)
{
m_Swapchain->Recreate(m_Window);
return; // ← fence 没被 reset,下帧 wait 立即返回
if (result.result == vk::Result::eErrorOutOfDateKHR) {
HandleResize();
return;
}
imageIndex = result.value;
}
catch (const vk::OutOfDateKHRError&)
{
m_Swapchain->Recreate(m_Window);
catch (const vk::OutOfDateKHRError&) {
HandleResize();
return;
}
// 3. acquire 成功, reset fence
m_SyncManager->ResetFence(frameIndex);
// 3. 录制:FrameContext + RenderGraph
FrameContext frame;
frame.frameSlot = frameSlot;
frame.imageIndex = imageIndex;
frame.cmd = m_CommandManager->BeginFrame(frameSlot);
// 4. 录制命令
auto cmd = m_CommandManager->BeginFrame();
m_RenderGraph->SetImportedImage(
m_Backbuffer,
m_Swapchain->GetImages()[imageIndex],
m_Swapchain->GetImageViews()[imageIndex]);
TransitionImageLayout(cmd, m_Swapchain->GetImages()[imageIndex],
vk::ImageLayout::eUndefined,
vk::ImageLayout::eColorAttachmentOptimal);
m_RenderGraph->Execute(frame);
// 深度转换
vk::ImageMemoryBarrier2 depthBarrier;
depthBarrier.setSrcStageMask(vk::PipelineStageFlagBits2::eEarlyFragmentTests)
.setSrcAccessMask(vk::AccessFlagBits2::eDepthStencilAttachmentWrite)
.setDstStageMask(vk::PipelineStageFlagBits2::eEarlyFragmentTests)
.setDstAccessMask(vk::AccessFlagBits2::eDepthStencilAttachmentWrite)
.setOldLayout(vk::ImageLayout::eUndefined)
.setNewLayout(vk::ImageLayout::eDepthAttachmentOptimal)
.setImage(m_Swapchain->GetDepthImage())
.setSubresourceRange({
vk::ImageAspectFlagBits::eDepth,
0, 1, 0, 1
});
m_CommandManager->EndFrame(frameSlot);
vk::DependencyInfo depthDep;
depthDep.setImageMemoryBarriers(depthBarrier);
cmd.pipelineBarrier2(depthDep);
RecordCommands(cmd, imageIndex);
TransitionImageLayout(cmd, m_Swapchain->GetImages()[imageIndex],
vk::ImageLayout::eColorAttachmentOptimal,
vk::ImageLayout::ePresentSrcKHR);
m_CommandManager->EndFrame();
// 5. 提交
// 4. 提交
std::array<vk::PipelineStageFlags, 1> waitStages = {
vk::PipelineStageFlagBits::eColorAttachmentOutput
};
std::array<vk::Semaphore, 1> waitSemaphores = {
m_SyncManager->GetImageAvailable(frameIndex)
m_SyncManager->GetImageAvailable(frameSlot)
};
std::array<vk::Semaphore, 1> signalSemaphores = {
m_SyncManager->GetRenderFinished(imageIndex)
};
vk::SubmitInfo submitInfo;
submitInfo.setCommandBuffers(cmd)
submitInfo.setCommandBuffers(frame.cmd)
.setWaitSemaphores(waitSemaphores)
.setWaitDstStageMask(waitStages)
.setSignalSemaphores(signalSemaphores);
m_Device->GetGraphicsQueue().submit(submitInfo, m_SyncManager->GetFrameFence(frameIndex));
m_Device->GetGraphicsQueue().submit(
submitInfo, m_SyncManager->GetFrameFence(frameSlot));
// 6. 呈现
// 5. 呈现
std::array<vk::SwapchainKHR, 1> swapchains = {m_Swapchain->Get()};
std::array<vk::Semaphore, 1> presentWait = {
m_SyncManager->GetRenderFinished(imageIndex)
@@ -347,186 +430,17 @@ namespace Engine
.setSwapchains(swapchains)
.setWaitSemaphores(presentWait);
try
{
try {
auto result = m_Device->GetPresentQueue().presentKHR(presentInfo);
if (result == vk::Result::eSuboptimalKHR)
{
m_Swapchain->Recreate(m_Window);
if (result == vk::Result::eSuboptimalKHR) {
HandleResize();
}
}
catch (const vk::OutOfDateKHRError&)
{
m_Swapchain->Recreate(m_Window);
catch (const vk::OutOfDateKHRError&) {
HandleResize();
}
if (m_Window.IsKeyPressed(GLFW_KEY_F1))
STATS.PrintComparison();
m_CurrentFrame = (m_CurrentFrame + 1) % kMaxFramesInFlight;
}
void Renderer::RecordCommands(vk::CommandBuffer cmd, u32 imageIndex)
{
vk::ClearValue clearValue;
clearValue.color = vk::ClearColorValue(std::array<float, 4>{0.1f, 0.1f, 0.1f, 1.0f});
// 颜色附件
vk::RenderingAttachmentInfo colorAttachment;
colorAttachment.setImageView(m_Swapchain->GetImageViews()[imageIndex])
.setImageLayout(vk::ImageLayout::eColorAttachmentOptimal)
.setLoadOp(vk::AttachmentLoadOp::eClear)
.setStoreOp(vk::AttachmentStoreOp::eStore)
.setClearValue(clearValue);
// 深度附件
vk::RenderingAttachmentInfo depthAttachment;
depthAttachment.setImageView(m_Swapchain->GetDepthImageView())
.setImageLayout(vk::ImageLayout::eDepthAttachmentOptimal)
.setLoadOp(vk::AttachmentLoadOp::eClear)
.setStoreOp(vk::AttachmentStoreOp::eDontCare)
.setClearValue(vk::ClearValue(vk::ClearDepthStencilValue(1.0f, 0)));
vk::RenderingInfo renderingInfo;
renderingInfo.setRenderArea({{0, 0}, m_Extent})
.setLayerCount(1)
.setColorAttachments(colorAttachment)
.setPDepthAttachment(&depthAttachment);
cmd.beginRendering(renderingInfo);
// 绑定着色器
std::array<vk::ShaderStageFlagBits, 2> stages = {
vk::ShaderStageFlagBits::eVertex,
vk::ShaderStageFlagBits::eFragment
};
std::array<vk::ShaderEXT, 2> shaders = {m_VertShader, m_FragShader};
cmd.bindShadersEXT(stages, shaders);
// 绑定描述符集
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics,
m_PipelineLayout, 0,
m_UBODescriptorSet, {});
// ===== 动态状态 =====
cmd.setRasterizerDiscardEnable(VK_FALSE);
cmd.setDepthTestEnable(VK_TRUE);
cmd.setDepthWriteEnable(VK_TRUE);
cmd.setDepthCompareOp(vk::CompareOp::eLess);
cmd.setDepthBoundsTestEnable(VK_FALSE);
cmd.setStencilTestEnable(VK_FALSE);
cmd.setDepthBiasEnable(VK_FALSE);
cmd.setPolygonModeEXT(vk::PolygonMode::eFill);
cmd.setCullMode(vk::CullModeFlagBits::eNone);
cmd.setFrontFace(vk::FrontFace::eCounterClockwise);
cmd.setPrimitiveTopology(vk::PrimitiveTopology::eTriangleList);
cmd.setPrimitiveRestartEnable(VK_FALSE);
// 顶点输入
/*
vk::VertexInputBindingDescription2EXT binding;
binding.setBinding(0)
.setStride(sizeof(f32) * 5)
.setInputRate(vk::VertexInputRate::eVertex)
.setDivisor(1);
std::array<vk::VertexInputAttributeDescription2EXT, 2> attributes;
// location 0: position
attributes[0].setLocation(0)
.setBinding(0)
.setFormat(vk::Format::eR32G32B32Sfloat)
.setOffset(0);
// location 1: uv
attributes[1].setLocation(1)
.setBinding(0)
.setFormat(vk::Format::eR32G32Sfloat)
.setOffset(sizeof(f32) * 3);
*/
auto binding = Vertex::GetBindingDescription();
auto attributes = Vertex::GetAttributeDescriptions();
cmd.setVertexInputEXT(binding, attributes);
cmd.setRasterizationSamplesEXT(vk::SampleCountFlagBits::e1);
vk::SampleMask sampleMask = 0xFFFFFFFF;
cmd.setSampleMaskEXT(vk::SampleCountFlagBits::e1, sampleMask);
cmd.setAlphaToCoverageEnableEXT(VK_FALSE);
cmd.setAlphaToOneEnableEXT(VK_FALSE);
vk::Viewport viewport(0.0f, 0.0f,
static_cast<float>(m_Extent.width),
static_cast<float>(m_Extent.height),
0.0f, 1.0f);
cmd.setViewportWithCount(viewport);
vk::Rect2D scissor({0, 0}, m_Extent);
cmd.setScissorWithCount(scissor);
vk::Bool32 blendEnable = VK_FALSE;
cmd.setColorBlendEnableEXT(0, blendEnable);
vk::ColorBlendEquationEXT blendEquation;
blendEquation.setSrcColorBlendFactor(vk::BlendFactor::eOne)
.setDstColorBlendFactor(vk::BlendFactor::eZero)
.setColorBlendOp(vk::BlendOp::eAdd)
.setSrcAlphaBlendFactor(vk::BlendFactor::eOne)
.setDstAlphaBlendFactor(vk::BlendFactor::eZero)
.setAlphaBlendOp(vk::BlendOp::eAdd);
cmd.setColorBlendEquationEXT(0, blendEquation);
vk::ColorComponentFlags colorWriteMask =
vk::ColorComponentFlagBits::eR |
vk::ColorComponentFlagBits::eG |
vk::ColorComponentFlagBits::eB |
vk::ColorComponentFlagBits::eA;
cmd.setColorWriteMaskEXT(0, colorWriteMask);
// 绑定顶点缓冲并绘制
for (auto& obj : m_Objects) {
cmd.pushConstants(m_PipelineLayout,
vk::ShaderStageFlagBits::eVertex,
0, sizeof(glm::mat4), &obj.transform);
for (auto& mesh : obj.model->GetMeshes()) {
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics,
m_PipelineLayout, 1,
mesh->GetMaterial()->GetDescriptorSet(), {});
mesh->Draw(cmd);
}
}
/*
cmd.bindVertexBuffers(0, m_VertexBuffer->Get(), {0});
cmd.bindIndexBuffer(m_IndexBuffer->Get(), 0, vk::IndexType::eUint32);
// cmd.draw(3, 1, 0, 0);
cmd.drawIndexed(36, 1, 0, 0, 0);
*/
cmd.endRendering();
}
void Renderer::TransitionImageLayout(vk::CommandBuffer cmd, vk::Image image,
vk::ImageLayout oldLayout, vk::ImageLayout newLayout)
{
vk::ImageMemoryBarrier2 barrier;
barrier.setSrcStageMask(vk::PipelineStageFlagBits2::eColorAttachmentOutput)
.setSrcAccessMask(vk::AccessFlagBits2::eColorAttachmentWrite)
.setDstStageMask(vk::PipelineStageFlagBits2::eColorAttachmentOutput)
.setDstAccessMask(vk::AccessFlagBits2::eColorAttachmentWrite)
.setOldLayout(oldLayout)
.setNewLayout(newLayout)
.setImage(image)
.setSubresourceRange({
vk::ImageAspectFlagBits::eColor,
0, 1, 0, 1
});
vk::DependencyInfo dependencyInfo;
dependencyInfo.setImageMemoryBarriers(barrier);
cmd.pipelineBarrier2(dependencyInfo);
}
} // namespace Engine