SetRenderState each frame

Started by
9 comments, last by S1CA 19 years, 7 months ago
Hi, I recently realized that every call to a DrawPrimitive leads to a bunch of SetRenderstates, SetTextureStages and SetSamplerStages which are ignored because of redundancy. I wonder now how this comes and how I can prevent it. I would understand it if I set the States myself but the Call to Draw executes them and not me?!? Any help would be greatly appreciated.
Advertisement
You should sort your renderable objects so that you can draw them using as few state changes and draw calls as possible.

While it is usually difficult and even unpractical to get a perfect partitioning of the drawable objects, it pays to strive towards that - graphics hardware likes big data portions infinitely better than small ones, for various reasons.

Also, it is not so relevant to you if the hardware states are actually set before or during the rendering. The card is free to cache instructions, as long as it executes them in the time of need (by the time of the draw call).

Niko Suni

Quote:Original post by MannyCalavera

I recently realized that every call to a DrawPrimitive leads to a bunch of SetRenderstates, SetTextureStages and SetSamplerStages which are ignored because of redundancy.


I don't think it does. What gave you this impression?
@Nik02

Thanks. That explains it much better. But I find it still strange that calls to SetTextureStage and SetSamplerState are even necessary since there is no point in my code where I call them. How can something be cached and latere ignored because of redundance if i don't even set it?

@DBX

When I debugged (step for step) I could see with the dbmon.exe that the call to Draw did spawn those warnings (SetRenderState[..]ignored[..]).
This is what I think, though I'm not 100% sure, I haven't read it in a DX document. DirectX internally caches the render states. That's why it is ignoring them, so it's not really a problem. You could also cache these states with some type of Render Manager. If you tell the render manager to set texture 0, and it knows that it was set previously, it can ignore your request to set it. Then again, DirectX is going to check that for you too, so then there are two places in the software where the state is cached and checked before setting. This is my understanding of it anyway.

How is your code structured? Do you set the render states during the render loop? Or did you just make a test application where you load everything, set the render states, then just call Draw every frame?

Chris
Chris ByersMicrosoft DirectX MVP - 2005
Quote:Original post by MannyCalavera
@Nik02

Thanks. That explains it much better. But I find it still strange that calls to SetTextureStage and SetSamplerState are even necessary since there is no point in my code where I call them. How can something be cached and latere ignored because of redundance if i don't even set it?


Are you using the .fx framework, by any chance? It can be configured to set various device states upon application (and more often than not, it is configured that way). If this is not the case, then something is wrong - and badly - because states do not magically set themselves. Period. [smile]

If the code you run isn't your own, run it thru debugger; stepping every line, until you either see a state change or an effect begin().

Niko Suni

Thanks so far.

Quote:How is your code structured? Do you set the render states during the render loop? Or did you just make a test application where you load everything, set the render states, then just call Draw every frame?


I set some renderstates (Backfaceculling and Alphachannelusage)but long before I go into the render loop but I don't ever set Texturestages or Samplerstates.

In the renderloop I only call beginscene, draw, endscene and present, nothing more.

Quote:
Are you using the .fx framework, by any chance? It can be configured to set various device states upon application (and more often than not, it is configured that way). If this is not the case, then something is wrong - and badly - because states do not magically set themselves. Period.

If the code you run isn't your own, run it thru debugger; stepping every line, until you either see a state change or an effect begin().


I've to admit I don't even know the .fx Framework, so I suppose I haven't even touched it. ;) I stepped through every line and the only one that executes this behaviour is my call to draw. The few places I set renderstated don't generate the ignorance out of redundancy.

Well, I'm so confused.
Quote:Original post by Supernat02
This is what I think, though I'm not 100% sure, I haven't read it in a DX document. DirectX internally caches the render states. That's why it is ignoring them, so it's not really a problem.

Direct3D does state-filtering only for non-pure devices - your only cost is a call to D3D.
However, with pure devices, any state changes get passed directly to the driver (which might or might not filter). An exception of this is changing a state that is supported by an interface (i.e. changing a texture will get filtered even with pure devices, because there's an IDirect3DTexture9). IIRC, the exception to this is pixel shaders. Even though they have an interface they don't got filtered.

In general, your application is in better position to filter redundant states - you'll be more efficient this way. Also, using PURE devices is recommended for improving performance, and with these redundant states will hurt.

Quote:Original post by Coder
Quote:Original post by Supernat02
This is what I think, though I'm not 100% sure, I haven't read it in a DX document. DirectX internally caches the render states. That's why it is ignoring them, so it's not really a problem.

Direct3D does state-filtering only for non-pure devices - your only cost is a call to D3D.
However, with pure devices, any state changes get passed directly to the driver (which might or might not filter). An exception of this is changing a state that is supported by an interface (i.e. changing a texture will get filtered even with pure devices, because there's an IDirect3DTexture9). IIRC, the exception to this is pixel shaders. Even though they have an interface they don't got filtered.

In general, your application is in better position to filter redundant states - you'll be more efficient this way. Also, using PURE devices is recommended for improving performance, and with these redundant states will hurt.



Yep. Just to expand on this:

when you're changing state, more often than not, you're changing more than one state at the same time; This knowledge of groups of states which change at the same time is why your application is in a much better position than the "if (currentstate!=newstate)" checking in the non-PURE Direct3D runtime.

If you use D3D state blocks and/or D3DX effects, then this can be as simple as sorting by block handle/effect and then making sure you don't set the same effect/state block twice in a row.

Simon O'Connor | Technical Director (Newcastle) Lockwood Publishing | LinkedIn | Personal site

I have a BSP loader which sets the render/texture/sampler-states with every Render() call. using the normal pDevice->SetxxxState() calls results in 80 fps and my debug window being spammed with "rednundand xxx state" messages.
So I decided to write my own statemanager (states are stored in a vector), and this is the result:

release build, debug DX runtime:
- no state manager: 80 FPS
- state manager: 230 FPS

Truly unbelievable, isn't it? :)
I thought the DX runtime would filter the redundant state changes, but obviously it doesn't.

This topic is closed to new replies.

Advertisement