SpriteSortMode.Immediate in XNA Game Studio 4.0

SpriteSortMode.Immediate in XNA Game Studio 4.0

  • Comments 9

Every now and then, a Game Studio 3.1 customer tries something like:

    spriteBatch.Begin(SpriteSortMode.Immediate);

    SetRenderStateFoo();
    spriteBatch.Draw(...);

    SetRenderStateBar();
    spriteBatch.Draw(...);

But this does not work! Sadness ensues.

The problem is that SpriteSortMode.Immediate did not really mean "immediate". A more accurate name would have been "inelegant hack that was added to enable drawing sprites with custom renderstates or shaders, but which still does some minimal amount of batching in the interest of having the aforementioned sprite drawing not be ridiculously slow when there are large numbers of such sprites". That's too long to make a good enum name, though, so we just went with "immediate" :-)

Prior to Game Studio 4.0, the way SpriteSortMode.Immediate actually worked was:

  • Begin sets default states onto the graphics device
  • Draw adds a sprite to the current batch
  • If you call Draw with a different texture from the previous call, it flushes the current batch
  • End flushes the current batch

That really only allowed one usage pattern:

  • Begin
  • Set custom states
  • Draw any number of sprites
  • End

Any time you wanted to change state, you had to End the current batch, then Begin a new one.

As of Game Studio 4.0, it is now possible to use custom renderstates and custom shaders with any SpriteSortMode, so Immediate mode no longer has to worry so much about batch performance.

So, we changed SpriteSortMode.Immediate to work the way people always expected it to. Every Immediate mode SpriteBatch.Draw call now generates a separate GPU draw call, exactly like the name implies, really truly immediately with no batching whatsoever.

Implications:

  • If you draw many sprites in a row using SpriteSortMode.Immediate, they will not be batched, and performance will suffer as a result. You should only use Immediate sort mode if you need to change state between every Draw call. Most of the places you used to specify Immediate sort mode, Deferred is now a better choice.

  • The code I posted at the start of this article now works like you would expect.
  • This is a great improvement, but I would strongly advise against overloading the meaning of SpriteSortMode.Immediate like this. It would be better if the name changed to indicate that the behavior had changed. Either way, you're going to be breaking existing code, so why not do it in an obvious way? :)

  • Note that the preliminary documentation for XNA 4 mentions "Immediate mode is faster than Deferred mode."Might need a bit more elaboration in the final version of the docs. :)

  • So deferred mode will try to batch as much as possible if i change change state between Draw calls, right?

  • I have been wondering why it is necessary to flush the sprite batch whenever the texture changes? All graphics cards support multitexturing, right?

    So when calling Draw with a different texture, the texture could be set on the device, and all sprites marked internally with a number that tells the sprite shader which texture to draw from? Only when the texture slots ran out would it be necessary to send off the batch.

    If there are reasons why this would be impossible or not desirable, I am curious to know them...

  • > Note that the preliminary documentation for XNA 4 mentions "Immediate mode is faster than Deferred mode."Might need a bit more elaboration in the final version of the docs. :)

    Good catch, thanks!

  • > So deferred mode will try to batch as much as possible if i change change state between Draw calls, right?

    Not exactly. Deferred mode defers all actual GPU drawing until the SpriteBatch.End call, so it is not possible to change renderstates to anything other than what you specified when you called SpriteBatch.Begin. So yes, it does batching, but no, you can't change state between Draw calls.

  • > I have been wondering why it is necessary to flush the sprite batch whenever the texture changes? All graphics cards support multitexturing, right?

    Multitexturing isn't really a good way to switch between different textures. For one thing, there are fairly low limits on how many textures can be bound to the shader at the same time. And more importantly, doing this kind of dynamic selection in the pixel shader would require a complex pixel shader, which would therefore be much slower than the simple/fast pixel shader that SpriteBatch uses today.

    Using multitexturing to reduce texture switches would be trading CPU side driver work for much more expensive GPU work. I guess there could be cases when that might be worthwhile (it all depends on where your bottleneck is), but for general purpose use, I don't think it would be a win.

  • This blog is great, but really this information should be in the API documentation. The XNA docs are quite sparse compared to say the Java imaging API docs (which are very thorough). What's the process for making your docs, do the developers write it and pass it through the editor, or do you have technical writer(s) assigned to do them? If the former is true, I guess it's a man-hours limitation, if the later, maybe a communication issue?

  • My platform game heavily relies on the old behaviour of SpriteSortMode.Immediate, and I had huge performance issues when porting to XNA GS 4 from 3.1:

    thank you Shawn (and thank you google too... :)

Page 1 of 1 (9 items)
Leave a Comment
  • Please add 4 and 6 and type the answer here:
  • Post