Jump to content
  • Advertisement
Sign in to follow this  
d000hg

Renderstate management

This topic is 4989 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

There are 2 factors for a renderstate manager, as has been mentioned - ensuring the states are always preictable and correct, and minimising the actual number of changes.
Using the Stack approach and delaying the actual state changes until render time is one optimal way of doing both.

I'd favour a version where each renderable object essentially knows nothing about the current states, and naively tries to set the whole load of them to its specifications - the RenderStateManager then actually calls D3D::SetRenderState for the states which are changing.
In a first version this isn't great, because each object needs to pass approx 170 render state values - I guess this isn't a performance problem in reality since the actual D3D::SetRenderState calls will be minimised. However if we have a default value for every state, then each object just needs to know which states it doesn't want to be the default. The RenderStateManager keeps track of all the states not currently in their default values. The default values don't need to be D3D defaults, at startup the actual states can be synched with our default values.

Share this post


Link to post
Share on other sites
Advertisement
Attempting to set 170 renderstates in each object will cause a performance hit, even if you check the render state. 10 particle emitters, 8 models, 3 world models and that itself is 3570 functions calls, per frame, and thats a very limited example. Even if it wasn't a performace hit, you would be writting some pretty big, and not very efficent code.

Some renderstates may never change (Colour Writing) some will change periodically (lighting) and some will change many times per frame (blend mode) (All render states used are examples). So having a default value is of course neccesary. How you decided what was to be changed though is up to you.

You could (but I would recommend against it) check each state against its default in each object then change the ones that needed to be changed. But that leads to the same problems pointed out in the first paragraph.

The other method is to assume the defaults are set, and just change the ones you need to change. You would then have to change back to the defaults before you left, so other objects could correctly make the same assumptions. This leads to the push/pop system that I have used.

Quote:
Original post by rick_appleton
What you could do to minimize the state changes is delay the change until something actually gets drawn


I do like the idea of this. This could really limit the number of unnessecary state changes. By calling SyncRenderState(..) or something before every API render call, the states would and could only be set as and when they are needed. Of course, this could still be open to abuse, and would need to be used in an ordered manner to be effective.

When the render state is pushed/popped, the stack is updated, but the render state remains the same, with an added array keeping track of what the states _should_ be. When SyncRenderState is called, all the states that have been changed can be changed...

Spree

Share this post


Link to post
Share on other sites
My state manager works that way. There is a class which represents a complete render state, with properties such as StencilOp, Vertex/IndexBuffer, streams, matrices, lighting, fog, all material (texture) passes, and so on. The manager class stores an array of them (128), and the render device fills it with data, and then pushes the state onto the stack.

When the render interface gets a draw call, it calls Commit() which sets the hardware to the values defined in the current state stack (iff they differ from the hardware value). After drawing, the state is popped off the stack, which sets the "wanted state" to the values defined in the current state stack, and the next state is drawn, which again calls Commit() and so on.

Ideally, the data sent to the renderer is already sorted by a scene graph or some other data sorting mechanism, but that isnt required, only good for reducing redundant state changes. The device controlling the render device (and thus the state manager) must be aware of how many push state calls it has made, so it does not overrun the array bounds.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!