Structural Layout of KTX 2.0 Files in glTF

This article provides a direct overview of the binary structure and layout of the Khronos Texture 2.0 (KTX 2.0) container format as used within glTF 2.0 assets via the KHR_texture_basisu extension. KTX 2.0 acts as the standardized packaging format for universal GPU texture compression technologies—specifically Basis Universal (ETC1S and UASTC)—allowing textures to be stored compactly and transcoded on the fly to a target device's native GPU format.

1. File Identifier (Magic Number)

Every KTX 2.0 file begins with a fixed 12-byte sequence that identifies the file and ensures endianness validation:

  • Byte Sequence: 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x32, 0x30, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A (ASCII representation: «KTX 20»\r\n\x1A\n).

2. Header

Immediately following the identifier is a 68-byte fixed-size header composed of 17 contiguous 32-bit unsigned integers (little-endian):

  • vkFormat: The Vulkan format identifier. In glTF assets using KHR_texture_basisu, this value is set to 0 (VK_FORMAT_UNDEFINED), signaling that the payload uses Basis Universal compression rather than a fixed hardware format.
  • typeSize: Data type size in bytes (set to 1 when vkFormat is 0).
  • pixelWidth: Width of the base level (level 0) in pixels.
  • pixelHeight: Height of the base level in pixels (must be 0 for 1D textures).
  • pixelDepth: Depth of the base level for 3D textures (must be 0 for 2D textures).
  • layerCount: Number of array layers (set to 0 or 1 for standard non-array textures).
  • faceCount: Number of cubemap faces (6 for cubemaps, 1 for all other textures).
  • levelCount: Number of mipmap levels. Must be at least 1.
  • supercompressionScheme: Identifies secondary compression. Common values in glTF include 1 (BasisLZ, typical for ETC1S) or 2 (Zstandard, often paired with UASTC).
  • Offsets and Lengths: Five pairs of 32-bit values define the locations and sizes of subsequent metadata blocks:
    • dfdByteOffset and dfdByteLength
    • kvdByteOffset and kvdByteLength
    • sgdByteOffset and sgdByteLength

3. Level Index

Located immediately after the header, the level index consists of an array of records for each mip level specified by levelCount. Each record is 24 bytes long and contains three 64-bit unsigned integers:

  • byteOffset: Byte offset from the start of the file to the start of the image data for that level.
  • byteLength: Length of the compressed image data in bytes.
  • uncompressedByteLength: Size of the uncompressed data in bytes (used for supercompression decoding).

Levels are indexed from 0 (base level, highest resolution) to levelCount - 1 (smallest mip level).

4. Data Format Descriptor (DFD)

The DFD block defines color channels, color spaces, and transfer functions according to the Khronos Data Format Specification. For glTF KTX 2.0 textures:

  • It specifies whether the texture is encoded in sRGB or linear color space (critical for differentiating base color maps from normal/roughness maps).
  • It defines channel mapping (e.g., RGB, RGBA) and sample bit depths.

5. Key/Value Data (KVD)

This block stores arbitrary key-value metadata pairs. Each entry contains a length prefix, a null-terminated UTF-8 key string, and the associated value. In glTF workflows, common keys include:

  • KTXwriter: Software used to generate the file.
  • KTXglTF: Metadata indicating compatibility and usage flags inside glTF engines.

6. Supercompression Global Data (SGD)

If the texture uses Basis Universal ETC1S (supercompressionScheme = 1), this section contains the global codebooks, endpoint tables, and selector tables required to reconstruct the mip level data. For UASTC with Zstandard or uncompressed files, this section is omitted and its length is set to 0.

7. Mip Level Array Data (Payload)

The final section of the container holds the actual texture payload. The data for each mip level is stored at the location specified in the Level Index, typically ordered from the lowest resolution mip level up to the highest resolution (level 0). Each level must be aligned to a multiple of its element size or a minimum of 4 bytes. Inside glTF, runtime loaders transcode these compressed blocks directly into target hardware formats (such as BCn, ASTC, or ETC2).