Direct State AccessGL 4.5

glCompressedTextureSubImage2D

Uploads already-compressed blocks (BC7, BC1, ASTC…) into one mip level of a texture.

Part of the family glTexSubImage*

Signature

void glCompressedTextureSubImage2D(GLuint texture, GLint level, GLint xoffset, GLint yoffset,
                                   GLsizei width, GLsizei height, GLenum format,
                                   GLsizei imageSize, const void *data);

How it works

Block-compressed formats store each 4×4 pixel block in a fixed number of bytes (8 for BC1, 16 for BC7), and the GPU decodes them while sampling. The data comes ready from a tool or a .dds / .ktx2 file; OpenGL only copies it.

Allocate the texture first with glTextureStorage2D and the same compressed format, then upload every mip level with one call each. imageSize is the byte count of that level: ceil(w/4) × ceil(h/4) × bytes per block.

Parameters

textureGLuint

Texture allocated with a compressed internal format.

levelGLint

Mip level.

xoffsetGLint

Left edge, a multiple of 4.

yoffsetGLint

Bottom edge, a multiple of 4.

widthGLsizei

Width of the region (the level's width for a full upload).

heightGLsizei

Height of the region.

formatGLenum

The compressed format, the same as the storage.

Common values

GL_COMPRESSED_RGBA_BPTC_UNORM / GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM
BC7: high quality colour, 16 bytes per block.
GL_COMPRESSED_RGB_S3TC_DXT1_EXT
BC1: 8 bytes per block, no real alpha.
GL_COMPRESSED_RG_RGTC2
BC5: two channels, for normal maps.
imageSizeGLsizei

Number of bytes in data.

dataconst void *

The compressed blocks.

Tips & pitfalls

  • Direct State Access (GL 4.5): the object is passed as a parameter, so nothing needs to be bound and no global state is disturbed.

  • A wrong imageSize gives GL_INVALID_VALUE and nothing is uploaded: the texture stays black.

Errors

When the call is invalid it does nothing and sets an error, which glGetError returns:

GL_INVALID_VALUE
imageSize does not match the size of the region in that format.
GL_INVALID_OPERATION
format differs from the texture's format, or the offsets are not block aligned.

Example

example.cpp
1glTextureStorage2D(tex, levels, GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM, w, h);
2for (int level = 0; level < levels; ++level) {
3    int lw = std::max(1, w >> level), lh = std::max(1, h >> level);
4    GLsizei bytes = ((lw + 3) / 4) * ((lh + 3) / 4) * 16;   // BC7
5    glCompressedTextureSubImage2D(tex, level, 0, 0, lw, lh,
6        GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM, bytes, blocks[level]);
7}
Official Khronos documentation