feat: ImGui 叠加层接入 RenderGraph(docking 分支,dynamic rendering)
框架与 UI 的职责边界: - ImGuiLayer(Engine/ImGui):只做管线桥接——上下文初始化、 NewFrame/BuildDrawData、draw data 录入 cmd;框架自身永不绘制 任何 ImGui 控件,UI 内容全部由派生类在 OnRenderOverlay() 定义 - 每帧顺序:NewFrame → OnRenderOverlay(声明控件)→ BuildDrawData → Renderer.Render(RG: Forward → ImGui(loadOp=Load 叠加) → Present) - ImGui pass 常驻 RG,未启用叠加层时空转,无图结构开销 - 后端共存:VK_EXT_shader_object 引擎无 vk::Pipeline,ImGui 用 UseDynamicRendering + PipelineInfoMain.PipelineRenderingCreateInfo (swapchain 格式),不需要 RenderPass - 析构序:ImGuiLayer 在 Application 成员序中后声明(先于 Renderer 析构),析构内 waitIdle 保证后端资源安全销毁 App 示例(证明职责边界):Scene Debug 面板实时拖动阴影光方向, ` 键反折叠加层
This commit is contained in:
@@ -9,10 +9,12 @@
|
||||
// 和事件钩子(OnEvent + 类型化事件)定义程序行为;
|
||||
// runtime、editor 等不同程序形态只是不同的派生类。
|
||||
//
|
||||
// 主循环固定为:PollEvents → OnUpdate(dt) → [主渲染 → OnRenderOverlay] → 判退出。
|
||||
// 主渲染(Renderer.Render(scene))是框架行为,派生类不可覆盖也不会丢失;
|
||||
// 派生类的渲染扩展(ImGui/调试视图/编辑器叠加层)走 OnRenderOverlay,
|
||||
// 在主渲染之后、Present 之前执行,不覆写则什么都不发生。
|
||||
// 主循环固定为:PollEvents → OnUpdate(dt) → [NewFrame → OnRenderOverlay →
|
||||
// BuildDrawData] → 主渲染(Renderer.Render)→ 判退出。
|
||||
// UI 构建与 GPU 提交分离:OnRenderOverlay 只"声明"控件,真正的 draw data
|
||||
// 提交发生在主渲染管线中的 ImGui pass(Forward 之后、Present 之前,
|
||||
// loadOp=Load 叠加)。主渲染是框架行为,派生类不可覆盖也不会丢失;
|
||||
// 框架自身永远不绘制任何 ImGui 控件——UI 内容全部由派生类定义。
|
||||
// dt 由框架统一计时(含首帧与卡顿钳制),派生层无需自己管理。
|
||||
//
|
||||
|
||||
@@ -28,6 +30,7 @@ namespace Engine {
|
||||
|
||||
class Window;
|
||||
class Renderer;
|
||||
class ImGuiLayer;
|
||||
|
||||
namespace ECS { class Scene; }
|
||||
namespace Assets { class AssetManager; }
|
||||
@@ -46,6 +49,11 @@ namespace Engine {
|
||||
// 请求退出(当帧结束后生效)
|
||||
void Close() { m_Running = false; }
|
||||
|
||||
// 启用 ImGui 叠加层(OnInit 内调用)。启用后每帧:
|
||||
// NewFrame → OnRenderOverlay(派生类画控件)→ BuildDrawData →
|
||||
// 主渲染(ImGui pass 把 draw data 叠加到场景上)。
|
||||
void EnableImGui();
|
||||
|
||||
// ---- 供派生类访问的模块 ----
|
||||
Window& GetWindow() const { return *m_Window; }
|
||||
Renderer& GetRenderer() const { return *m_Renderer; }
|
||||
@@ -92,6 +100,9 @@ namespace Engine {
|
||||
Scope<ECS::Scene> m_Scene;
|
||||
Scope<Renderer> m_Renderer;
|
||||
Scope<Assets::AssetManager> m_Assets;
|
||||
// 注意成员序:ImGuiLayer 必须后声明(先于 Renderer/Window 析构,
|
||||
// 其后端销毁需要 Device 与 GLFWwindow 存活)
|
||||
Scope<ImGuiLayer> m_ImGuiLayer;
|
||||
|
||||
bool m_Running = false;
|
||||
f32 m_DeltaTime = 0.0f;
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
//
|
||||
// Created by atdunbg on 2026/9/22.
|
||||
//
|
||||
// ImGuiLayer:ImGui 与 Vulkan/RenderGraph 的桥接层。
|
||||
//
|
||||
// 职责边界(重要):
|
||||
// - 本层只做"管线级"工作:上下文初始化、每帧 NewFrame、
|
||||
// draw data 构建、把 draw data 录进给定的 command buffer。
|
||||
// - 本层永远不创建任何 ImGui 窗口/控件(框架不渲染 UI 内容);
|
||||
// 所有 UI 内容由派生类在 OnRenderOverlay() 里自行绘制。
|
||||
// - GPU 提交由 Renderer 的 "ImGui" RG pass 调 RenderDrawData 完成
|
||||
// (Forward 之后、Present 之前,loadOp=Load 叠加在场景上)。
|
||||
//
|
||||
|
||||
#ifndef HELLOVULKAN_IMGUI_LAYER_H
|
||||
#define HELLOVULKAN_IMGUI_LAYER_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Engine/Core/Types.h>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
namespace Engine {
|
||||
|
||||
class Window;
|
||||
class Renderer;
|
||||
class Device;
|
||||
|
||||
class ImGuiLayer {
|
||||
public:
|
||||
// 需要 Renderer 就绪后创建(依赖 Device + swapchain 格式)
|
||||
ImGuiLayer(Window& window, Renderer& renderer);
|
||||
~ImGuiLayer();
|
||||
|
||||
ImGuiLayer(const ImGuiLayer&) = delete;
|
||||
ImGuiLayer& operator=(const ImGuiLayer&) = delete;
|
||||
|
||||
// ---- 每帧三段式(由 Application::Run 驱动)----
|
||||
|
||||
// 开始 UI 构建(ImGui::NewFrame)。此后到 BuildDrawData 之间,
|
||||
// 派生类可任意调用 ImGui::* 绘制控件。
|
||||
void NewFrame();
|
||||
|
||||
// 结束 UI 构建:把本帧的控件调用编译成 draw data(ImGui::Render)。
|
||||
void BuildDrawData();
|
||||
|
||||
// 把 draw data 录入 cmd(RG ImGui pass 内调用)。
|
||||
// 无 UI 内容时 draw data 为空,是合法 no-op。
|
||||
void RenderDrawData(vk::CommandBuffer cmd);
|
||||
|
||||
bool IsEnabled() const { return m_Enabled; }
|
||||
void SetEnabled(bool enabled) { m_Enabled = enabled; }
|
||||
|
||||
private:
|
||||
// 生命周期保证:Application 成员序中 ImGuiLayer 在 Renderer 之后声明
|
||||
//(先析构),因此 Device 引用在整个层生命周期内有效
|
||||
Device& m_Device;
|
||||
vk::DescriptorPool m_Pool;
|
||||
bool m_Enabled = true;
|
||||
};
|
||||
|
||||
} // namespace Engine
|
||||
|
||||
#endif //HELLOVULKAN_IMGUI_LAYER_H
|
||||
@@ -30,6 +30,7 @@ namespace Engine {
|
||||
|
||||
namespace ECS { class Scene; }
|
||||
namespace Assets { class AssetManager; }
|
||||
class ImGuiLayer;
|
||||
|
||||
// Renderer 职责(收敛后):
|
||||
// 1. 装配底层模块(Device/Swapchain/Sync/Command/Descriptor/Shader)
|
||||
@@ -52,6 +53,12 @@ namespace Engine {
|
||||
MemoryAllocator& GetAllocator() const { return *m_Allocator; }
|
||||
DescriptorManager& GetDescriptorManager() const { return *m_DescriptorManager; }
|
||||
vk::DescriptorSetLayout GetTextureSetLayout() const { return m_TextureSetLayout; }
|
||||
vk::Format GetSwapchainFormat() const; // Swapchain 不完整,实现在 cpp
|
||||
u32 GetSwapchainImageCount() const;
|
||||
|
||||
// 可选叠加层(ImGui):不设置则 RG 里的 ImGui pass 为空转。
|
||||
// 生命周期:层必须先于 Renderer 析构(Application 成员序保证)。
|
||||
void SetImGuiLayer(ImGuiLayer* layer) { m_ImGuiLayer = layer; }
|
||||
|
||||
private:
|
||||
void BuildGraph(); // 声明 pass 结构 + 首次 Compile
|
||||
@@ -99,6 +106,9 @@ namespace Engine {
|
||||
Assets::AssetManager* m_BoundAssets = nullptr;
|
||||
glm::mat4 m_LightSpace{1.0f}; // 阴影光源 VP(每帧由 Render 算好)
|
||||
|
||||
// 可选叠加层(不拥有;Application 持有)
|
||||
ImGuiLayer* m_ImGuiLayer = nullptr;
|
||||
|
||||
vk::Extent2D m_Extent{};
|
||||
u32 m_CurrentFrame = 0;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user