// // Created by atdunbg on 2026/9/20. // // Renderer:编排者。pass 实现在 Passes::*,场景理解在 SceneRenderer, // 本文件只做装配、资源声明与每帧编排——新增渲染效果不需要改这里 // (除非要加新的 RG 资源或注册新 pass)。 // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Engine { Renderer::Renderer(Window& window) : m_Window(window) { // 1. Device / Allocator / Descriptor / Shader m_Device = CreateScope(window); m_Allocator = CreateScope(*m_Device); m_DescriptorManager = CreateScope(*m_Device); m_ShaderManager = CreateScope(*m_Device); // 2. Per-frame ring:UBO + GPUDriven 实例 SSBO(当前/上一帧, // 同一 ring 类,SSBO 只是 usage 不同;正确性保证一致) m_UniformBuffer = CreateScope( *m_Device, *m_Allocator, sizeof(UniformBufferObject), kMaxFramesInFlight); m_ObjectBuffer = CreateScope( *m_Device, *m_Allocator, sizeof(glm::mat4) * kMaxInstances, kMaxFramesInFlight, vk::BufferUsageFlagBits::eStorageBuffer); m_PrevObjectBuffer = CreateScope( *m_Device, *m_Allocator, sizeof(glm::mat4) * kMaxInstances, kMaxFramesInFlight, vk::BufferUsageFlagBits::eStorageBuffer); // 3. pass 装配体:布局/shader/采样器/per-slot 描述符 m_SceneGpu = CreateScope( *m_Device, *m_DescriptorManager, *m_ShaderManager, *m_UniformBuffer, *m_ObjectBuffer, *m_PrevObjectBuffer); m_FullscreenGpu = CreateScope( *m_Device, *m_DescriptorManager, *m_ShaderManager); // 4. Swapchain(只管呈现;渲染目标统一归 RenderGraph) m_Swapchain = CreateScope(*m_Device, *m_Allocator, m_Window); m_Extent = m_Swapchain->GetExtent(); // 5. Sync / Command(per-frame) m_SyncManager = CreateScope( *m_Device, kMaxFramesInFlight, m_Swapchain->GetImageCount()); m_CommandManager = CreateScope(*m_Device, kMaxFramesInFlight); // 6. 场景翻译层(pass 经引用读取 FrameSceneData,必须先于 BuildGraph) m_SceneRenderer = CreateScope(); // 7. 资产上传服务(渲染层对外提供的 IAssetUploader 实现) m_AssetUploader = CreateScope( *m_Device, *m_Allocator, *m_DescriptorManager, m_SceneGpu->textureSetLayout); // 8. RenderGraph:资源声明 + pass 注册 + 首次编译 m_PostParams = CreateScope(); BuildGraph(); // 首次编译后物理镜像就位:各 pass 绑定自己的输入描述符 for (auto& pass : m_Passes) { pass->OnTargetsRebuilt(*m_RenderGraph); } // 9. GPU timestamp:每 pass 两枚(前后),按帧槽位分区 m_QueriesPerFrame = static_cast(m_RenderGraph->GetPassCount()) * 2; m_PassNames = m_RenderGraph->GetPassNames(); m_PassGpuMs.assign(m_RenderGraph->GetPassCount(), 0.0f); vk::QueryPoolCreateInfo qpInfo; qpInfo.setQueryType(vk::QueryType::eTimestamp) .setQueryCount(m_QueriesPerFrame * kMaxFramesInFlight); m_QueryPool = m_Device->GetDevice().createQueryPool(qpInfo); m_RenderGraph->SetQueryPool(m_QueryPool, m_QueriesPerFrame); m_TimestampPeriod = static_cast( m_Device->GetPhysicalDevice().getProperties().limits.timestampPeriod); ENGINE_INFO("Renderer initialized"); } Renderer::~Renderer() { // 必须等 GPU 空闲再析构成员(pass/RG/装配体都会销毁 GPU 对象) m_Device->GetDevice().waitIdle(); if (m_QueryPool) { m_Device->GetDevice().destroyQueryPool(m_QueryPool); } } vk::DescriptorSetLayout Renderer::GetTextureSetLayout() const { return m_SceneGpu->textureSetLayout; } vk::Format Renderer::GetSwapchainFormat() const { return m_Swapchain->GetFormat(); } u32 Renderer::GetSwapchainImageCount() const { return m_Swapchain->GetImageCount(); } Assets::IAssetUploader& Renderer::GetAssetUploader() const { return *m_AssetUploader; } f32 Renderer::GetExposure() const { return m_PostParams->exposure; } void Renderer::SetExposure(f32 e) { m_PostParams->exposure = e; } bool Renderer::GetUseACES() const { return m_PostParams->useACES; } void Renderer::SetUseACES(bool b) { m_PostParams->useACES = b; } f32 Renderer::GetBloomThreshold() const { return m_PostParams->bloomThreshold; } void Renderer::SetBloomThreshold(f32 v) { m_PostParams->bloomThreshold = v; } f32 Renderer::GetBloomStrength() const { return m_PostParams->bloomStrength; } void Renderer::SetBloomStrength(f32 v) { m_PostParams->bloomStrength = v; } bool Renderer::GetShowTemporalDiff() const { return m_PostParams->showTemporalDiff; } void Renderer::SetShowTemporalDiff(bool b) { m_PostParams->showTemporalDiff = b; } u32 Renderer::GetMainInstanceCount() const { return m_SceneRenderer->GetMainInstanceCount(); } u32 Renderer::GetShadowInstanceCount() const { return m_SceneRenderer->GetShadowInstanceCount(); } void Renderer::BuildGraph() { m_RenderGraph = CreateScope( *m_Device, *m_Allocator, kMaxFramesInFlight); // ---- 资源声明(命名资源;pass 经句柄引用,数据流由 uses 决定)---- // 导入 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}); // CSM 级联阴影图:每级联独立 1024² 正交深度图(D32 采样), // 范围由 SceneRenderer::ComputeCascades 按相机视锥切片拟合 for (u32 c = 0; c < kMaxCascades; ++c) { m_ShadowMaps[c] = m_RenderGraph->CreateTexture( "ShadowMap" + std::to_string(c), RG::TextureDesc{vk::Format::eD32Sfloat, kCascadeRes, kCascadeRes}); } // HDR 颜色图:Forward 的输出(线性光照值 + 抖动),TAA 显式完成 // 时域累积后写入 TAAColor(对齐 UE/Unity 管线) m_HDRColor = m_RenderGraph->CreateTexture( "HDRColor", RG::TextureDesc{vk::Format::eR16G16B16A16Sfloat}); // velocity:clip 空间运动向量(TAA 反推历史像素位置) m_Velocity = m_RenderGraph->CreateTexture( "Velocity", RG::TextureDesc{vk::Format::eR16G16B16A16Sfloat}); // TAA 累积输出:既是 resolve 结果也是下一帧的历史(自引用) m_TAAColor = m_RenderGraph->CreateTexture( "TAAColor", RG::TextureDesc{vk::Format::eR16G16B16A16Sfloat}); // Bloom ping-pong:半分辨率(sizeScale 相对目标尺寸,resize 自动跟随) m_BloomA = m_RenderGraph->CreateTexture( "BloomA", RG::TextureDesc{vk::Format::eR16G16B16A16Sfloat, 0, 0, 0.5f}); m_BloomB = m_RenderGraph->CreateTexture( "BloomB", RG::TextureDesc{vk::Format::eR16G16B16A16Sfloat, 0, 0, 0.5f}); // 帧历史差异(调试视图):|上一帧 − 当前帧| × 增益。 // 帧历史机制(ReadHistory)的验证消费端,也是 TAA 的参考形态 m_TemporalDiff = m_RenderGraph->CreateTexture( "TemporalDiff", RG::TextureDesc{vk::Format::eR16G16B16A16Sfloat, 0, 0, 0.5f}); // ---- pass 注册:执行序由拓扑排序决定,与注册顺序无关 ---- // 要加新 pass:new 一个 RenderPass 子类,在这里 push 一行。 FrameSceneData& frame = m_SceneRenderer->Frame(); m_Passes.push_back(CreateScope( *m_SceneGpu, frame, m_ShadowMaps)); m_Passes.push_back(CreateScope( *m_SceneGpu, frame, m_HDRColor, m_Velocity, m_Depth, m_ShadowMaps)); m_Passes.push_back(CreateScope( *m_FullscreenGpu, /*historyAlpha*/ 0.9f, m_HDRColor, m_Velocity, m_TAAColor)); m_Passes.push_back(CreateScope( *m_FullscreenGpu, /*gain*/ 8.0f, m_HDRColor, m_TemporalDiff)); m_Passes.push_back(CreateScope( *m_FullscreenGpu, *m_PostParams, m_TAAColor, m_BloomA, m_BloomB)); m_Passes.push_back(CreateScope( *m_FullscreenGpu, *m_PostParams, m_TAAColor, m_BloomA, m_TemporalDiff, m_Backbuffer)); m_Passes.push_back(CreateScope( &m_ImGuiLayer, m_Backbuffer)); m_Passes.push_back(CreateScope(m_Backbuffer)); for (auto& pass : m_Passes) { pass->Register(*m_RenderGraph); } m_RenderGraph->SetTargetExtent(m_Extent); // 触发首次 Compile } void Renderer::SetVSync(bool vsync) { if (m_Swapchain->GetVSync() == vsync) return; m_Swapchain->SetVSync(vsync); HandleResize(); // present mode 变化需要重建 swapchain } void Renderer::HandleResize() { m_Device->GetDevice().waitIdle(); m_Swapchain->Recreate(m_Window); m_Extent = m_Swapchain->GetExtent(); // image 数量可能变化 m_SyncManager = CreateScope( *m_Device, kMaxFramesInFlight, m_Swapchain->GetImageCount()); // RG 重编译:物理镜像按新尺寸轮换,各 pass 重绑输入描述符 m_RenderGraph->SetTargetExtent(m_Extent); for (auto& pass : m_Passes) { pass->OnTargetsRebuilt(*m_RenderGraph); } } void Renderer::ReadGpuTimes(u32 frameSlot) { if (!m_QueryPool || m_QueriesPerFrame == 0) return; // 每槽位首帧:该区间的查询尚未被 reset/写入,跳过一次读取 if (!m_TimesPrimed[frameSlot]) { m_TimesPrimed[frameSlot] = true; return; } const u32 passCount = m_QueriesPerFrame / 2; std::vector ticks(m_QueriesPerFrame, 0); // fence 已等待本槽位上一轮完成,结果必然可用(阻塞式 + 64bit) const vk::Result r = m_Device->GetDevice().getQueryPoolResults( m_QueryPool, frameSlot * m_QueriesPerFrame, m_QueriesPerFrame, sizeof(u64) * m_QueriesPerFrame, ticks.data(), sizeof(u64), vk::QueryResultFlagBits::e64 | vk::QueryResultFlagBits::eWait); if (r != vk::Result::eSuccess) return; for (u32 i = 0; i < passCount; ++i) { const u64 start = ticks[i * 2]; const u64 end = ticks[i * 2 + 1]; m_PassGpuMs[i] = (end >= start) ? static_cast(end - start) * m_TimestampPeriod / 1.0e6f : 0.0f; } } void Renderer::Render(ECS::Scene& scene, Assets::AssetManager& assets) { ZoneScoped; // CPU 侧:UBO/SSBO 上传 + 录制 + 提交(GPU 耗时见 RG timestamp) if (m_Window.WasResized()) { m_Window.ResetResizedFlag(); HandleResize(); } const u32 frameSlot = m_CurrentFrame; const auto& vkDevice = m_Device->GetDevice(); // 1. 场景 → 当帧渲染数据(相机/灯光/双视图剔除;纯 CPU,不碰 GPU) if (!m_SceneRenderer->BuildFrame(scene, assets, m_Extent)) { return; // 无 primary 相机:跳帧 } const FrameSceneData& frame = m_SceneRenderer->Frame(); // 2. 等本槽位 fence → 写 UBO/SSBO → reset(写-读竞争关闭) m_SyncManager->WaitFence(frameSlot); ReadGpuTimes(frameSlot); // fence 已等:上一轮该槽位的查询已就绪 m_UniformBuffer->Update(frameSlot, &frame.ubo, sizeof(frame.ubo)); m_SyncManager->ResetFence(frameSlot); if (!frame.instanceModels.empty()) { m_ObjectBuffer->Update(frameSlot, frame.instanceModels.data(), frame.instanceModels.size() * sizeof(glm::mat4)); // 上一帧姿态与当前帧平行对齐(velocity 顶点着色器按下标取) m_PrevObjectBuffer->Update(frameSlot, frame.prevInstanceModels.data(), frame.prevInstanceModels.size() * sizeof(glm::mat4)); } // 3. acquire swapchain image u32 imageIndex = 0; try { const auto result = vkDevice.acquireNextImageKHR( m_Swapchain->Get(), std::numeric_limits::max(), m_SyncManager->GetImageAvailable(frameSlot)); if (result.result == vk::Result::eErrorOutOfDateKHR) { HandleResize(); return; } imageIndex = result.value; } catch (const vk::OutOfDateKHRError&) { HandleResize(); return; } // 4. 录制:FrameContext + RenderGraph FrameContext frameCtx; frameCtx.frameSlot = frameSlot; frameCtx.imageIndex = imageIndex; frameCtx.cmd = m_CommandManager->BeginFrame(frameSlot); m_RenderGraph->SetImportedImage( m_Backbuffer, m_Swapchain->GetImages()[imageIndex], m_Swapchain->GetImageViews()[imageIndex]); m_RenderGraph->Execute(frameCtx); m_CommandManager->EndFrame(frameSlot); // 5. 提交 std::array waitStages = { vk::PipelineStageFlagBits::eColorAttachmentOutput }; std::array waitSemaphores = { m_SyncManager->GetImageAvailable(frameSlot) }; std::array signalSemaphores = { m_SyncManager->GetRenderFinished(imageIndex) }; vk::SubmitInfo submitInfo; submitInfo.setCommandBuffers(frameCtx.cmd) .setWaitSemaphores(waitSemaphores) .setWaitDstStageMask(waitStages) .setSignalSemaphores(signalSemaphores); m_Device->GetGraphicsQueue().submit( submitInfo, m_SyncManager->GetFrameFence(frameSlot)); // 6. 呈现 std::array swapchains = {m_Swapchain->Get()}; std::array presentWait = { m_SyncManager->GetRenderFinished(imageIndex) }; vk::PresentInfoKHR presentInfo; presentInfo.setImageIndices(imageIndex) .setSwapchains(swapchains) .setWaitSemaphores(presentWait); try { const auto result = m_Device->GetPresentQueue().presentKHR(presentInfo); if (result == vk::Result::eSuboptimalKHR) { HandleResize(); } } catch (const vk::OutOfDateKHRError&) { HandleResize(); } m_CurrentFrame = (m_CurrentFrame + 1) % kMaxFramesInFlight; } } // namespace Engine