Tutorial: Texture Compression in AIR (Using ATF)
Starting in AIR 3.4, Adobe added support for Adobe Texture Format (ATF) for use with Stage3D and Starling.
The point of ATF is to compress your PNG textures, providing much faster upload times to the GPU, as well as a lower RAM footprint.
The savings vary depending on the type of compression you use, and the format of your starting PNG, but generally you can see savings of up to 8:1.
ATF is really just a wrapper around the industry standard compression formats: PVRTC, ETC and DXT. For a basic primer on what ATF is, check this post from the eternally awesome Thibault Imbert:
Part 1: How does it work?
To understand how this works, we must look at how the GPU handles textures when they are uploaded.
PNG is a compression format designed for viewing with the human eye, it is not built for use within a GPU. That means, before the GPU can do anything with a PNG, it must fully decompress the image. This is similar to a BitmapData object in Flash, each pixel is a full 32-bit (4byte) RGBA value. For example:
- 2048×2048 PNG Uncomppressed = 2048 * 2048 * 4 = 16,700kb
- Upload Time: 3800ms
You can see that a standard PNG, when uncompressed, consumes nearly 17MB of video ram. It also takes close to 4 seconds to upload on an iPad 2.
Block Compression (PVRTC, DXT, ETC)
Block compression formats, are formats that have been built specifically for the GPU. They can not be viewed directly on your computer without a specialized viewer but the GPU can work with them directly. They don’t need to be uncompressed at all.
There are various formats that are used on different devices, for the sake of discussion we’ll use PVRTC, which is used across all iOS devices.
As opposed to an uncompressed image, which uses 32bits/pixel, PVRTC4 uses only 4bits / pixel. When we look at memory usage now, it looks like this:
- 2048×2048 PVRTC4 = 2048 * 2048 * 0.5 = 2,097kb
- Upload Time: 353ms
You can see that both the upload times and the memory usage were reduced by 8x!
Note: You can also use PVRTC2, which uses just 2bits/pixel, and would reduce memory even further, but with reduced image quality.
OK, but what’s the catch? There’s always a catch…
The catch is: Artifacts.
Block Based compression will create some level of artifacts within your images. Your mileage is going to vary depending on your art style.
The other small catch is File Size. Block Compression is not as efficient as PNG, and it will increase the size of your binary. Luckily, ATF incorporates lossless JPEG-XR compression, which limits the typical file increase to ~20%.
For the remainder of this tutorial we’ll look at how to create ATF files, and techniques to improve your image quality, while still retaining memory savings.
Part 2: Creating ATF Files
The first step to using ATF, is to create the files.
To do this we must use some special tools from Adobe, provided in the Gaming SDK . Within that SDK, you will find a folder called “ATFTools” and within that, a command line tool called “png2atf”, that is what we’ll use to create our ATFs.
Using png2atf is pretty straightforward, at it’s most basic form, you define an input (-i), output (-o) and block compression (-c):
> png2atf -c -i image.png -o image.atf
ATF includes a UserManual, but it’s a bit out of date. Also, the reference post I linked to above from the Flash Team is out of date! So, the best place to go, is right to the horses mouth:
We can ignore most of that when using Block Compression, but lets go over the ones that are important:
- “-c” : This option enabled block compression, creating DXT, ETC and PVRTC all within one file.
- “d,e,p” – Specify these aftyer “-c” to only include specific formats (ie “-c p,e” only PVRTC and ETC would be created, and DXT would be ommitted.
- “-r” : This is a flag to enable JPEG-XR lossless compression.
- “-e” : If you are not scaling your assets, you don’t need mip-maps. So you can use this to save some extra memory (Note: You must set mipMaps=false in Starling or the image won’t appear)
With those in mind, a nice command to use for production assets for iOS is:
> png2atf -c p -r -i image.png -o image.atf
The above command will create an ATF file, containing only PVRTC4, with lossless JPEG-XR applied on top of it.
Once you have the ATF file, rendering it with Starling is simple:
[Embed(source="starling.atf", mimeType="application/octet-stream")] public static const CompressedData:Class; var data:ByteArray = new CompressedData(); var texture:Texture = Texture.fromAtfData(data); var image:Image = new Image(texture); addChild(image);
NOTE: It’s worth noting that png2atf is not the only way to generate PVRTC files. You can generate them with a variety of industry standard tools, such as PVRTexTool from Imagination Technologies. These 3rd party tools tend to offer more options than png2pvr, and can produce superior results (or so I’m told… I haven’t dug into this too far). If you decide to use one of these tools to create the PVRTC, that’s all good, you can use another tool in the SDK called pvr2atf to wrap it as ATF. See the ATF User Manual for more info.
Part 3: Managing Texture Artifacts (aka Downscaling)
Typically Block Compression can create some pretty nasty texture artifacts, especially on lower resolution assets. This can be a major issue for your games if you really want to have crisp, clean beautiful artwork.
Luckily, Block Compression responds very well to hi-resolution assets, so we can take advantage of this to hide texture artifacts, while still getting a nice gain in performance. This is a similar technique to one you might’ve seen on the Web for handling Retina Displays. (tldr; Use lots of compression, export at hi-res, downscale to hide artifacts)
Here you can see our original uncompressed Blacksmith @ 1024px (scaled up 50% to highlight artifacts):
Once we apply PVRTC, he looks like this:
You can see compression all over the place on that image. His face, the letters on the sign, the sausages, it’s really ruining the overall clarity of the artwork.
If we author that same PNG @ 2x resolution, and scale it back down by 50%, we get something that looks like this:
You can see see that the compression artifacts have are almost completely non-existent, while our load times still seeing an excellent decrease of 70% over PNG, and we’ve still got a 50% memory savings. Dare we say, best of both worlds!?
Note that we’ve increased the size of our texture by 2x, but that is really overkill and was just to keep the example simple. From our testing, downscaling from 1.5x is more than enough to provide excellent results, and gives you even better performance.