Wednesday 7 November 2012

Pigment & the Droid, Part 2

As outlined in Part 1, the HTC Desire bracketed the heap allocation of Pigment.  That is, while developing the game, if it failed to work due to lack of memory then it would be cut back in order to fit, and thus the game came to be defined, at least in terms of heap allocation, by the Desire.  However, there came a point in development where more assets were required than could fit - there seemed to be no more screens to cut, no bitmaps that could be not-loaded, but something had to give in order for the game to work.

In order to fit more assets into memory than could physically go, Pigment uses a trick based on how some of the assets relate to each other.  One group of bitmaps the game uses are the messages, the info screens sent to the user after certain events; the "Win!" message, the tip about pressing Back to undo, the Bonus Unlocked messages, the congratulations message for completing worlds / the game.  Of these, the Science Unlocked message and the final congratulations message on completing the game made a useful pair.

The Science Unlocked message always (and only) displays after you complete your 4th level.  It doesn't matter what level it is, but when you have completed four levels total the Science Unlocked message is displayed (and, of course, the Science skin is unlocked in the Bonus menu).

The End Game message, on the other hand, only displays once you have completed every single level in the game.  Clearly it is very unlikely that a user will see both these messages in one play session.

Thus we have this solution: when Pigment is loading its assets it checks whether the user has already seen the Science Unlocked message.  If they haven't then it loads that image into heap and does not load the End Game message.  Conversely, if they have already seen the Science Unlocked message then they will never see it again, and so it loads the End Game message instead.  We just saved one screen-load of heap!

This does introduce a bug into the game: if you sit down with a fresh copy of Pigment and complete it in one session, without switching to a different app (or taking a phone call, or reading a text message, or putting the phone on standby, or...) then, come the end of the game, it will display the Science Unlocked message again, instead of the Congratulations you might expect.

This technique was inserted into Pigment during development, but when the game initially shipped it was, in fact, not used.  Why not?  Because during development a larger saving in memory was found, which meant that on all the test devices this alternating-message-load system wasn't necessary - the game worked fine without it.

What was the larger saving?  Storing the images in a less consumptive manner.  To understand this you need to know how Android stores images on the heap; there are two main options for how to hold a bitmap, two main formats: ARGB8888 and RGB565.

ARGB8888 is a powerhouse, high definition format.  For every pixel in the bitmap you not only store a byte of information for every colour (red, green and blue), but you also a byte for an alpha channel - the alpha channel dictates the pixel's opacity.  This gives you a True Colour, 24-bit image, and allows you to blend it easily with other images since you can make parts of it transparent (or semi-transparent).

RGB565, on the other hand, is a very light format, whose only real selling point is the very small amount of memory it takes up.  Every pixel of a bitmap stored in RGB565 only has 5 bits each for red and green, 6 bits for blue, and no alpha channel at all.  The downside to this is a reduction in image quality, and the inability to blend with other images.  The upside is it only takes up 2 bytes of memory per pixel.

Compare the memory footprint of the two formats: ARGB8888 stores 32 bits per pixel, while RGB565 stores 16.  ARGB8888 takes up twice as much space!

Pigment had respected this fairly well, for the most part. The messages were all stored in RGB565, while the game pieces (the sprites) were stored in ARGB8888, since they needed the alpha channel to designate their shape and provide some anti-aliasing.

Two assets were held poorly, however; the "Win!" message is stored in ARGB8888 - it has to be since it needs the alpha channel.  What it did not need to be was a full screen in size: the "Win!" image was originally a full 800x480 pixels, even though it only has data in something like the 500x240 rectangle in the middle.  Dropping the transparent border provided a big saving.

Bigger still was the memory returned from switching the other offender: the Credits screen.  Pigment stores a variety of background images as it runs.  More detail will be provided in Part 3, but for now know that the paper-texture backdrop, visible through the gaps in the puzzles which have them, is held in memory.  To generate the Credits screen Pigment was first drawing this background image, and then drawing the credits image - the image containing all the credit text - on top.  That credit text image, of course, needed an alpha channel in order to expose the background texture beneath, and so was being held as ARGB8888.

Nothing dynamic was happening on the Credit screen, so there was no need for this compositing.  The screen would work just as well if it was simply a pre-rendered bitmap of the text over the backdrop, and this is what was implemented.  Instead of storing the credit screen as ARGB8888 it is now held as RGB565, and that provided another full screen of heap.

So, the saving generated by properly handling image formats superseded the saving brought about by alternating the message load.  Since the alternating load was a bit clunky, created a bug (albeit an extremely esoteric and unlikely to be reproduced bug), and resorted in a performance hit when the user toggled Demo Mode*, it was turned off.

Then Pigment was released as the FAotD on Amazon and it was clear that it ran out of memory on certain handsets.  Out Of Memory was something Pigment already had a solution for: all that needed to be done was to turn the alternating message load back on, and resubmit the new version to Amazon.  A week later 1.0.7 would be available, and all would be well.  Or would it?  Find out in Part 3!

Hint: there's a Part 3.  That means no.

*Why is there a performance hit when the user toggles to Demo Mode?  Left as an exercise for the reader!

No comments:

Post a Comment