How executeCallableEXT Works in GLSL Ray Tracing
This article explains how the executeCallableEXT
function executes a callable shader routine in GLSL under the
GL_EXT_ray_tracing extension. It outlines the mechanics of
the dynamic dispatch process, the mapping of the call to the Shader
Binding Table (SBT), and how parameters are communicated between the
caller and the invoked shader.
In modern ray tracing pipelines, executeCallableEXT
allows ray generation, closest hit, miss, and other callable shaders to
invoke execution blocks dynamically. Unlike hardcoded function calls,
callable shaders are dispatched dynamically at runtime, behaving
similarly to a virtual function call or an indirect jump within the GPU
pipeline.
The function takes the following signature:
void executeCallableEXT(uint sbtRecordIndex, int callableDataLocation);1. Shader Binding Table (SBT) Resolution
When executeCallableEXT is executed, the GPU uses the
first argument, sbtRecordIndex, to locate the appropriate
shader routine in the Shader Binding Table.
The pipeline's host setup defines a callable shader binding region
via VkStridedDeviceAddressRegionKHR. When the shader
executes:
- The GPU calculates the memory address of the target shader handle
using the formula:
targetAddress = callableBaseAddress + (sbtRecordIndex * callableStride). - The shader record stored at that address contains the shader group handle corresponding to the compiled callable shader, along with any embedded local shader parameters.
- Control flow transfers to the callable shader specified by this record.
2. Passing Data with Storage Qualifiers
The second argument, callableDataLocation, links input
and output parameters between the invoking shader and the callable
shader without using an explicit parameter list.
Data communication relies on custom storage qualifiers matched by location indices:
In the calling shader, data is declared using the
callableDataEXTqualifier:layout(location = 0) callableDataEXT MyDataBlock { vec4 parameter1; vec4 result; } myData;In the callable shader, the corresponding data is received using the
callableDataInEXTqualifier at the identical location:layout(location = 0) callableDataInEXT MyDataBlock { vec4 parameter1; vec4 result; } receivedData;
The GPU passes an effective pointer to this memory payload. Any
modifications made by the callable shader to variables marked with
callableDataInEXT directly alter the payload defined in the
caller.
3. Execution and Return Flow
Calling executeCallableEXT suspends execution of the
calling shader. The GPU switches execution contexts to the target
callable shader entry point (main()).
Once the callable shader reaches the end of its routine:
- Execution control returns to the caller immediately after the
executeCallableEXTinstruction. - The caller can then read any modified values stored in the
callableDataEXTstructure. - Callable shaders can also recursively invoke other callable shaders
using
executeCallableEXT, provided the implementation's maximum call depth limit (maxRayDispatchInvocationCount/ call depth settings) is not exceeded.