What difference does a sprite sheet make?
Published on Tuesday, February 22, 2011 6:54:00 AM UTC in Programming
In game programming, a sprite sheet is a texture that contains not only a single image, but multiple images that either belong to different sprites, or that show different parts or animation frames of a single sprite. When you start creating your own games, or even when you look into creating modifications for existing games and look at their assets, you will run across this technique very soon. Everybody will tell you that using sprite sheets will result in smaller loading times, less wasted memory, and most of all, better performance. I've been telling people this too. But can we put a number on this? How much do you really gain if you use sprite sheets instead of single texture files? I cannot remember seeing any statistics or analyzes about this, so I decided to take a look at it myself, with particular focus on the Windows Phone 7 platform and 2D games.
As you might know, I'm currently writing an "XNA for Silverlight developers" series over at Silverlight Show. In Part 4 about frame-based animations, a reader suggested in the comments that it probably would've been better to load the animation frames I used for demonstration as sprite sheet instead of single images. What I didn't say in the article was that I had actually thought about introducing this technique, but then decided against it. I was very confident that it wouldn't matter regarding performance or memory consumption in the small sample we were building, and not even in simple games, so I wanted to concentrate on the core topic and not confuse the reader with optimization details that are probably not even required. However, that comment gave me the motivation to actually take a closer look at the involved numbers, so I decided to do some testing.
Video cards are generally slow at setting up things, compared to their performance once they can start doing their actual work. This means that things like loading a texture from system to video memory or even switching textures during rendering is what is considered an expensive operation. Once everything is set up, rendering that texture to the screen, even a great number of times, takes a comparatively small amount of time. That is why developers try to optimize their textures to minimize the required loading and switching operations. For example, they put all the individual texture parts of a 3D model or all the required tiles for a tile-based level on one texture etc. And if it's not possible to use a single texture, they may try to optimize the order of rendering in a way so that the number of required texture switches is minimized.
A word of caution
What I'm trying here is a very difficult thing: measure the advantage you get from using this technique. Even if you could take a finished, commercial game and switch between using sprite sheets and not using them, the resulting numbers would not be useful down to the detail for your own game. The actual benefit very much depends on the circumstances and such a huge number of factors that neither a simple test nor a complex one can accommodate for that (we will see an example for this below). However, I wanted to get a feeling of the order of magnitude we are talking about on the Windows Phone 7 device, and in particular for the animation sample I've been using. In a theoretical, worst case vs. best case scenario, what can I expect? Twice the performance? Two percent performance gain? That said, let's finally dive into the numbers.
I am using the same animation that I used in Part 4 of my XNA series here, and the tests performed are:
- Playing a list of animations using sequential images, where every animation uses a different frame than the animation before. This is the worst case, because texture switching has to happen for every animation that is drawn on the screen.
- Performing the same test but using a sprite sheet instead.
The test starts with one animation and keeps adding additional animations until the frame rate drops below a certain threshold (I chose 10 fps). On Windows Phone 7, the typical target frame rate is 30 fps; my expectation was that for some added animations keeping this frame rate won't be a problem, but then at some point a decline will kick in.
Please note that XNA tries to adhere to the targeted frame rate as accurately as possible for the update method of your game. It will only skip rendering frames to keep up. To measure the decline in fps, you therefore have to look at the rendered frames (i.e. the draw method) instead. My tests showed that the update method indeed stayed at the desired 30 fps all the time, confirming that this concept works really well (more on that in Part 1 of my series).
In the emulator
As almost all sources around Windows Phone development already have pointed out, the emulator's performance is a lot different than the one on actual devices, which is why everyone strongly recommends to test your applications on real hardware during the development process, at least before you submit them to the market place. I decided to include these numbers anyway to make a point. I know that the emulator is faster than an actual device, but I was a bit surprised how much faster it turned out to be. The following will also show the difference of the test results between the emulator and the real device, proving what I just pointed out: with different circumstances (e.g. different performance of the platform), the results even of a simple test like this can be very different.
As you can see, sprite sheets have a clear performance benefit when we are talking about a lot of animations. The most important thing to note about the above diagram is that the x-axis is logarithmic. Showing the diagram without that scaling would've been pretty useless because the performance degradation with single images kicked in so much earlier than with sprite sheets that you'd only see an almost vertical line in comparison. The key numbers are:
|Start of degradation||Reached 10 fps at|
|Single images||281 animations||1,241 animations|
|Sprite sheet||12,000 animations||37,000 animations|
Without drawing any conclusions yet, let's simply move on to the device and see how it performs in comparison.
On a real device
The device used for this was a Samsung Omnia 7. First let's take a look at the diagram:
First thing to note: we are not using a logarithmic scale here, because the performance of both methods didn't show such a huge difference anymore. The key numbers are:
|Start of degradation||Reached 10 fps at|
|Single images||151 animations||461 animations|
|Sprite sheet||201 animations||611 animations|
There are some extremely interesting conclusions we can make here:
Raw performance numbers
In the emulator, single images only reached around 2.3-3.3% of the performance of the sprite sheets. That is an incredible difference between both methods which is probably owed to the really good video card I'm using. On the real device however, this gap closes and the single image performance now is at ~75% of the one for sprite sheets. This is truly amazing and once again demonstrates that you cannot draw general conclusions without taking the surrounding factors into account. Apparently on the device other limitations (probably CPU and/or fill rate) exist that play a much more important role.
It's also very noticeable that there's a huge difference of the absolute numbers. 12,000 animations in the emulator vs. 201 on the device clearly shows the importance of testing on real hardware.
Given the fact that 40 of the sample animations are able to cover the whole screen of a device already, the question is whether the difference between 151 and 201 animations is of anything else than theoretical interest. Even more, the sample takes it to the extreme and simulates the absolute worst case where a texture switch happens between every single draw call. In a more realistic scenario, the gap between those two methods is likely to be less significant, because usually you'd have some kind of grouping/ordering logic for your drawing calls in place anyway.
If you are willing to make more sacrifices, you can even completely nullify this difference for animations. For example, if you tune multiple instances of the same animation to run in sync (e.g. all instances show the same frame at a given time), the logic consequence is that there's virtually no difference anymore between using single images and a sprite sheet (but of course the visual impression may lack variety):
It might seem that the whole objective of this article is to lead to my final recommendation to not use sprite sheets on the phone, or at least to come to the conclusion that there's no need for them. The truth is, I very much encourage this technique! Even if it's doubtful that using sprite sheets brings a huge performance benefit on the Windows Phone 7 platform in most scenarios, the performance benefit is existent. You should go for this kind of optimizations on a limited platform like a mobile device anyway, especially if it is so easy to use like this one. For example, the sprite sheet sample in the App Hub education sample is a ready to go implementation that hooks into the content pipeline and makes this as easy as creating a simple XML file. In addition, sprite sheets have additional advantages, for example to minimize the required memory (if you're working with powers of two sized textures) and loading times. It's just that on the device, it most likely won't be the killer feature that magically doubles your game's performance, like some people are trying to sell it.