The surfaces follow the header directly, at offset 128, or at offset 148 with a DX10 header. There is no index: a reader works out where each surface is from the format and the sizes.
Pitch and level size
dwPitchOrLinearSize is unreliable, because libraries have filled it in
inconsistently, so Microsoft recommends computing it:
| Formats | Pitch in bytes |
|---|---|
| Block-compressed | max(1, (width + 3) / 4) × block size. The block size is 8 for DXT1, BC1 and BC4, and 16 for other block formats. |
R8G8_B8G8, G8R8_G8B8, UYVY, YUY2 | ((width + 1) >> 1) × 4 |
| Other formats | (width × bits per pixel + 7) / 8 |
The size of one level of a block-compressed texture is
max(1, (width + 3) / 4) × max(1, (height + 3) / 4) × block size. The pitch
the runtime supplies is not always the same as this, so Microsoft recommends copying a
scan line at a time.
A texture with mipmaps
The main image is followed by each smaller level, down to the last. A 256 by 256
uncompressed R8G8B8 texture holds:
| Part | Bytes |
|---|---|
| Header | 128 |
| 256 by 256 main image | 196608 |
| 128 by 128 | 49152 |
| 64 by 64 | 12288 |
| 32 by 32 | 3072 |
| 16 by 16 | 768 |
| 8 by 8 | 192 |
| 4 by 4 | 48 |
| 2 by 2 | 12 |
| 1 by 1 | 3 |
With compression, levels smaller than 4 by 4 pixels still take a full block: 8 bytes for DXT1, 16 bytes for DXT2 to DXT5.
Cube maps
Faces are written in the order positive x, negative x, positive y, negative y, positive z, negative z, leaving out any missing face. Each face is its main image and then its mipmaps. All faces are the same size with the same number of levels, and since DirectX 8 a cube map has all six faces.
In Direct3D 10 and later a cube map is a 2D texture array of 6 images, written with a
DX10 header. An array of cube maps has arraySize cubes and so
arraySize × 6 images.
Volume textures
Without mipmaps, each depth slice is written in order. With mipmaps, all slices of one level are written together, and each level has half as many slices as the one before, with a minimum of 1. A 64 by 64 by 4 volume of 3-byte pixels with all levels holds four 64 by 64 slices, then two 32 by 32 slices, then one each of 16 by 16, 8 by 8, 4 by 4, 2 by 2 and 1 by 1.
Texture arrays
With a DX10 header, array elements follow each other, and each element holds its full set of mipmap levels:
for (element = 0; element < arraySize; element++)
for (level = 0; level < dwMipMapCount; level++)
...the surface...