Monday, October 31, 2011

Rendering architecture (1)

Hi guys!
Too much time I don't update this blog!

I wanted to share with you a way in which I describe rendering for my home-engine, used to study technologies quickly.
I'm doing this way since 2008, so now it's starting to become very mature, but I'm sure will improve in the future!

Let's start from the objective: I wanted to create something flexible and quick to iterate to study all the different rendering techniques that I'm interested into.
Speaking about DX9+ GPUs, the context of the problem has some constraints.
The rendering APIs are a state machine, and to draw we must provide at least those informations:

1) Vertex Buffer
2) Index Buffer
3) Vertex Format
4) Vertex Program
5) Fragment Program
6) Shader Constants
7) Render States
8) Render Targets

We can see the Rendering as a problem on HOW to create those information to be sent to the GPU.
The Rendering nowadays can be seen as a sequence of drawcalls applied to a render target.
So back in time I started to define the concept of Rendering Pipeline as a sequence of drawcalls in a render target.
Each of those sequences became a Stage of the pipeline.
At the end of the day we have

Pipeline
Stage0 -> Stage1 -> Stage2

This sounds a little simplified, and actually it is simple, but it's really powerful.
An example of Stage can be as simple as a ForwardRendering that renders in the framebuffer (that can be seen as a Render Target),
a GBuffer generation, Shadow Creation, SSAO, ...

For each stage we define some RenderTargetInputs and Outputs, to link the different stages together.

If I made the picture clear, each rendering became a series of rendering of stages.
To describe the rendering I started using an XML file like that:


Each stage type corresponds to a class that extends the Stage class in the code.
At the very beginning this approach was good, because I could describe rendering in a mix of
xml/code that was very fast to prototype with!
After some months of coding I saw emerging some interesting patterns:
  • Each stage has some RenderStates set before rendering
  • Each stage can draw per material or providing a shader
  • Each stage that describes a postprocess, draws a single quad and has a shader associated.

Further defining the rendering problem, I found another missing information in the rendering objects that were sent to each stage.

How can I define them?

I ended up with what I called a RenderView, that is a camera plus a list of "render instances". So now each stage renders a particular RenderView and has some renderstates defined, plus an optional shader if it is a postprocess.

The point is...why just not describe all those informations in the XML?

Enter ScriptableStage!

This stage has a renderview, some renderstates, and an optional shader. All defined in the XML. This provides me the flexibility to describe a lot of the rendering techniques around.

After some more technique explorations, I found another emerging pattern:

Each time I want to render, I need to provide 3 groups of informations

  1. Geometry
  2. Shading
  3. Render states

When you define all those informations, you can describe all the rendering you want! Even materials can be seen as a list of Shaders corresponding to stages and can be described through XMLs...

The application logic that sits on top must really provide mostly the geometry and link it with materials (that are shaders + render states).

With this simple description I found a very powerful way of describing the rendering and prototype/explore very fast.

Next post I'll describe also a way to achieve a simple reloading mechanism and avoid virtuals for the renderer itself to be more console friendly ;)

Enjoy!