6.6 KiB
Render Graph: Per‑Frame Scheduling, Barriers, and Dynamic Rendering
Lightweight render graph that builds a per‑frame DAG from pass declarations, computes the necessary resource barriers/layout transitions, and records passes with dynamic rendering when attachments are declared.
Why
- Centralize synchronization and image layout transitions across passes.
- Make passes declarative: author declares reads/writes; the graph inserts barriers and begins/ends rendering.
- Keep existing pass classes (
IRenderPass) while migrating execution to the graph.
High‑Level Flow
- Engine creates the graph each frame and imports swapchain/G‑Buffer images:
src/core/vk_engine.cpp:303. - Each pass registers its work by calling
register_graph(graph, ...)and declaring resources via a builder. - The graph appends a present chain (copy HDR
drawImage→ swapchain, then transition toPRESENT), optionally inserting ImGui before present. compile()topologically sorts passes by data dependencies (read/write) and computes per‑pass barriers.execute(cmd)emits barriers, begins dynamic rendering if attachments were declared, calls the pass record lambda, and ends rendering.
Core API
-
RenderGraph::add_pass(name, RGPassType type, BuildCallback build, RecordCallback record)- Declare image/buffer accesses and attachments inside
buildusingRGPassBuilder. - Do your actual rendering/copies in
recordusing resolved Vulkan objects fromRGPassResources. - See:
src/render/rg_graph.h:36,src/render/rg_graph.cpp:51.
- Declare image/buffer accesses and attachments inside
-
RenderGraph::compile()→ builds ordering and per‑passVk*MemoryBarrier2lists. Seesrc/render/rg_graph.cpp:83. -
RenderGraph::execute(cmd)→ emits barriers and dynamic rendering begin/end. Seesrc/render/rg_graph.cpp:592. -
Import helpers for engine images:
import_draw_image(),import_depth_image(),import_gbuffer_*(),import_swapchain_image(index). Seesrc/render/rg_graph.cpp:740. -
Present chain:
add_present_chain(draw, swapchain, appendExtra)inserts Copy→Present passes and lets you inject extra passes (e.g., ImGui) in between. Seesrc/render/rg_graph.cpp:705.
Declaring a Pass
Use register_graph(...) on your pass to declare resources and record work. The graph handles transitions and dynamic rendering.
void MyPass::register_graph(RenderGraph* graph,
RGImageHandle draw,
RGImageHandle depth) {
graph->add_pass(
"MyPass",
RGPassType::Graphics,
// Build: declare resources + attachments
[draw, depth](RGPassBuilder& b, EngineContext*) {
b.read(draw, RGImageUsage::SampledFragment); // example read
b.write_color(draw); // render target
b.write_depth(depth, /*clear*/ false); // depth test
},
// Record: issue Vulkan commands (no begin/end rendering needed)
[this, draw](VkCommandBuffer cmd, const RGPassResources& res, EngineContext* ctx) {
VkPipeline p{}; VkPipelineLayout l{};
ctx->pipelines->getGraphics("my_pass", p, l); // hot‑reload safe
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, p);
VkViewport vp{0,0,(float)ctx->getDrawExtent().width,(float)ctx->getDrawExtent().height,0,1};
vkCmdSetViewport(cmd, 0, 1, &vp);
VkRect2D sc{{0,0}, ctx->getDrawExtent()};
vkCmdSetScissor(cmd, 0, 1, &sc);
vkCmdDraw(cmd, 3, 1, 0, 0);
}
);
}
Builder Reference (RGPassBuilder)
-
Images
read(RGImageHandle, RGImageUsage)→ sample/read usage for this pass.write(RGImageHandle, RGImageUsage)→ write usage (compute/storage/transfer).write_color(RGImageHandle, bool clearOnLoad=false, VkClearValue clear={})→ declares a color attachment.write_depth(RGImageHandle, bool clearOnLoad=false, VkClearValue clear={})→ declares a depth attachment.
-
Buffers
read_buffer(RGBufferHandle, RGBufferUsage)/write_buffer(RGBufferHandle, RGBufferUsage).- Convenience import:
read_buffer(VkBuffer, RGBufferUsage, size, name)andwrite_buffer(VkBuffer, ...)dedup by raw handle.
See src/render/rg_builder.h:39 and impl in src/render/rg_builder.cpp:20.
Resource Model (RGResourceRegistry)
- Imported vs transient resources are tracked uniformly with lifetime indices (
firstUse/lastUse). - Imports are deduplicated by
VkImage/VkBufferand keep initial layout/stage/access as the starting state. - Transients are created via
ResourceManagerand auto‑destroyed at end of frame using the frame deletion queue. - See
src/render/rg_resources.h:11andsrc/render/rg_resources.cpp:1.
Synchronization and Layouts
- For each pass,
compile()compares previous state with desired usage and, if needed, adds a pre‑pass barrier:- Images:
VkImageMemoryBarrier2with stage/access/layout derived fromRGImageUsage. - Buffers:
VkBufferMemoryBarrier2with stage/access derived fromRGBufferUsage.
- Images:
- Initial state comes from the imported descriptor; if unknown, buffers default to
TOP_OF_PIPE. - Format/usage checks:
- Warns if binding a depth format as color (and vice‑versa).
- Warns if a transient resource is used with flags it wasn’t created with.
Image usage → layout/stage examples (subset):
SampledFragment→SHADER_READ_ONLY_OPTIMAL,FRAGMENT_SHADER.ColorAttachment→COLOR_ATTACHMENT_OPTIMAL,COLOR_ATTACHMENT_OUTPUT(read|write).DepthAttachment→DEPTH_ATTACHMENT_OPTIMAL,EARLY|LATE_FRAGMENT_TESTS.TransferDst→TRANSFER_DST_OPTIMAL,TRANSFER.Present→PRESENT_SRC_KHR,BOTTOM_OF_PIPE.
Buffer usage → stage/access examples:
IndexRead→INDEX_INPUT,INDEX_READ.VertexRead→VERTEX_INPUT,VERTEX_ATTRIBUTE_READ.UniformRead→ALL_GRAPHICS|COMPUTE,UNIFORM_READ.StorageReadWrite→COMPUTE|FRAGMENT,SHADER_STORAGE_READ|WRITE.
Built‑In Pass Wiring (Current)
- Resource uploads (if any) → Background (compute) → Geometry (G‑Buffer) → Lighting (deferred) → Transparent → CopyToSwapchain → ImGui → PreparePresent.
- See registrations:
src/core/vk_engine.cpp:321–src/core/vk_engine.cpp:352.
Notes & Limits
- No aliasing or transient pooling yet; images created via
create_*are released end‑of‑frame. - Graph scheduling uses a topological order by data dependency; it does not parallelize across queues.
- Load/store control for attachments is minimal (
clearOnLoad,storeonRGAttachmentInfo). - Render area is the min of all declared attachment extents and
EngineContext::drawExtent.
Debugging
- Each pass is wrapped with a debug label (
RG: <name>). - Compile prints warnings for suspicious usages or format mismatches.