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:

  1. 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.
  2. 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 shaderRecordEXT is 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 buffer block, not a uniform block.
  • Memory Layout: Typically paired with std430 (or std140) to guarantee deterministic byte alignment matching host-side CPU data serialization.
  • Read-Only Behavior: In standard usage, variables inside a shaderRecordEXT block 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 shaderRecordEXT block 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.