Search code examples
opengltexturesdds-format

Loading DDS textures?


I'm reading about loading DDS textures. I read this article and saw this posting. (I also read the wiki about S3TC)

I understood most of the code, but there's two lines I didn't quite get.

blockSize = (format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ? 8 : 16;

and:

size = ((width + 3) / 4) * ((height + 3) / 4) * blockSize;

and:

bufsize = mipMapCount > 1 ? linearSize * 2 : linearSize;
  1. What is blockSize? and why are we using 8 for DXT1 and 16 for the rest?

  2. What is happening exactly when we're calculating size? More specifically why are we adding 3, dividing by 4 then multiplying by blockSize?

  3. Why are we multiplying by 2 if mipMapCount > 1?

Solution

  • DXT1-5 formats are also called BCn formats (it ends with numbers but not exactly the same ones) and BC stands for block compression. Pixels are not stored separately, it only stores a block of data for the equivalent of 4x4 pixels.

    The 1st line checks if it's DXT1, because it has a size of 8 byte per block. DXT3 and DXT5 have use 16 bytes per block. (Note that newer formats exist and at least one of them is 8 bytes/block: BC4).

    The 2nd rounds up the dimensions of the texture to a multiple of the dimensions of a block. This is required since these formats can only store blocks, not pixels. For example, if you have a texture of 15x6 pixels, and since BCn blocks are 4x4 pixels, you will need to store 4 blocks per column, and 2 blocks per row, even if the last column/row of blocks will only be partially filled.

    One way of rounding up a positive integer (let's call it i) to a multiple of another positive integer (let's call it m), is:

    (i + m - 1) / m * m
    

    Here, we need get the number of blocks on each dimension and then multiply by the size of a block to get the total size of the texture. To do that we round up width and height to the next multiple of 4, divide by 4 to get the number of block and finally and multiply it by the size of the block:

    size = (((width + 3) / 4 * 4) * ((height + 3) / 4 * 4)) / 4 * blockSize;
    //                         ^                        ^     ^
    

    If you look closely, there's a *4 followed by a /4 that can be simplified. If you do that, you'll get exactly the same code you had. The conclusion to all this could be comment any code that's not perfectly obvious :P

    The 3rd line may be an approximation to calculate a buffer size big enough to store the whole mipmap chain easily. But I'm not sure what this linearSize is; it correspond to dwPitchOrLinearSize in the DDS header. In any case, you don't really need this value since you can calculate the size of each level easily with the code above.