Updated Crunch texture compression library

Crunch is a lossy texture compression format, which is normally used on top of DXT texture compression. Crunch compression helps to reduce the size of the textures in order to use less disk space and to speed up downloads. The original Crunch compression library, maintained by Binominal, is available on GitHub. Support for Crunch texture format was first added in Unity 5.3. In Unity 2017.3, we are introducing an updated version of the Crunch compression library.

Textures compressed with Crunch are first decompressed to DXT and then uploaded to the GPU at runtime. Crunched textures not only use less space, but they can be also decompressed really fast. This makes the Crunch format very efficient for distributing textures. At the same time, Crunched textures can take quite a lot of time to compress, which is a major drawback when using Crunch (for a big project, compression of all the textures into Crunch format can take several hours in the Editor).

The updated Crunch library, introduced in Unity 2017.3, can compress DXT textures up to 2.5 times faster, while providing about 10% better compression ratio. But more importantly, the updated library is now capable of compressing ETC_RGB4 and ETC2_RGBA8 textures, which makes it possible to use Crunch compression on iOS and Android devices. This should help you reduce the build sizes of your mobile games, and thus make it easier to comply with App Store over-the-air size limitations, ultimately letting you reach a wider audience for your content.

In order to use Crunch compression on Android, iOS and tvOS platforms, you can now select either “RGB Crunched ETC” or “RGBA Crunched ETC2” format for your textures in the inspector window. If you enable the “Use Crunch Compression” option in the Default tab, all the textures on Android platform will be compressed with ETC Crunch by default.

In the near future, the Crunch compression library will be improved even further. The latest version of the library, which will reach Beta builds soon, will be able to perform Crunch compression of DXT textures about 5 times faster than the original version, and speed up Crunch compression of ETC textures about 1.3 times. The latest version of the Crunch library can be found in the following GitHub repository: https://github.com/Unity-Technologies/crunch/tree/unity (for those interested in the implementation details: thorough descriptions of the improvements made to the Crunch library can be found in the commit messages of this repository).

Size and performance comparison

The compression performance has been tested on two Unity projects available in the Asset Store: “Adam Character Pack: Adam, Guard, Lu” and “Adam Exterior Environment”. Testing has been performed in Windows Editor, running on i7-4790, 3.6GHz, using default Crunch quality settings.

Compressing textures with Crunch using DXT encoding

When using the updated compression library, DXT textures can be compressed significantly faster and with better compression ratio. At the same time, the updated library fully preserves the original compression quality. In fact, decompressed textures, generated by both libraries, are identical bit by bit.

Compressing textures from the “Adam Character Pack: Adam, Guard, Lu” project with Crunch using DXT encoding (93 textures with total size of 652.7 MB in uncompressed DXT format):

Unity 2017.2.0f3

Unity 2017.3.0b5

Compressed size

142.8 MB

128.7 MB

Compression time

39.0 minutes

15.9 minutes

Compressing textures from the “Adam Exterior Environment” project with Crunch using DXT encoding (227 textures with total size of 717.8 MB in uncompressed DXT format):

Unity 2017.2.0f3

Unity 2017.3.0b5

Compressed size

156.3 MB

138.1 MB

Compression time

45.1 minutes

19.5 minutes

Compressing textures with Crunch using ETC encoding

Crunch compression of ETC_RGB4 and ETC2_RGBA8 textures is performed in a similar way to compression of DXT textures, except that textures are decompressed into ETC/ETC2 format and then uploaded to the GPU at runtime. ETC and DXT formats have quite a lot in common, which allowed us to modify the original Crunch algorithm in such a way, so that it can now be used for compression of both formats. The default quality parameters for ETC Crunch encoding have been selected in such a way, that ETC Crunch compression gives approximately the same average Luma PSNR as DXT Crunch compression.

The following table shows the performance test results for Crunch compression when using ETC/ETC2 encoding:

Project

Uncompressed size (ETC/ETC2)

Compressed size
(Crunched ETC/ETC2)

Compression time

Adam Character Pack: Adam, Guard, Lu (93 textures)

541.4 MB

112.2 MB

23.5 minutes

Adam Exterior Environment (227 textures)

588.2 MB

118.0 MB

25.8 minutes

Quality comparison

Below you can see the examples of the textures compressed with Crunch using default quality settings. Note that the artifacts on the final textures are introduced both by Crunch compression and selected GPU texture format (DXT or ETC).

Nice feature but what with not compressed images, is there any plan to provide lossless and loss compression formats for RGBA and other RAW pixel formats? Will be nice to get availability to use even PNG or JPEG file formats to decrease build size. Another nice feature will be provide dithering setting for images with decreased bits per pixel ration, right now setting RGBA4444 for imported RGBA8888 is useless, I always prepare images with smaller color depth with external tools and I can’t easily switch between it for different build targets. Sadly compression is still not god option for many cases in 2D games.

Yes, there are plans to add lossless compression for RGB and RGBA images (no specific ETA at the moment).

Regarding the RGBA4444 format. If I understand correctly, you are using it not to reduce the size of the texture on GPU, but rather to reduce the download size. If this is the case, then you are basically asking about a lossy compression format, providing higher quality (and most likely larger file size) than standard GPU compression formats (i.e. DXT or ETC), preferably having a variable quality parameter, which can be decompressed into RGB24 or RGBA32 at runtime? I think such an option would be useful and might be considered in the future.

I read my comment second time and indeed it’s not clear about which compression I think. :)

When I write this comment I think about runtime decompressed file formats and decreasing build size. Modern devices have at least 1GB RAM and more but we still have middle ages limits on mobile app stores and not always significantly bigger mass storage than older devices – It’s not a problem to run one, eye candy game, but storing many of them and sharing space with user files is a real problem. I also think about any images compression (raw and GPU compressed formats, like PVR still can be better compressed using lossless algorithms), but for RGB24/RGBA32 is the most painful and best visible. For example on iOS application all assets are fully decompressed from IPA during installation and high quality (RGB/RGBA) images eats hundreds MiB of disk space which is not necessary. Also Android APK file format is not good enough to work with RAW pixels, PNG and JPEGS are far, far batter for this task. Also I think that loading 64MiB raw data from disk direct to GPU memory is slower (at least on some devices with cheaper flash) than reading and decoding regular PNG or JPEG files.

Right now we deal with this using asset bundles stored in streaming assets, but… I sometimes think it’s overcomplicated, especially when I think about games write in past with good, old Cocos2D. ;)

Crunched ETC textures without alpha should work on all iOS and Android devices, as ETC is required by the GLES2 spec. Crunched ETC textures with alpha require ETC2 support (as ETC1 has no support for alpha), which is always supported by GLES3 (it is part of the spec) and Metal. On GLES2, some Android devices support ETC2 – but on iOS or on unsupported Android devices, Crunched ETC2 textures need to be decompressed to RGBA at runtime.

Turns out I was wrong here. ETC1 is not required by the GLES2 spec, so it is not supported on iOS on GLES2 (only on GLES3). It is supported by most Android devices via GL extension, but there may be some old devices where it has to fall back to decompressing to RGBA.

Is using crunch compression beneficial, if the player and/or asset bundles use compression too? As I understand crunch compressed textures, it’s all about how much space they occupy on the file system, but if the asset bundle is compressed already, where is the win when using crunched textures?

If I use crunch compression and compressed asset bundles, I assume Unity needs to decompress that twice? First the data from the asset bundle and then the texture. Does this affect the cost to load textures?

This is a good question. Whether you can gain something from compressing an already crunched texture or not depends on the texture contents. Crunch is using Huffman coding for entropy encoding, so in some special cases (i.e. a large empty texture) the gain can be significant. In practice however, such special cases are not very common and normally the gain is minimal. Let’s consider the “Adam_LOD_01_a” texture (displayed in the Inspector window on the screenshot above):

As you can see, LZMA does not give much gain when used for compression of average crunched textures, especially considering LZMA decompression time. So if you have an asset bundle which contains only crunched textures, it makes sense not to use LZMA on top of it.

Note that advantage of Crunch format is not just small size of compressed texture in memory, but also very fast decompression. This is exactly why it is using Huffman coding (even though other encoding could provide better compression ratio).

If I understand this correctly, crunched textures might improve loading times and reduce file size, if I store them in an uncompressed asset bundle. In this case, it might perform even faster than using non-crunch textures in a LZMA compressed bundle.

Yes, a crunched texture without post-compression is normally 2-2.5 times smaller than non-crunched texture compressed with LZMA, therefore it will be downloaded much faster. Moreover, Crunch decompression is significantly faster than LZMA decompression, therefore such a texture will also be decompressed much faster. This is, however, achieved at the expense of reduced image quality.

You can still use additional compression for an asset bundle containing crunched textures. Just note that efficiency of such additional compression step depends on the texture contents, download speed and available resources on the client side.

Awesome stuff. These are the things that actually move Unity forward for developers (other examples include the texture importer settings rewrite sometime late in 5.x, moving WWW to use UnityWebRequest, and countless other good little things). Thank you.

There, you’ve talked about it in a blog. You may now resume putting your public-facing focus back on the never ending trail of stillborn high-level features (UI, HLAPI networking, new navmesh, don’t start me on the 2017.x big-bullet features…) to talk about in keynotes.