This sample demonstrates mesh shaders in Vulkan by procedurally generating a 2D grid of wireframe bounding boxes. It renders all geometry without culling, providing a baseline for comparison with mesh_task_shaders.
Pipeline: Mesh Shader → Fragment Shader
- Direct Mesh Dispatch: Fixed workgroup grid dispatches all boxes regardless of visibility.
- Procedural Generation: Each mesh workgroup generates multiple boxes using stride-based loops (typically 8 boxes = 64 vertices + 96 line primitives with 32-thread workgroups).
- Position Derivation: Box positions calculated directly from
groupIDwithout intermediate buffers. - No Culling: All geometry processed every frame for predictable baseline performance.
Note: In our sample code we sometimes list ranges of values like 0..31 threads or 0..7 boxes in the mesh shader, given those are typical results of the preferred values for NVIDIA mesh and task shaders. The actual runtime values however can be different as they depend on the hardware's properties.
uint32_t workgroupsX = (totalBoxesX + BOXES_PER_MESH - 1) / BOXES_PER_MESH; // ceil division
uint32_t workgroupsZ = totalBoxesZ;
// Note: Actual implementation also clamps to hardware limits
vkCmdDrawMeshTasksEXT(cmd, workgroupsX, workgroupsZ, 1);Each mesh workgroup handles up to BOXES_PER_MESH boxes (typically 8, derived as workgroupSize / 4). Workgroup calculates box indices from groupID and outputs geometry directly.
Note: Some
VK_EXT_mesh_shaderimplementations only support 16-bit per launch grid dimension. As a result, if you want to launch 1D workloads with more than 16-bit elements, one needs to convert the launch grid into 2D. This is demonstrated in vk_lod_clusters.
- Hardware-dependent thread count per workgroup (typically 32, set to
maxPreferredMeshWorkGroupInvocations) - Up to
BOXES_PER_MESH × 8vertices (typically 64 vertices with 32-thread workgroups) - Up to
BOXES_PER_MESH × 12line primitives (typically 96 lines with 32-thread workgroups) - Stride-based generation: threads loop to generate all vertices/primitives
VK_EXT_mesh_shaderextensionmeshShaderfeature enabled
Mesh shaders have strict per-workgroup output limits (hardware-dependent):
- Max vertices per workgroup: Typically 256 (queried via
maxMeshOutputVertices) - Max primitives per workgroup: Typically 256 (queried via
maxMeshOutputPrimitives)
This sample uses simple box geometry (8 vertices, 12 lines) which allows multiple boxes per workgroup. However, more complex geometry may not fit these limits.
Here we are rendering multiple simple boxes per workgroup, staying well within hardware limits.
- Fixed Cost: All boxes processed every frame regardless of visibility
- Predictable: No dynamic branching or culling logic
- Zero Geometry Bandwidth: Procedural generation eliminates vertex/index buffer reads
For GPU-driven culling optimization, see mesh_task_shaders which adds task shader frustum culling (30-70% improvement with off-screen geometry).
