Every KTX 2 file starts with an 80-byte header and index, followed by one level index entry per mipmap level. All numbers are little-endian. This page follows the Khronos KTX File Format Specification, version 2.0.
Header
| Offset | Size | Field | Meaning |
|---|---|---|---|
| 0 | 12 | identifier | AB 4B 54 58 20 32 30 BB 0D 0A 1A 0A: «KTX 20», CR LF, Ctrl-Z, LF. |
| 12 | 4 | vkFormat | The Vulkan VkFormat of the texels (below). 0, VK_FORMAT_UNDEFINED, when no Vulkan format fits. |
| 16 | 4 | typeSize | Size in bytes of the data type, for byte swapping on big-endian machines. 1 for block-compressed formats and for VK_FORMAT_UNDEFINED. |
| 20 | 4 | pixelWidth | Width of the base level in pixels; never 0. |
| 24 | 4 | pixelHeight | Height of the base level; 0 only for a 1D texture. |
| 28 | 4 | pixelDepth | Depth of the base level; 0 for anything but a 3D texture, and always 0 for depth and stencil formats. |
| 32 | 4 | layerCount | Number of array layers; 0 if the texture is not an array. |
| 36 | 4 | faceCount | 6 for a cube map or cube map array, otherwise 1. |
| 40 | 4 | levelCount | Mipmap levels stored. 1: only the base level, and no more should be made. 0: only the base level, and a loader may generate the rest (not allowed for block-compressed formats). Never more than the full chain for the largest dimension. |
| 44 | 4 | supercompressionScheme | How the levels are supercompressed; 0 for none (see supercompression). |
Index
| Offset | Size | Field | Meaning |
|---|---|---|---|
| 48 | 4 | dfdByteOffset | File offset of the data format descriptor. |
| 52 | 4 | dfdByteLength | Its length; equal to its own dfdTotalSize. |
| 56 | 4 | kvdByteOffset | File offset of the key and value data; 0 when there is none. |
| 60 | 4 | kvdByteLength | Its length including padding; 0 when there is none. |
| 64 | 8 | sgdByteOffset | File offset of the supercompression global data; 0 when there is none. |
| 72 | 8 | sgdByteLength | Its length; 0 unless the scheme uses global data. |
Level index
From offset 80, max(1, levelCount) entries of 24 bytes, the base (largest)
level first:
| Offset in entry | Size | Field | Meaning |
|---|---|---|---|
| 0 | 8 | byteOffset | File offset of the level’s data, after any padding. |
| 8 | 8 | byteLength | Bytes of the level as stored, which may be supercompressed, for all layers, faces and slices. |
| 16 | 8 | uncompressedByteLength | Bytes once the supercompression is undone. Equal to byteLength with no supercompression; 0 for BasisLZ. |
Order of the sections
- Identifier, header and index (80 bytes), then the level index.
- The data format descriptor, with no padding after it.
- The key and value data, if any, each entry padded to 4 bytes.
- Zero padding to a multiple of 8, then the supercompression global data, if any.
- The mipmap levels, from the smallest to the largest: the reverse of the level index.
When there is no supercompression, each level is preceded by 0 or more zero bytes
(mipPadding) so it starts on a multiple of
lcm(texel block size, 4). Supercompressed levels are not padded. The texel
block size comes from Vulkan’s format compatibility classes, except that
VK_FORMAT_D16_UNORM_S8_UINT counts as 4 and
VK_FORMAT_D32_SFLOAT_S8_UINT as 8; for VK_FORMAT_UNDEFINED it
comes from the data format descriptor.
Inside a level
- For each layer, for each face, for each z slice, for each row of texel blocks, the blocks from left to right.
- Rows are tightly packed, with no row padding (like
GL_UNPACK_ALIGNMENT1). - Faces are in the order +X, −X, +Y, −Y, +Z, −Z.
- For a cube map,
uncompressedByteLengthdivides evenly byfaceCount × max(1, layerCount).
vkFormat
Any VkFormat may be used except the scaled formats (every
*_USCALED* and *_SSCALED*) and the multi-planar formats (every
*_2PLANE_* and *_3PLANE_*). VK_FORMAT_UNDEFINED is
used for BasisLZ (ETC1S) data, for UASTC data, and for formats known only to OpenGL,
Direct3D or Metal, which are then named by the KTXglFormat,
KTXdxgiFormat__ or KTXmetalPixelFormat keys. With Zstandard or
zlib supercompression, vkFormat is the format before compression.
| vkFormat | Name |
|---|---|
| 0 | VK_FORMAT_UNDEFINED |
| 37 | VK_FORMAT_R8G8B8A8_UNORM |
| 43 | VK_FORMAT_R8G8B8A8_SRGB |
| 44 | VK_FORMAT_B8G8R8A8_UNORM |
| 97 | VK_FORMAT_R16G16B16A16_SFLOAT |
| 109 | VK_FORMAT_R32G32B32A32_SFLOAT |
| 122 | VK_FORMAT_B10G11R11_UFLOAT_PACK32 |
| 123 | VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 |
| 131 | VK_FORMAT_BC1_RGB_UNORM_BLOCK |
| 137 | VK_FORMAT_BC3_UNORM_BLOCK |
| 143 | VK_FORMAT_BC6H_UFLOAT_BLOCK |
| 145 | VK_FORMAT_BC7_UNORM_BLOCK |
| 147 | VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK |
| 151 | VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK |
| 157 | VK_FORMAT_ASTC_4x4_UNORM_BLOCK |
These are a few common values; the full list is in the Vulkan specification.
A header
The first 80 bytes of a 256 by 256 VK_FORMAT_R8G8B8A8_SRGB texture with 9
levels and no supercompression. The level index takes 9 × 24 bytes from offset 80, so
the 92-byte data format descriptor starts at offset 296 (0x128).
00000000 AB 4B 54 58 20 32 30 BB 0D 0A 1A 0A 2B 00 00 00
00000010 01 00 00 00 00 01 00 00 00 01 00 00 00 00 00 00
00000020 00 00 00 00 01 00 00 00 09 00 00 00 00 00 00 00
00000030 28 01 00 00 5C 00 00 00 00 00 00 00 00 00 00 00
00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00