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.
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.
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.
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.