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:
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.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
callableDataInEXTqualifier. In Vulkan GLSL, callable shaders accept inputs only atlocation = 0:layout(location = 0) callableDataInEXT MyPayload { vec3 inputParam; vec3 outputResult; } callData;
The Execution Flow
The exchange of data occurs synchronously in three distinct steps:
- Populating Input Values: Before initiating the
call, the caller writes necessary inputs into the
callableDataEXTvariable. - Invoking
executeCallableEXT(): The caller executes the functionexecuteCallableEXT(uint sbtRecordIndex, uint callableDataLocation). The second parameter matches thelocationlayout index specified in the caller’scallableDataEXTdeclaration. - 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
callableDataInEXTbuffer, 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.