How callableDataEXT Exchanges Data in GLSL

In GLSL for Vulkan Ray Tracing, the callableDataEXT qualifier facilitates dynamic, bidirectional communication between a caller shader and a callable shader. Callable shaders act as execution subroutines invoked on demand via the executeCallableEXT() function. This article explains how caller shaders use callableDataEXT and callee shaders use callableDataInEXT to pass parameters, share execution context, and return calculated results without hardcoding functional paths into a single shader stage.

The Storage Qualifiers: Caller vs. Callee

Data exchange relies on a complementary pair of storage qualifiers:

  1. callableDataEXT (Caller side): Declared in shaders capable of triggering a callable invocation, such as Ray Generation, Closest Hit, Miss, or another Callable shader. It acts as an outgoing and incoming payload buffer.
  2. callableDataInEXT (Callee side): Declared inside the callable shader itself to receive the incoming data and write return values back.

Location Matching and Binding

The connection between the caller and callee is established through explicit layout locations:

  • Caller Declaration: The caller associates a structure with a specific location index:

    layout(location = 0) callableDataEXT MyPayload {
        vec3 inputParam;
        vec3 outputResult;
    } callData;
  • Callee Declaration: The callable shader receives the data using the callableDataInEXT qualifier. In Vulkan GLSL, callable shaders accept inputs only at location = 0:

    layout(location = 0) callableDataInEXT MyPayload {
        vec3 inputParam;
        vec3 outputResult;
    } callData;

The Execution Flow

The exchange of data occurs synchronously in three distinct steps:

  1. Populating Input Values: Before initiating the call, the caller writes necessary inputs into the callableDataEXT variable.
  2. Invoking executeCallableEXT(): The caller executes the function executeCallableEXT(uint sbtRecordIndex, uint callableDataLocation). The second parameter matches the location layout index specified in the caller’s callableDataEXT declaration.
  3. Execution and Return: Control halts in the caller and jumps to the callable shader resolved via the Shader Binding Table (SBT). The callee reads inputs from its callableDataInEXT buffer, processes the logic, and writes output values directly back into the same memory block.

When the callable shader finishes execution, control returns to the instruction directly following executeCallableEXT() in the caller shader. The caller can then read the updated variables from its original callableDataEXT instance.

Memory Semantics and Struct Layout

The payload is passed by reference under the hood. Any write to callableDataInEXT in the callee immediately affects the memory backing callableDataEXT in the caller.

To prevent undefined behavior, both the caller and callee must declare identical struct definitions—matching field types, member names, and ordering—to guarantee correct memory alignment and data integrity across shader stages.