Frame Graph
/Recently I've been looking at a better way to handle the renderer architecture of the engine. After looking at Frostbite's implementation I decided to go with a render graph approach. The render graph architecture consists of three main classes; CRenderGraph ( a transient graph generated every frame that contains the render target for resolve and all of the player views) , and CPipelineStage (represents a single rendering pass) , and IPooledRenderTarget ( a render target from the pool).
The render graph has three phases; stage generation , resource compilation , and stage execution.
Stage Generation
In this phase, the render graph determines the stages that will be needed for the frame. For example; in debug mode the user will want to render debug geometry, so the "CDebugDrawStage" is registered with the frame graph; and if running in deferred shading mode, the CSceneGBufferStage and CTiledLightingStages are registered.
Example of Stage generation for deferred lighting render graph.
Resource Compilation
In the resource compilation phase, render stages register with the render graph the temporary resources they require. These resources can be structured buffers, render targets, etc. After all of the resources have been collected, the render graph determines the ordering of the stages and the point for the most optimum resource transitions (for vulkan and directx12), and render target resolves.
Example of compile resources phase for CSceneGBufferStage. This stage detects if a depth prepass stage is registered with the graph. If the stage is registered, it sets the stage's output as this stage's input, and as a "read write" resource with the output id of "EStageOutputId_3". If the CSceneDepthStage does not exist, the gbuffer stage creates it's own depth target.
Stage Execution
This is the final stage of the render graph. In this stage the render graph traverses the pipeline stages in the order generated during the "Compile Resources" stage. If the next resource requires a render target, a render target is generated from the pooled render target and set to the proper output slot. All resource transitions and render target resolves are automatically handled prior to the stage running.