How sbtRecordStride Works in GLSL traceRayEXT

In Vulkan ray tracing, the sbtRecordStride parameter in GLSL’s traceRayEXT function directly controls how the GPU indexes through hit group records in the Shader Binding Table (SBT) when a bottom-level acceleration structure (BLAS) contains multiple geometries. By acting as a multiplier against the internal geometry index, sbtRecordStride dictates the stride between consecutive geometry records, enabling shaders to efficiently multiplex between different ray types—such as primary, shadow, or ambient occlusion rays—without requiring separate acceleration structures.

The Hit Group Indexing Formula

When a ray intersects a geometry within a BLAS, the ray tracing pipeline calculates the index of the hit group shader record in the SBT using the following standard equation:

HitGroupIndex = instanceShaderBindingTableRecordOffset + 
                (geometryIndex * sbtRecordStride) + 
                sbtRecordOffset

In this formula:

  • instanceShaderBindingTableRecordOffset is defined on the CPU inside the VkAccelerationStructureInstanceKHR descriptor for the given instance.
  • geometryIndex is the zero-based index of the specific geometry within the BLAS that was intersected.
  • sbtRecordStride is passed dynamically via traceRayEXT.
  • sbtRecordOffset is passed dynamically via traceRayEXT to identify the specific ray type.

How sbtRecordStride Dictates Memory Progression

The primary purpose of sbtRecordStride is to handle instances where a single BLAS consists of \(N\) geometries and the application supports \(M\) ray types.

To organize the SBT for multiple ray types, hit groups are typically grouped by geometry or interleaved by ray type. The standard layout arranges the SBT so that each geometry has a dedicated block of shader records, with one record per ray type:

  • sbtRecordStride must equal \(M\) (the total number of ray types per geometry).
  • sbtRecordOffset must equal the index of the current ray type (ranging from \(0\) to \(M - 1\)).

When a hit occurs, the hardware multiplies the current geometryIndex by sbtRecordStride. This jumps over all the shader records allocated to preceding geometries in the BLAS. After the stride calculation lands on the base record for the intersected geometry, sbtRecordOffset is added to select the precise shader record for the active ray type.

Practical Example

Consider a scene with two ray types:

  1. Radiance Ray (sbtRecordOffset = 0)
  2. Shadow Ray (sbtRecordOffset = 1)

Because there are two ray types per geometry, sbtRecordStride is set to 2.

If a BLAS contains three geometries (Indices 0, 1, and 2), the SBT layout for that instance appears as:

  • Index 0: Geometry 0 — Radiance Hit Group
  • Index 1: Geometry 0 — Shadow Hit Group
  • Index 2: Geometry 1 — Radiance Hit Group
  • Index 3: Geometry 1 — Shadow Hit Group
  • Index 4: Geometry 2 — Radiance Hit Group
  • Index 5: Geometry 2 — Shadow Hit Group

When tracing a shadow ray (sbtRecordOffset = 1, sbtRecordStride = 2) that hits Geometry 2 (geometryIndex = 2):

HitGroupIndex = 0 + (2 * 2) + 1 = 5

The stride calculation advances 4 records past Geometries 0 and 1, and the offset selects the shadow record at index 5.

Behavioral Edge Cases

  • Single Ray Type: If an application only uses one ray type across all geometries, sbtRecordStride is set to 1, advancing one shader record per geometry.
  • Shared Hit Groups Across Geometries: If all geometries in a BLAS share the exact same shader record for a given ray type, sbtRecordStride can be set to 0. This eliminates the geometry index from the equation, causing every geometry in that BLAS to resolve to the same record determined solely by instanceShaderBindingTableRecordOffset + sbtRecordOffset.