GLSL imageStore Behavior for Raw Texels
This article provides an overview of the imageStore
function in GLSL, detailing how it writes raw texel data into image
variables. It covers function mechanics, type-matching rules, component
truncation, format conversions, out-of-bounds behavior, and the memory
coherency requirements necessary to ensure written values are read
correctly across shader invocations.
Function Signature and Core Mechanism
In OpenGL Shading Language (GLSL), imageStore is a
built-in function used to perform random-access writes to image
variables without blending or filtering. Its general signature is:
void imageStore(writeonly gimageIMAGE_PARAMS image, ivecCOORD_PARAMS P, gvec4 data);The function takes an image unit, an integer coordinate vector
matching the dimensionality of the target image, and a four-component
vector (vec4, ivec4, or uvec4)
containing the raw texel value to be written. The data type of the input
vector must match the underlying scalar type of the image format:
floating-point images require vec4, signed integer images
require ivec4, and unsigned integer images require
uvec4.
Component Truncation and Unused Channels
Regardless of the target image format, imageStore always
expects a four-component vector as the payload. When writing to formats
with fewer than four channels, excess components are discarded:
- Single-channel formats (e.g.,
r32f,r8): Onlydata.r(ordata.x) is written. Componentsy,z, andware ignored. - Two-channel formats (e.g.,
rg16f,rg32ui): Onlydata.rg(ordata.xy) are written. Componentszandware ignored. - Three-channel formats (where supported) and four-channel formats: Components are mapped directly to the available channels in order (R, G, B, A).
Data Conversion and Quantization
The raw values passed to imageStore undergo conversion
according to the memory format qualifier defined on the image variable
in the shader (or the bound texture's internal format):
- Floating-Point Formats (
rgba32f,rgba16f): Values are stored directly or rounded to the appropriate floating-point precision (e.g., 32-bit values are converted to half-precision floats for 16-bit targets). - Normalized Formats (
rgba8,r16_snorm): Floating-point values are converted to fixed-point integers. Unsigned normalized formats (unorm) clamp input values to the range[0.0, 1.0]before scaling to integer space. Signed normalized formats (snorm) clamp input values to the range[-1.0, 1.0]. - Pure Integer Formats (
rgba32i,rgba32ui,r8ui): Raw integer values are written without normalization. If the target format has fewer bits than the shader integer (e.g., writing tor8ui), values are truncated to the target bit depth.
Out-of-Bounds Behavior
If the coordinate P passed to imageStore
falls outside the valid dimensions of the target image, the write
operation is discarded. Unlike standard memory writes in native C/C++,
writing out of bounds via imageStore does not cause memory
corruption or a hardware fault; it acts as a safe no-op.
Memory Coherency and Visibility
Writes performed by imageStore are not automatically
coherent with subsequent memory reads. Because the graphics pipeline
executes work concurrently across cache domains:
- In-Shader Reads: If an invocation writes data with
imageStoreand later reads it viaimageLoad, the variable should be declared with thecoherentmemory qualifier. - Pipeline Barriers: For subsequent draw calls,
compute dispatches, or texture sampling operations to see texels written
by
imageStore, an explicit memory barrier must be issued on the host side (such asglMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT)orGL_TEXTURE_FETCH_BARRIER_BIT) or within the shader viamemoryBarrierImage().