Accessing Local Parameters with shaderRecordEXT in GLSL
The shaderRecordEXT storage qualifier enables Vulkan ray
tracing shaders written in GLSL to access local, per-pipeline parameters
directly from the Shader Binding Table (SBT). Instead of relying on
global descriptor sets or dynamic uniform offsets to bind per-geometry
or per-material resources, developers can embed custom parameter data
alongside shader identifiers. This article details the mechanics of the
shaderRecordEXT qualifier, its interaction with the Shader
Binding Table, how it is declared in GLSL, and the performance and
architectural advantages it provides in real-time ray tracing
pipelines.
The Role of the Shader Binding Table (SBT)
In Vulkan ray tracing (VK_KHR_ray_tracing_pipeline),
execution relies on the Shader Binding Table. The SBT is a GPU buffer
organized into sequential records. Each record consists of:
- A Shader Identifier: A fixed-size handle that indicates which shader program (ray generation, miss, closest hit, any hit, or callable) the GPU must execute.
- Local Shader Record Data: An optional block of arbitrary user-defined data placed immediately after the shader identifier.
When a ray interacts with geometry, the hardware uses the ray type, instance offsets, and geometry index to calculate an exact byte offset into the SBT. This offset points to the specific record for that hit or event.
How
shaderRecordEXT Maps to the SBT
The shaderRecordEXT layout qualifier instructs the GLSL
compiler and SPIR-V generator to bind a buffer block to the local data
payload within the currently executing SBT entry.
When the shader executes:
- The ray tracing hardware evaluates the address of the selected SBT entry.
- It steps past the shader group handle (sized according to
shaderGroupHandleSize). - The base address of the block qualified by
shaderRecordEXTis automatically resolved to the memory location immediately following the handle.
Because the offset computation is handled directly by ray tracing indexing formulas, the shader accesses its local parameters with zero descriptor binding overhead.
Declaring
shaderRecordEXT in GLSL
To use shaderRecordEXT, the
GL_EXT_ray_tracing extension must be enabled. The qualifier
is applied to a buffer block declaration:
#version 460
#extension GL_EXT_ray_tracing : require
#extension GL_EXT_buffer_reference : require
layout(shaderRecordEXT, std430) buffer ShaderRecord {
uint64_t vertexBufferAddress;
uint64_t indexBufferAddress;
vec4 baseColor;
int textureIndex;
};
void main() {
// Access parameters directly as block members
vec4 materialColor = baseColor;
int diffuseMapID = textureIndex;
}Key Declaration Rules:
- Block Type: Must be declared as a
bufferblock, not auniformblock. - Memory Layout: Typically paired with
std430(orstd140) to guarantee deterministic byte alignment matching host-side CPU data serialization. - Read-Only Behavior: In standard usage, variables
inside a
shaderRecordEXTblock are read-only because the SBT is populated during scene setup or acceleration structure updates, not modified by concurrent ray invocations. - Single Instance: Only one
shaderRecordEXTblock is permitted per ray tracing shader stage.
Parameter Addressing and Memory Indexing
When traceRayEXT triggers a closest hit or any hit
shader, the SBT address for the record is calculated internally as:
\[\text{Address} = \text{SBT Base} + (\text{InstanceOffset} + \text{GeometryIndex} \times \text{Stride} + \text{RayType}) \times \text{RecordSize}\]
Because the data exposed by shaderRecordEXT resides
physically inside this entry, accessing its fields requires no indirect
memory dereferencing through descriptor tables. If dynamic resources
such as vertex or index buffers are required, developers typically write
64-bit GPU device addresses (GL_EXT_buffer_reference) into
the shader record. The shader reads the 64-bit pointer directly from the
shaderRecordEXT block and immediately dereferences geometry
data.
Practical Advantages
- Elimination of Descriptor Set Churn: Materials and geometric meshes do not require individual descriptor sets or massive bindless arrays indexed by draw IDs.
- Cache Locality: Loading the shader identifier and its immediate execution constants occurs in the same memory transaction or contiguous cache lines.
- Pipeline Simplification: Decouples pipeline state from resource binding, allowing thousands of distinct materials to be handled cleanly within a single ray dispatch call.