Multiple Render Targets
Posted by Jason Z, 17 June 2010 · 362 views
I have been wanting to add multiple render target support to Hieroglyph for a while, and finally sat down for a little while and got it implemented. It actually required a small architectural change to how I represent the rendering pipeline, so I thought I would discuss it briefly here.
In Hieroglyph, all of the programmable shader stages (all six of them!) are represented by subclasses of a ShaderStageDX11 class, with each of the subclasses implementing methods for that particular shader stage. This is necesary since setting a constant buffer uses a different method call for each shader stage. By using a common base class, it makes it fairly easy to perform generic data binding to each stage. The renderer actually references the shader stages by an array of the base class pointers for some operations.
So what does this have to do with multiple render targets? The fixed function stages of the pipeline didn't have a class based representation - the renderer directly managed the states that were set by the user. Once I started planning how to add the MRT support, I wanted to have an automatic memory of what render targets are set, so that if nothing changes and the user still calls the method to set the render targets then it would skip the call all together. I didn't like the idea of bloating the renderer even more, so I decided to make an OutputMergerStageDX11 class to handle the responsibilities.
Now this class maintains two arrays of ID3D11RenderTargetView pointers. One represents the current values set in the API (i.e. in the real output merger) and the other represents what the application has currently indicated that it wants to be set. When the 'Apply' method is called, the two arrays are compared and the minimum number of changes are made to the render targets to fulfill the desired array. Of course, after setting the API array is updated as well for use next time. Its simple, but appears to be working quite well.
This update is the first step to adding a deferred rendering capability to the engine - since G-buffers are typically filled in a single pass, this was the minimum entry step to get started... Next up I want to add the remainder of the OutputMerger functionality to my new class, which will further relieve the renderer from low level maintenance of the pipeline.
The latest commit can be picked up at the Hieroglph codeplex repository. As always, questions or comments are always welcome!