feat: Tracy GPU 时间线——RG pass 级 GPU zone

RenderGraph 新增 IGpuProfiler 可选注入(pass 边界 Begin/End 钩子 +
帧尾 Collect,zone 覆盖 barrier+lambda+postBarriers),RG 本体不感知
任何 profiler 实现。Renderer 侧 TracyGpuProfiler 实现:TracyVkContext
(校准用临时 cb,池必须带 RESET_COMMAND_BUFFER_BIT——tracy 校准流程
对同一 cb 连续 begin 三次)+ TracyVkZoneTransient(pass 名是运行时
字符串)。TRACY_ENABLE 关闭全链路退化为空。

用法:Tracy GUI(0.14.1 配对)连接后按 pass 名看 GPU 段时间线,
与 ImGui 数表互补;LOD 调优的测量前置。
This commit is contained in:
2026-09-24 19:45:17 +08:00
parent 99e6712cdf
commit 3bfe28b027
6 changed files with 182 additions and 0 deletions
@@ -260,6 +260,24 @@ namespace Engine::RG {
// pool 由调用方创建(容量 ≥ framesInFlight × queriesPerFrame),
// 读取由调用方在本槽位 fence 等待之后进行。
void SetQueryPool(vk::QueryPool pool, u32 queriesPerFrame);
// GPU profiler(可选):pass 边界的 GPU zone 钩子(Tracy 等工具的
// 接缝,RG 本体不感知任何 profiler 实现)。BeginPass 返回的 scope
// 析构 = 结束时间戳;注入者须保证 scope 生命周期覆盖 pass lambda。
// EndFrame 在全部 pass 录制完后调用(仍在当帧 cmd 内,提交前)。
class IGpuProfiler {
public:
virtual ~IGpuProfiler() = default;
class IScope {
public:
virtual ~IScope() = default;
};
[[nodiscard]] virtual Scope<IScope> BeginPass(
const char* name, vk::CommandBuffer cmd) = 0;
virtual void EndFrame(vk::CommandBuffer cmd) = 0;
};
void SetGpuProfiler(IGpuProfiler* profiler) { m_GpuProfiler = profiler; }
std::vector<std::string> GetPassNames() const;
// ---- 统计 ----
@@ -314,6 +332,7 @@ namespace Engine::RG {
// GPU timestamp(可选注入)
vk::QueryPool m_QueryPool{};
u32 m_QueriesPerFrame = 0;
IGpuProfiler* m_GpuProfiler = nullptr; // 非拥有(Renderer 持有)
// 物理资源池:key = (format, extent, usage),value = 空闲镜像列表
struct PoolKey {
@@ -44,6 +44,7 @@ namespace Engine {
class Cubemap;
class IblGenerator;
class ImGuiLayer;
class TracyGpuProfiler;
namespace ECS { class Scene; }
namespace Assets { class AssetManager; class IAssetUploader; }
@@ -172,6 +173,9 @@ namespace Engine {
std::vector<f32> m_PassGpuMs; // 最近一帧各 pass 耗时
bool m_TimesPrimed[2] = {false, false}; // 每槽位首帧跳过读取
// Tracy GPU 时间线(pass zone;TRACY_ENABLE 关闭时空实现)
Scope<TracyGpuProfiler> m_TracyProfiler;
vk::Extent2D m_Extent{};
u32 m_CurrentFrame = 0;
};
@@ -0,0 +1,41 @@
//
// Created by atdunbg on 2026/9/24.
//
// TracyGpuProfiler:RG::IGpuProfiler 的 Tracy Vulkan 实现。
//
// 每个 RG pass 在 GPU 时间线里是一个 zone(TracyVkZoneTransient,运行时
// 名字),时间戳在命令录制期写入当帧 cmd,TracyVkCollect 在帧尾解析。
// TRACY_ENABLE 关闭时退化为空实现(零开销)。
//
// 时间戳未做 CPU/GPU 校准(TracyVkContext 非 calibrated 变体):
// Tracy 按收集批次对齐,长时间运行的漂移可后续升级 Calibrated 变体。
//
#ifndef HELLOVULKAN_TRACYGPUPROFILER_H
#define HELLOVULKAN_TRACYGPUPROFILER_H
#include <Engine/RenderGraph/RenderGraph.h>
namespace Engine {
class Device;
class TracyGpuProfiler final : public RG::RenderGraph::IGpuProfiler {
public:
explicit TracyGpuProfiler(Device& device);
~TracyGpuProfiler() override;
TracyGpuProfiler(const TracyGpuProfiler&) = delete;
TracyGpuProfiler& operator=(const TracyGpuProfiler&) = delete;
[[nodiscard]] Scope<IScope> BeginPass(const char* name,
vk::CommandBuffer cmd) override;
void EndFrame(vk::CommandBuffer cmd) override;
private:
class ScopeImpl;
void* m_Ctx{}; // tracy::VkCtx*(TracyVulkan.hpp 只在实现内 include)
};
} // namespace Engine
#endif //HELLOVULKAN_TRACYGPUPROFILER_H