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:
+287
-373
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user