FrameGraph 资源生命周期与渲染管线对比

在 Vulkan 和 Direct3D 12 中,手动维护 RenderTarget 生命周期与 VkImageMemoryBarrier 很容易漏掉读写同步或产生冗余屏障。把每帧的 Pass 组织为有向无环图(FrameGraph),可以在编译期自动裁剪无引用的 Pass、复用瞬态显存并集中计算管线屏障。

光照着色阶段的微表面方程推导见 [[PBR 微表面 BRDF 与能量守恒推导]],渲染模块的静态库依赖隔离见 [[CMake Target 依赖传递与属性速查]]。

实时渲染管线带宽与特性对比

管线类型G-Buffer 带宽开销多光源扩展性MSAA 支持着色灵活性适用场景
Forward低(直接写 Color/Depth)差 O(Nmesh×Nlight)O(N_{\text{mesh}} \times N_{\text{light}})原生支持高(可按材质定制 Shader)移动端场景、半透明物体
Clustered Forward+较低(需 Depth Pre-pass)好(按三维簇剔除光源)原生支持高(存在寄存器占用压力)VR、高帧率场景
Standard Deferred高(3~4 张 MRT 读写)好(屏幕空间解耦)差(依赖 TAA/FSR)受限于 G-Buffer 通道数PC 与主机写实场景
Visibility Buffer低(仅存 PrimitiveID / InstanceID)好(Compute 分类着色)配合时域超分高(消除 Quad Overdraw)虚拟几何体管线

FrameGraph 执行阶段

flowchart LR
    Setup["Setup\n声明读写纹理与 Buffer"] --> Compile["Compile\n引用计数裁剪与拓扑排序"]
    Compile --> Alias["Memory Aliasing\n瞬态资源显存池复用"]
    Alias --> Barrier["Barrier 计算\n合并生成 PipelineBarrier"]
    Barrier --> Exec["Execute\n录制 CommandBuffer"]

RenderPass 声明接口示例

每个 Pass 在 setup 阶段只声明自己读写的虚拟资源句柄和期望的 ResourceState,不直接分配底层 VkImage:

void DeferredLightingPass::setup(FrameGraphBuilder& builder, PassData& data) {
    data.gbufferAlbedo = builder.read(m_blackboard.get<FGTexture>("GBufferAlbedo"), ResourceState::ShaderResource);
    data.gbufferNormal = builder.read(m_blackboard.get<FGTexture>("GBufferNormal"), ResourceState::ShaderResource);
    data.depthStencil  = builder.read(m_blackboard.get<FGTexture>("SceneDepth"),    ResourceState::DepthRead);

    FGTextureDesc hdrDesc{};
    hdrDesc.width  = m_viewport.width;
    hdrDesc.height = m_viewport.height;
    hdrDesc.format = PixelFormat::RGBA16_FLOAT;

    data.sceneHdrColor = builder.create<FGTexture>("SceneHDRColor", hdrDesc);
    data.sceneHdrColor = builder.write(data.sceneHdrColor, ResourceState::RenderTarget);
}