Jump to content
  • Advertisement
Sign in to follow this  
Opwiz

Minimizing render-state changes

This topic is 4721 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

I'm currently designing/implementing a renderer and I need some input on one idea I have about minimizing render-state changes. First off, the scene to be rendered is represented by geometric objects organized spatially in some sort of data structure. When drawing the scene, the renderer iterates through the renderable geometric objects currently in the view frustum and calls a Draw() method passing itself as an argument. The Draw() method uses methods in the renderer to change render-state and to draw geometric data. Currently the renderer updates the render-state as soon as any render-state data is changed. If the material diffuse setting is changed the render-state is updated (in the api used). If the ambient setting is changed next the material state is updated again. So my first idea how to optimize my current design is to wait for a request to render geometric data before updating the render-state. So material/etc. settings is changed but updated first when the renderer get request to render geometric data (any flaws in doing this?). Now this does not optimize the order of the render-state changes is done, so I thought that when the renderer get a request to draw geometric data it queues it in some sort of data structure along with the current render-state. I have no idea how to implement this data structure though (possible?). So a render pass might look like this: renderer.RenderState.Fog.Enable = ... renderer.Draw(geometry1) renderer.RenderState.Material.Diffuse = ... renderer.RenderState.Material.Ambient = ... renderer.Draw(geometry2) renderer.Draw(geometry3) ... The renderer takes care of sorting these draw-requests and sets render-state and draws the geometry in a optimal order at the end of the render-pass. Is it a good idea or not to use this approach?

Share this post


Link to post
Share on other sites
Advertisement
You pretty much have to queue your rendering requests in order to sort, it's the simplest way and it always works. If the states of your renderable objects are hardcoded, you have to figure out a little data-packet to tag along all objects which are then compared as you showed.
A simpler approach would be to assign "global" data-packets about state changes that are pointed to by all renderable objects, I'll call them shaders (don't confuse this with the gfx-card ones). Instead of sorting by on a per-object basis, you can sort on a shader-basis. When you render everything, you just render a run of objects with the same states whenever a unique shader pops up in your render queue (example: if you got a "brick-wall" shader and have requested 5 walls for rendering, the walls should show up right after each other in the sorted render queue and they all use the same shader, the objects before and after use other shaders and therefore other states).

If there are a lot of shaders in a scene, simply bunching up shaders into groups should help, but you could keep in mind a way to sort on a per-state basis too. Assign weights to the most important states in a simple list of states for each shader ("zbuffer = 2", "vtxshader = 5" etc) and let a shader-comparison function figure out how much two shaders differ.

Share this post


Link to post
Share on other sites
I understand what you are saying. Now the most difficult part as I see it, is to figure out how the sorting is done. E.g. if we have a total of 3 render-state changes (and geometric data associated with each):

1. MaterialA, TextureA
2. MaterialA, TextureB
3. MaterialB, TextureA

Only the material and texture state is changed for simplicity. How do I go about sorting these render-state changes?

Share this post


Link to post
Share on other sites
To keep things simple ("kiss"), say we have a render queue in a static list like this after just appending a set of renderable objects:

1) Object #1 -> Mat A + Tex A
2) Object #2 -> Mat B + Tex A
3) Object #3 -> Mat A + Tex B
4) Object #4 -> Mat B + Tex B
5) Object #5 -> Mat B + Tex B
6) Object #6 -> Mat A + Tex B

If you use C, you could try out 'qsort' to start with and write a comparison function similar to:


int queue_cmp(void *a, void *b) {
Entry *e0 = (Entry*)a, *e1 = (Entry*)b;
int cmp = (int)e0->material - (int)e1->material;

if (cmp) return cmp;

return (int)e0->texture - (int)e1->texture;
}


The above function will sort first by material, then by texture. It doesn't care about any states, it only knows that two materials do not have the same set of states and thus will group render entries into materials. Handling states for materials shouldn't be much of a problem more than designing a system to represent states.
Loop through the new sorted queue and whenever a new material, or a new texture, is encountered, update states accordingly.

PS. You could let the render queue be a linked list and insert requests in sorted order directly.

Share this post


Link to post
Share on other sites
However, there is a point where sorting will actually be more expensive than just dumping the queue to card as it is.

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.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!