3
\$\begingroup\$

I would like to know what the performance difference is between

  1. using multiple sprites in one file (sprite sheets) to draw a game-character being able to face in 4 directions and

  2. using one sprite per file but rotating that character to my needs.

I am aware that the sprite sheet method restricts the character to only be able to look into predefined directions, whereas the rotation method would give the character the freedom of "looking everywhere".


Here's an example of what I am doing:

  1. Single Sprite Method

    Assuming I have a 64x64 texture that points north.

    So I do the following if I wanted it to point east:

    spriteBatch.Draw(
        _sampleTexture,
        new Rectangle(200, 100, 64, 64),
        null,
        Color.White,
        (float)(Math.PI / 2),
        Vector2.Zero,
        SpriteEffects.None,
        0);
    
  2. Multiple Sprite Method

    Now I got a sprite sheet (128x128) where the top-left 64x64 section contains a sprite pointing north, top-right 64x64 section points east, and so forth.

    And to make it point east, i do the following:

    spriteBatch.Draw(
        _sampleSpritesheet,
        new Rectangle(400, 100, 64, 64),
        new Rectangle(64, 0, 64, 64),
        Color.White);
    

So which of these methods is using less CPU-time and what are the pro's and con's?

Is .NET/XNA optimizing this in any way (e.g. it notices that the same call was done last frame and then just uses an already rendered/rotated image thats still in memory)?

\$\endgroup\$
3
  • 5
    \$\begingroup\$ Profiling this yourself is a great way to learn about profilers and get the answer you want. Try Slimtune \$\endgroup\$
    – House
    Jun 18, 2012 at 16:08
  • \$\begingroup\$ Why don't you just test it and provide information anyone can use? This doesn't really sound very difficult to profile. You might also want to use reflector.net to take a look into the inner workings of XNA. I haven't tested that yet concerning XNA, but it worked for me with other libraries and sometimes cleared up some things. \$\endgroup\$
    – Adam
    Jun 18, 2012 at 16:54
  • \$\begingroup\$ Hint: there is nothing stopping you from combining (1) and (2). \$\endgroup\$ Jun 19, 2012 at 22:51

4 Answers 4

3
\$\begingroup\$

Without access to the XNA source for the SpriteBatch object it could be hard to tell. But the main difference is in the transformation.

When you render a sprite with SpriteBatch it will create a quad and place it in a buffer. The vertices of this quad will have to be transformed to put the sprite in the position you specified.

When you use the SpriteBatch.draw() method in the first example you provide two rectangles. It is from the first one that your sprite quad will be constructed and you should be able to see how constructing the vertex coordinates from a rectangle would be trivial.

In the second instance an extra step will have to be taken because of the rotation. To handle the rotation a transformation matrix will be constructed and each vertex of the quad will be transformed using this matrix.

Now, it may be that in both cases a transformation matrix is created, but in the second method an extra step will have to be taken to add rotation to that transformation matrix.

A good profiler will give you a better idea of what is going on, although the reality is that you are most likely not rendering enough objects to see an difference when you put this method to work on a real project and you will find that artistic requirements will dictate which you will use at that time.

I would also like to point out that if you are concerned over this because it was a common technique back the in the glorious 2D era you don't really have to worry as you have the power at your disposal to forget about it. The main reason it that this was a problem on older hardware seems to be because the creation of a rotation matrix would most likely involve the use of many trigonometric functions which are not trivial operations.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Good answer! I'd like to clarify some of your assumptions after analyzing the contents of SpriteBatch. The rotation is always being applied even when the value is zero. This is done directly using the unfolded form of a 2D rotation matrix multiplication. But when rotation is zero, the trigonometric functions are avoided so it's cheaper. \$\endgroup\$ Jun 18, 2012 at 23:58
  • \$\begingroup\$ @DavidGouveia How did you analyze the contents of the SpriteBatch? Also, I think you should make your comment an edit for the sake of the answer. \$\endgroup\$ Jun 19, 2012 at 0:27
  • \$\begingroup\$ I used dotPeek :) And actually at first I wrote a huge answer describing the entire process in detail, but a lot of it was more curiosity than actually answering the question, so I stripped it down to the minimum. \$\endgroup\$ Jun 19, 2012 at 0:42
4
\$\begingroup\$

Using a sprite sheet reduces the need for the computer to load a new/different image in order to draw on the screen.

Here is an article which shows the performance differences in XNA (in the emulator and on a device) as well as the animation class used.

\$\endgroup\$
1
  • 3
    \$\begingroup\$ Your answer is out of context. It's true that using a spritesheet is better than using several textures. But in this case he's only using one texture. What is changing is that one case uses the rotation parameter, while the other uses the source rectangle parameter. \$\endgroup\$ Jun 18, 2012 at 22:29
4
\$\begingroup\$

Hard to say without actually profiling it but some information that might help:

  • When you do not use the rotation parameter or leave it as 0:

    • The rotation transformation is still applied, but SpriteBatch handles it as a special case which costs one Math.Cos and one Math.Sin less for each sprite being drawn, because it already knows that the sine and cosine of zero are 0 and 1 without having to calculate it.
  • When you do not use the sourceRectangle parameter or leave it as null:

    • SpriteBatch still fill outs the rectangle internally using the texture size as default values. There is no difference in the rendering part of the algorithm, which still uses these values to calculate the correct texture coordinates and sprite size.

Since trigonometry functions are somewhat expensive, and using a source rectangle requires the same amount of work as not using one, I think using the sprite sheet approach will probably be a bit faster than rotation, although the difference is probably negligible.

\$\endgroup\$
2
\$\begingroup\$

This is such a horrible, terrible micro-optimisation that you should not be pursuing it!

On the CPU, selecting a rectangle will be faster by a tiny, tiny amount (as David Gouveia has already pointed out, with a rotation of exactly 0, XNA skips two trig operations required to rotate the vertices).

On the GPU you are using more RAM by using a sprite sheet. The difference in size could conceivably cause a similarly minuscule performance difference.

Because each method alters performance by an extremely small amount and affects both CPU and GPU - which is better will almost certainly depend on the CPU/GPU combination in use and what the rest of your app is doing.

Certainly any measurements from a profiler will be meaningless (unless you are targeting fixed hardware like the Xbox 360).

To answer your last question: No, XNA does not cache sprite batch Draw operations. The vertex buffer is recalculated each frame.

So what should you do?

If you are actually at a stage where you legitimately need to consider these performance implications (eg: you need to draw 10000+ copies of your character), you should stop using SpriteBatch entirely. If you implement an alternative that handles only your specific case, and you have the necessary skills, you can write something that performs considerably faster.

Assuming you don't actually need the performance optimisation, which method should you choose?

Use the rotation method! Firstly it matches conceptually with what you are doing - a rotation. And secondly it reduces the amount of content you need to create.

\$\endgroup\$
1
  • \$\begingroup\$ Completely agree with this opinion although I refrained from voicing it. I think the benefits of not having to replicate the content and how easily you can change the angle are more important than that tiny (if any) performance gain. \$\endgroup\$ Jun 19, 2012 at 13:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .