taskPayloadSharedEXT in GLSL Task to Mesh Communication
This article provides a concise guide to the
taskPayloadSharedEXT storage qualifier introduced with the
Vulkan mesh shading extension (VK_EXT_mesh_shader) in GLSL.
It explains the qualifier's architectural purpose, how it coordinates
dynamic data exchange from task shaders to mesh shaders, the memory and
synchronization rules governing its use, and best practices to maximize
memory throughput.
What is taskPayloadSharedEXT?
The taskPayloadSharedEXT storage qualifier designates a
user-defined block of variables as the primary communication payload
passed from a task shader workgroup to the downstream mesh shader
workgroups it spawns. In the mesh shading pipeline, task shaders (also
known as amplification shaders) evaluate geometry at a coarse
level—performing tasks such as frustum culling, occlusion culling, and
level-of-detail selection—before launching mesh shader workgroups. The
taskPayloadSharedEXT qualifier defines the shared memory
space that transfers the results of these operations directly between
stages without writing to high-latency global device memory (such as
SSBOs).
Core Mechanisms and Data Flow
- Shared Workspace in the Task Shader: Within the
task shader, variables declared with
taskPayloadSharedEXTbehave similarly to workgroup shared memory (shared). All invocations within a single task shader workgroup can read and write to this payload structure during execution. - Payload Transmission: The task shader issues
EmitMeshTasksEXT(x, y, z)to spawn a grid of mesh shader workgroups. When this occurs, the contents of the payload are made available to all spawned mesh shader workgroups. - Read-Only Consumption in Mesh Shaders: In the
receiving mesh shaders, the identical payload structure must be declared
using
taskPayloadSharedEXT. However, within the mesh shader stage, the payload is strictly read-only. All invocations across all spawned mesh workgroups read from this shared dataset to determine which primitives, vertices, or meshlet indices they are responsible for processing.
Typical Syntax and Declaration
The payload definition must be structurally identical in both the task shader and the mesh shader.
Task Shader:
#version 460
#extension GL_EXT_mesh_shader : require
layout(local_size_x = 32) in;
struct TaskData {
uint meshletIndices[32];
uint visibleCount;
};
taskPayloadSharedEXT TaskData payload;
void main() {
uint gID = gl_GlobalInvocationID.x;
// Perform culling and populate payload
if (gl_LocalInvocationIndex == 0) {
payload.visibleCount = 0;
}
barrier();
// Cooperative write to payload
if (/* meshlet is visible */) {
uint index = atomicAdd(payload.visibleCount, 1);
payload.meshletIndices[index] = gID;
}
barrier();
// Emit mesh tasks matching the number of visible meshlets
if (gl_LocalInvocationIndex == 0) {
EmitMeshTasksEXT(payload.visibleCount, 1, 1);
}
}Mesh Shader:
#version 460
#extension GL_EXT_mesh_shader : require
layout(local_size_x = 32) in;
layout(triangles, max_vertices = 64, max_primitives = 126) out;
struct TaskData {
uint meshletIndices[32];
uint visibleCount;
};
taskPayloadSharedEXT TaskData payload;
void main() {
// Read the culled meshlet ID assigned to this mesh workgroup
uint meshletID = payload.meshletIndices[gl_WorkGroupID.x];
// Process geometry for meshletID...
}Synchronization and Memory Rules
Because the payload functions as workgroup shared memory during the task shader stage, proper synchronization is required:
- Task shader invocations writing to
taskPayloadSharedEXTmust ensure all writes are complete beforeEmitMeshTasksEXT()is called. A workgroup barrier (barrier()) or memory barrier (memoryBarrierShared()) must precede the emit command if multiple invocations write to the payload. - Mesh shaders do not need to synchronize reads from the payload because the driver ensures that payload data is fully committed and visible to the spawned mesh workgroups prior to their execution.
Performance Considerations
- Size Limits: Hardware imposes a limit on the size
of the payload (queryable via
maxTaskPayloadSizein Vulkan properties, typically 16 KB). Exceeding hardware thresholds will cause compilation errors or severely limit execution occupancy. - Occupancy Impact: Larger payloads reduce the number of active task and mesh workgroups that can reside concurrently on a GPU Compute Unit or Streaming Multiprocessor. Keep the payload footprint minimal by packing data and storing only per-meshlet indices, offsets, or compact draw parameters rather than full vertex records.