Query Image Dimensions with GLSL imageSize

The GLSL imageSize built-in function provides shaders with the ability to retrieve the runtime dimensions of bound image variables without performing manual uniform updates from the CPU. This article explains how imageSize operates, its syntax and return formats across different image target types, the distinction between it and traditional texture queries, and how it evaluates bound mipmap levels.

How imageSize Functions

The imageSize function inspects the internal state of a bound image unit to determine its width, height, depth, or layer count. Unlike traditional texture sampling functions that operate on opaque sampler* types, imageSize is designed specifically for read/write image variables (image1D, image2D, image3D, imageCube, and their array or signed/unsigned variants) introduced in OpenGL 4.2 and GLSL 4.20 via the GL_ARB_shader_image_load_store extension.

When invoked, the function does not read texel data or access texture filtering hardware. Instead, it extracts the dimension metadata directly from the texture descriptor currently bound to the image unit.

Return Types and Dimension Mapping

The return type of imageSize depends directly on the dimensionality of the target image variable. The returned integer values represent texel counts along each axis:

  • 1D Images (image1D): Returns an int representing the width in texels.
  • 2D Images (image2D, imageCube, imageRect): Returns an ivec2 containing (width, height). For cube maps, it returns the dimensions of a single face.
  • 3D Images (image3D): Returns an ivec3 containing (width, height, depth).
  • Array Images (image1DArray, image2DArray, imageCubeArray): The last component of the vector represents the number of layers. For instance, calling imageSize on an image2DArray returns an ivec3 formatted as (width, height, layer_count).
  • Multisample Images (image2DMS, image2DMSArray): Returns an ivec2 or ivec3 indicating spatial dimensions; sample counts are not part of the return vector and must be queried separately using imageSamples.

Target Mipmap Level Evaluation

A critical distinction between imageSize and the sampler-based textureSize function is how levels of detail (LOD) are handled:

  1. textureSize accepts an explicit LOD parameter to query specific mipmap levels of a complete texture object.
  2. imageSize does not take an LOD parameter. Images are bound to shader execution units using host-side API commands such as glBindImageTexture, which explicitly binds a single, specific mipmap level. Consequently, imageSize returns the exact dimensions of that bound mipmap level rather than the base level dimensions.

Usage in Boundary Checking

A primary use case for imageSize is in compute shaders executing image processing tasks, where invocations must ensure write operations do not exceed the boundaries of the storage buffer:

layout(local_size_x = 16, local_size_y = 16) in;
layout(rgba32f, binding = 0) uniform writeonly image2D u_outputImage;

void main() {
    ivec2 pixelCoords = ivec2(gl_GlobalInvocationID.xy);
    ivec2 imgDimensions = imageSize(u_outputImage);

    // Prevent out-of-bounds writes
    if (pixelCoords.x >= imgDimensions.x || pixelCoords.y >= imgDimensions.y) {
        return;
    }

    imageStore(u_outputImage, pixelCoords, vec4(1.0, 0.0, 0.0, 1.0));
}

By querying the metadata dynamically at execution time, shaders remain decoupled from hardcoded resolution uniforms, ensuring flexibility across dynamic render targets and viewport sizes.