September 30th, 2008
Understanding Zune DevelopmentXNA Game Studio, by nazeeh.
With the upcoming release of XNA Game Studio 3.0 (it is currently in Beta), one of the big features of the release is the ability to write your own games on a Zune device. This is a very exciting prospect for a lot of people as well as the XNA Game Studio dev team. When we first released Game Studio Express, we didn’t know what to expect as far as the type and quality of games people would make. I remember sitting in a big room with a Xbox hooked up to a nice TV about to see demos of games from the first Dream.Build.Play contest. Boy… seeing games like Dishwasher and others totally took us by storm! So now that we have Zune as another platform, I want to make sure you guys have as much as you need to blow our minds again! So… what’s the deal with developing a game for the Zune?
Understanding the Device
The Zune player, while comes in different form factors, has the same capabilities across the board except for the storage size it has. All Zune devices have the following characteristics:
- A screen resolution of 240×320 pixels. This is regardless of the physical size of the device. The resolution is the same.
- An internal storage medium that is either flash or hard drive based.
- The biggest size game you can create is 2GB.
- The amount of memory available for your game in total is 16MB. This includes your code in memory, data, textures, sounds, etc. Take away some memory for the XNA Game Framework and you realistically have around 12MB of memory to work with.
So what does this mean to you as an aspiring Zune game developer? Well… the most obvious factor you have to consistently keep in mind is that 16MB of available memory. If you don’t take that into account and just code away, I guarantee you that your game will run out of memory pretty quickly.
Memory on the Zune
As I mentioned above, you have a total of 16MB of memory to work with for your Zune game. If left unchecked, your game will probably run out of memory leaving you quite unhappy. This will manifest itself in one of many ways including Out of Memory Exceptions or Out of Video Memory Exception. You see one of those bad boys, and you know you’re in trouble. So let’s see what kind of things can cause this evil to happen!
A common scenario you might find yourself in is if you write a game on Xbox and/or Windows and just directly port it to Zune via the Convert to Zune feature of our project system. The game will probably build just fine, you’ll do some quick fixes to scale your textures down to fit the Zune screen. You’ll hit F5 and the game will launch on the Zune and things will look nice and happy. You’ll think that the XNA Game Studio team are a bunch of amazing geniuses to enable something so cool to be so easy. Well… until your game crashes and you start to call us some really bad names.
So what happened? Is the XNA Game Studio team a bunch of n00bs? In certain games, yes…they are! But in coding, so not! Here’s what happened:
Your game, the one you initially created on Windows or Xbox, is probably using some nice, big textures. Windows and Xbox have way..way..waaaaaay more memory than their little brother the Zune. So if you have a texture that is say 512×512 in dimensions in your game, that is would come out to approx 1/2 MB of memory.
To calculate the size of a texture in memory, the formula is:
Texture has no transparency: width x height x 2bytes
Texture has transparency (alpha channel): width x height x 3bytes
So right there, you just ate 1/2 MB of your 16MB of memory.
So right there, that’s your first clue why you ran out of memory. You have to be very careful about the size of the textures you’re loading. And no, scaling the texture in game doesn’t solve that! You have to scale down the actual texture and then build the game.
Tip: Keep the sizes of your textures small! If you don’t need transparency, don’t use it. Re-use textures as much as you can.
Another area you can optimize is animations in your game. 2D animations are usually created using sprite sheets (see my post on the topic). Since such animations are created using frames of equal size usually, that means you can end up with a pretty big texture just for an animation. To get around that, you might need to approach it a bit differently. Things to consider:
- Instead of storing all the frames in your animation, start storing only the the parts that actually move and animate them over the static parts. This way your frames don’t have to be of equal size and can drastically reduce the size of your texture strip.
- Animations don’t have to be done via texture strips. Borrowing from the 80s style of game development (which makes sense since they had similar restrictions), you can animate stuff by using static textures and compositing them over each other. Check out this video to get an idea of what I am talking about. See how the boss is just a set of textures that are moved around to give the animation? Much smaller in size than animating the boss the usual way.
How you create your world is another area you want to focus on. In Windows/Xbox, you can use relatively hefty textures for your backdrops and so forth. Try that on Zune and you’re taking away from your memory budget. Consider using Tile Maps (I just started a post about this) for your world. They use much less memory and encourage reuse of textures.
I was talking to Yuichi Ito about this subject last week, and he actually told me this story of some artist he was working with back in the day. He said the guy knew he had little memory to work with but wanted the game to look good still. So he had to improvise. He started using the same texture he used for trees in the background for the hair on the characters! Just changed the color. No one noticed ;) You’d be surprised how much you can get away with and people won’t notice.
Yet another area you want to look into is particle effects. If you have any in your game, make sure you’re not using a separate texture for every particle color you’re using. Use a master white texture and then use the Tint color argument of SpriteBatch.Draw to color them.
Audio and Music
Audio and music in your game is very much like textures. So they need the same amount of focus from you or else you’ll hit the memory barrier yet again. Audio gets loaded in memory to be played, so the bigger it is, the more memory it will eat up. So use lower quality audio for your Zune games! You can read all about audio in general in Eli’s blog post about it right here.
Smaller Audio == more memory for your game!
Under the Hood
XNA Game Studio on the Zune runs using the .NET Compact Framework (NetCF). NetCF, while quite similar to its bigger brother on Windows, it’s not quite the same internally. Desktop .NET has a lot more memory and CPU power to work with, while NetCF doesn’t. So certain measures had to be taken to ensure good performance on the target platforms. This means some features are less efficient than they are on the desktop. So how does this affect us while we create Zune games?
Most of the content you can create on a Zune game has both a Managed object and a native resource attached to it. For instance, a Texture has both a Texture2D object (the managed one) and an underlying Texture resource that is in Zune native land. The managed object references that native resource and wraps it. This way you get the nice looking managed objects without having to worry about the underlying implementation.
So when you actually load a Texture2D object, NetCF sees a small object being loaded, the managed object that represents the Texture. It doesn’t see the huge native resource that is also loaded by that texture object. As far as NetCF is concerned, your Texture2D object is only a few bytes large and therefore is not a priority when it has to do garbage collection. But we know better! If anything, that object better get collected as soon as possible since it’s actually pretty large. NetCF disagrees though :) So you need to lend a helping hand.
When you’re done with textures you were using, you need to either call Content.Unload to unload all the content that was previously loaded by your content manager or call Dispose on that texture yourself. You can make this a bit easier on yourself by creating a new instance of ContentManager in your code to load specific textures you know you’ll want to get rid off soon. You can have more than one ContentManager in your game, it’s totally fine. Same applies to things like Audio and others.
Clean up after yourself! Don’t rely on Garbage Collection to do the right thing for you!
Here’s another interesting implementation detail for you to keep in mind. When you load a Texture in memory, ContentManager will load it in system memory first, then copy it to Video memory. Guess what? In Zune, System and Video memory are one of the same! So when you load a Texture that is 1MB in memory size, you are actually using 2MB of memory to finish the operation. The first 1MB though will get garbage collected when more memory is needed. But keep that in mind since if you have 4MB of memory available, you will not be able to load 4 x 1MB textures because of this. You’ll only be able to load 3.
Debugging the Issues
So how do you debug memory issues on the Zune? When we would talk to people about this topic for Xbox 360 development, we usually would just tell people to use performance profiling tools on Windows against a Windows build of the same game. Since Windows and Xbox 360 are relatively close to each other, you can actually spot the issues on Windows using the more advanced tools and can fix them for the Xbox 360. Can’t really do that for the Zune :/
The Zune is severely dwarfed in power when compared to a PC. So perf issues that affect the Zune probably won’t appear on Windows in any obvious way. Sure, you can try, but I doubt you’ll get much helpful information. But there are tools that can still help you somewhat. We provide the Remote Performance Monitor tool (RPM) that can be used to tell you how much memory you’re using by your game and so forth.
To use RPM, launch it from your Start Menu (Microsoft XNA Game Studio 3.0->Tools). Get your Zune device hooked up and the game deployed on it (but not running). Then:
- Pick your Zune device from the list and then enter the name of the game you deployed:
- Hit the Ok button. Your game should launch on the Zune.
- Now we check the GC Heap by clicking on the “GC Heap” button on the toolbar, you’ll see a window similar to this one:
- This already provides you with good information. You can see how many objects your code is running at the moment and the size in KB of all of them. This way you can see which objects are getting too big and might need to get on a diet.
- Another area you might want to look at is the JIT section of the main window UI:
- This will tell you how much space your code is taking up in memory. Another data point that might help you realize you may need to reduce the size of your code. Unless you’ve written your game in a very horrible way, I don’t think you’ll have much to optimize here though.
Developing games on the Zune is indeed a very exciting thing! We can’t wait till we see the kind of games people will come up with. The experience of developing a game the right way can be quite challenging but also rewarding. So get started on those games and let us know how we can help you out!Thanks for reading! I'd love to hear your thoughts, feel free to leave a comment below. Don't forget to subscribe to my RSS Feed!