API

KTX2 Compressed Textures

Introduction

Using GPU compressed textures is becoming more and more important in the computer graphics / gaming world because it allows you to use more assets within the same memory budget and provides better performance 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. That's different from a .png or .jpg file, for example, which also holds compressed data but 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. Because this is 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 version 1), and the associated file format extension is .ktx2.

This file does not in fact contain different formats of the same asset, but rather a universal representation of the data that can be transcoded to any format supported by the target device! We speak of transcoding instead of expanding because the data are not expanded per se; they are transformed into another compressed format, one supported by your target device (the universal representation is 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 sizes. Works best on images, photos, map data, or albedo/specular/etc. textures, but does not work as well on 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 texture, 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 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 only deals with the ETC1S and UASTC universal compression schemes listed above.

Babylon.js support for .ktx2 files

On the Babylon.js side, using such files is a breeze: just create a Texture instance that points 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 implementation of Babylon.js is developed 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 or heard of .basis files. Those files use the same compression scheme as .ktx2 files, but this format is not backed by any standards committee, unlike the KTX2 format. So, you should prefer the latter, as it will become the de-facto standard.

Tools

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

Khronos provides command line tools that you can use to generate, check, and 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 compressing!