Texture Compression Update (Alpha testing)

Texture Compression Update

We’ve previously had quite limited options for texture compression for our platforms.
The ones we’ve had have been mostly focused on mobile platforms (ETC1 and Pvrtc1).

Now we’ve updated our pipeline to support ASTC, ETC2, BCx and RGTC formats.
To do this, we use a library called Basis Universal from Binomial.

What does it do?

Traditionally, textures are compressed on the development machine, into a format that (hopefully) is supported on the target user machine. However, if the target machine doesn’t support that format, you have to mitigate that somehow (e.g. separate bundles).

Basis Universal instead compresses into a generic format that gets shipped with the game.
When the game runs, we check what hardware compression formats are supported, and then ask the basis library to transcode the compressed basis texture into the hardware format we want.

That way you can use the same bundle for multiple versions (e.g. old and new android devices)

Texture Profiles

The way it works is that you choose a texture format (say TEXTURE_FORMAT_RGBA) for a set of textures.
Then you choose the compression type.

If you chose DEFAULT, which means no compression, you’ll get the format you asked for at runtime and the data will be uploaded to the GPU uncompressed. This might be good if you wish to upload a new version of the texture at runtime.

If you chose BASIS_UASTC, the texture will be compressed into a .basis file (internally), with possible mipmaps.

Fallback strategy

Note that the texture format you specified, will now act as the fallback format, in case the graphics card didn’t support any suitable compressed formats.

You can see the actual code here
The current fallback strategy is fixed, and it favors quality over size (e.g. ASTC over Pvrtc1).


The size of the compressed texture stored on disc will be 1 byte per pixel. Also note that we have LZ4 compression on the entire game archive, so the actual size is a little bit smaller still.

To compress faster, the texture compiler itself uses up to 8 threads to compile the texture.
A big (commercial) project with ~1.5gb of textures takes ~15 minutes on my machine.
I also happen to know that the authors of Basis Universal are working on improving both the size of the compressed textures, and also the compression speed with ~2-3 times in the next few months.

At runtime, the texture will transcode into the final format before uploading to the GPU. This step takes ~5-15ms per texture. It is currently done on the loader thread, but one of the next tasks is to move the transcoding work to the texture upload thread.

Also, don’t forget to check the texture sizes at runtime using our Web Profiler!
It’s an easy way to see if the textures were uploaded to a hardware supported compression format on your device.


For engine size (and performance) reasons, the previous compression format WebP has been removed.
For backwards compatibility, we convert the compression type like so



Note that I’m also working on upgrading our OpenGL backend to support OpenGLES 3 and WebGL 2.
This is needed in order to support ETC2 on Android, and ASTC on iOS. I expect this work to be done in a few days.

Interestingly enough, the Android devices I have tested on, already support ASTC, so that’s something you can test right now.


We’d love to hear your experience with this feature, and to see if there are any issues that pop up.

You can get the build from the Alpha Download Page.


Fix the link, please! It doesn’t work.

That’s fantastic news! We’re going to use Basis for the upcoming 3d web game mentioned here.




I got my old test project and made a comparison.


WebP Safari:

Basis Safari:

WebP Chrome:

Basis Chrome:

Build size:

Basis 58.6Mb
WebP 23.5Mb

Basis zip 18.9Mb
WebP zip 16.9Mb


Device: Xiaomi Redmi Note 4





Build size:

Basis 20Mb
WebP 18Mb


Build size:

Basis 19.3Mb
WebP 17.3Mb

*Similar to webp, the first time is always much slower. But I didn’t make screenshots it this time.

**I’m going to improve the old test project and repeat all the measurements


Are these fonts? We have duplicate fonts with different materials set probably a better way to deal with that?


Doing testing with BASIS_UASTC now.

1 Like

Is LZ4 compression not efficient for Basis textures? Looks like the game archives are not compressed at all.


Compression must be enabled in the editor when building from the editor and testing a texture profile with BASIS_UASTC enabled otherwise you get errors.

ERROR:GRAPHICS: Failed to validate header (Basis) for file '/_generated_6a8c4c5.texturec'
ERROR:GAMESYS: Failed to transcode /_generated_6a8c4c5.texturec
ERROR:GAMESYS: No matching texture format found for /_generated_6a8c4c5.texturec. Using blank texture.

Loading seems to be faster with BASIS_UASTC enabled but need to do more testing. Final file size seems larger but need to test that more too.

1 Like

@agulev What are the “zip” files? Are they the game bundle? Or just the build folder zipped up?

@aglitchman There is currently work being done for the uastc compression to make it being more “compressible” by LZ4 (or any other), with minimal quality loss. You can follow the developer Rich Geldrich on Twitter for a lot of updates and details regarding this.


Just a zipped bundle folder.

1 Like

@pkeod No, fonts have the suffix “.fontc”.

We disassemble each font into separate glyphs (raw data), which we then compress individually. We do this since we use a texture atlas which we populate with the small glyphs as they are used, and evict older glyphs as needed.

Since we removed WebP, we now use Deflate for compression, so the sizes grew a little bit. (from 55% to 66%)

I have a PR coming up that will bring the compression of the glyphs back to 62% (On 26 MB fonts, it previously compressed to 17.6mb with deflate, now it compresses to 16.6 mb)

The next big thing for fonts is to add an api to dmSDK that lets extensions provide the actual glyphs themselves to the engine. That, I think will be a huge space saver.


What’s an easy way to figure out what the /_generated_f6cce506.texturec files are? There are apparent duplicates in size which concern me.

Agreed, the naming is an issue. You could try to add “-v” to bob (if you’re using it that is), to perhaps see which atlas becomes which texture.
If it doesn’t, I should add it :confused:

Unfortunately, the editor is more “clever” and merges all output that has the same checksum (not sure how often that happens though), so the same .texturec could potentially have multiple source files.


Since @Jerakin asked for some numbers from my testing.
Thanks to this I found a thing I had forgot to change, add the LZ4 compression on the textures(!). It was previously turned off since minimal impact on the WebP compressed textures.

  • 5 textures (256x256) 2xRGB, 2xRGBA, 1xR
  • With mipmaps
  • macOS

Build times

WebP (lossy)      14.808s
WebP (non lossy)  14.816s
Basis             7.035s

Size on disc: (game.arcd) (LZ4 compressed):

WebP (lossy)      313930
WebP (non lossy)  315906
Basis             395526

the uncompressed basis textures were 645846 bytes

Runtime decompress/transcode

WebP (lossy)      5 textures / 327680 texels in 7.487000 ms
WebP (non lossy)  5 textures / 327680 texels in 7.310000 ms
Basis             5 textures / 436905 texels in 4.886000 ms

I calculated the texel count is more accurate on basis. They should be the same

Update The average LZ4 compression of the basis textures are ~42% of the original size.
Also note that we anticipate even more compression ratio improvements from Basis Universal, as they continue to develop it as we speak.


Some engine size numbers (since I know @AGulev wants to know :wink: )

Release builds, stripped


1.2.179 2635564
1.2.180 2553284

-80kb (~3%)

arm64-android (dmengine.apk)

1.2.179 2024820
1.2.180 2092295

+64kb (~3%)


1.2.179 2160378
1.2.180 2187290

+~26 kb (~1%)

32 kb was added for the WebGL 1 fallback

In all honesty, I would have thought that the engine would have decreased even more since WebP was quite big. But I guess they were more or less the same size then. :man_shrugging:


There is a new alpha build available, with LZ4 compression enabled for the textures.


Piggybacking on this topic, but as I’m trying to compress my resources for iOS and Android. How do you know which FORMAT to chose?

Luminance, Luminance alpha etc don’t sound familiar, I don’t know which one to chose from. I use regular pngs and spines, which one would you pick and why? Thanks

(If this is off topic I will delete my post)

1 Like

Check out this thread


awww, thx!

Then it’s time to exclude the video recorder by default! =) For me it was a surprise that webp and the recorder uses separate codecs lib. I was sure the recorder use the format it uses just to avoid using separate vpx lib.


Yes. But also note that the video recorder is excluded by default on release builds, so you won’t save anything there