KTX2 Compressed Textures


Using GPU compressed textures is becoming more and more important in the computer graphics / gaming land as it allows to use more assets within the same memory budget and provides better performances by reducing cache misses on the GPU side.

Note that we are speaking about GPU compressed textures, meaning textures that remain compressed on the GPU board. That's different from a .png or .jpg file, for eg, that holds compressed data too but which must be expanded before being sent to the GPU.

Working with compressed texture formats

There are a number of compression formats used by the industry (ASTC, DXT, PVRTC, etc), and depending on your device it will generally support only a (small) subset of them : see the table here for more details. So, to support a wide range of devices, you would need to provide your assets in multiple different formats and Babylon.js would choose the right one depending on the capability of the target device.

It can be a bit tedious to generate and maintain so many formats for a given asset, so container files have been created. These files can either contain multiple formats of the same asset or be transcodable to multiple formats, and being the subject of this article we are going to deal with the KTX2 container file format.

KTX2 container

KTX stands for Khronos Texture Container and the current incarnation is v2.0 (we won't discuss v1 version) and the associated file format extension is .ktx2.

This file does not in fact contains different formats of the same asset but a universal representation of the data that can be transcoded to any format supported by the target device! We are speaking of transcoding instead of expanding because the data are not expanded per se, they are transformed to another compressed format, one supported by your target device (the universal representation being itself compressed).

Currently, the universal representation is generated by using a compression algorithm known as Basis Universal, or BasisU for short, created by a company named Binomial. This algorithm supports two modes :

  • ETC1S : original low/medium quality mode, produces lower file size. Work best on images, photos, map data or albedo/specular/etc textures, but don't work as well on any data that are not true color data (like normal maps, metallic/roughness maps, etc)
  • UASTC : high quality mode, can be used on any type of textures, even for non color data maps

On top of this compression, the data can be further compressed in the UASTC case by using a Zstandard compression scheme. Note however that this additional compression pass can lead to smaller .ktx2 file sizes but not smaller GPU compressed textures ! The data compressed with Zstandard will be expanded on the CPU side and then will be transcoded to a GPU texture.

Note that .ktx2 files can also store GPU compressed non-universal data, but as far as Babylon.js is concerned it is only dealing with the ETC1S and UASTC universal compression schemes listed above.

Babylon.js support for .ktx2 files

On Babylon.js side, using such files is a breeze: just create a Texture instance by pointing to the .ktx2 file you want to use, as you would with any other standard picture format (png, jpg, etc) !

The KTX2 format is also used in the glTF world by means of the KHR_texture_basisu extension : this extension simply enables you to use .ktx2 files for the images used by your .gltf/.glb files and is supported by Babylon.js.

The KTX2 implemention of Babylon.js is developped as an external package (the KTX2 decoder) designed to be small (the minified .js file is less than 22kb) and efficient. Depending on the universal representation of the data in the .ktx2 file and the compressed formats supported by the target device, the right module is used for the transcoding. Whenever possible, the Universal Texture Transcoders (UTT) are used, as they are both very fast and small. For transcoding formats not supported by the UTTs (yet), the MSC Basis Transcoder module is used instead.

Note : you may have already encountered/heard of .basis files. Those files are using the same compression scheme than the .ktx2 files but this format is not baked by any standard committee, contrary to the KTX2 format. So, you should prefer using the latter as it will become the de-facto standard.


Now that you know why you should use .ktx2 files, you will need to actually generate them !

Khronos is providing command line tools that you can use to generate / check / dump .ktx2 files :

  • toktx.exe is the primary tool, used to generate .ktx2 files from .png, .jpg files. There are a handful of options, just type toktx.exe to display them
  • ktxinfo.exe will display useful data in human readable form about a .ktx2 file
  • ktx2check.exe will check that your .ktx2 file is a valid file
  • ktxsc.exe will allow you to update some parameters of an existing .ktx2 file (change the compression scheme, add a Zstandard compression, etc)

Happy compressions !