https://www.khronos.org/blog/mesh-shading-for-vulkan Skip to main content Toggle navigation The Khronos Group: Connecting Software to Silicon * Developers + Active Standards o 3D Commerce o ANARI o Camera o COLLADA o Data Format o EGL o glTF o KTX o NNEF o OpenCL o OpenGL o OpenGL ES o OpenGL SC o OpenVG o OpenVX o OpenXR o Safety Critical o SPIR o SYCL o Vulkan o Vulkan SC o WebGL + Groups & Forums o Heterogeneous Communication o Machine Learning Forum o SYCL SC Explortatory Forum o New Initiative Process + Inactive Standards o OpenKCAM o OpenKODE o OpenMAX o OpenML o OpenSL ES o OpenWF o StreamInput o WebCL + + Registry + Advisors + Github + Khronos Support Forums + Khronos Slack + + Videos & Presentations + Reference Guides + Books + + Jobs + Request for Proposals + Merchandise * Conformance + API Adopter program + API Adopters + Conformant Products + File Format Adopter Program + File Format Adopters + Trademark Guidelines + IP Framework Briefing + + Adopter Login + + Certification Program + Certified Viewers + + Certificant Login * Membership + Join the Khronos Group + Khronos Members + IP Framework + + Create an account + Member Login * News & Events + Newsroom + Press Releases + Khronos Blog + Newsletter + Share your news + + Events + Conference Code of Conduct + + Marketing with Khronos * About + Overview + Contact Us + Logo Packs + Directors & Officers + Working Group Officers + Diversity and Inclusion + Technical Support + Khronie Awards * Member Login * Search + [ ] Search Khronos Blog Mesh Shading for Vulkan September 1, 2022 by Christoph Kubisch, Principal Developer Technology Engineer, NVIDIA vulkan Introduction With the release of the VK_EXT_mesh_shader extension Vulkan gets an alternative geometry rasterization pipeline. This extension brings cross-vendor mesh shading to Vulkan, with a focus on improving functional compatibility with DirectX 12. Mesh and Task shaders follow the compute programming model and use threads cooperatively to generate meshes within a workgroup. The vertex and index data for these meshes are written similarly to shared memory in compute shaders. Mesh shader output is directly consumed by the rasterizer, as opposed to the previous approach of using a compute dispatch followed by an indirect draw. Therefore mesh shading applications can avoid preallocation of output buffers. [2022-blog-] Figure 1: Pipeline comparison The new mesh shading pipeline with the task and mesh shading stages provides an alternative to the traditional vertex, tessellation or geometry shader stages that feed into rasterization (see Figure 1). The use of the task shader (amplification shader in DirectX) is optional and provides a way to implement geometry amplification by creating variable mesh shader workgroups directly in the pipeline. Task shader workgroups can output an optional payload, which is visible as read-only input to all its child mesh shader workgroups. Before deciding to use mesh shaders, developers should ensure they are a good fit for their application. The traditional pipeline may still be best suited to many use cases, and it may not be trivial to improve performance using the mesh shading pipeline given the long evolution and optimization efforts applied to the traditional pipeline stages. Applications and games dealing with high geometric complexity can, however, benefit from the flexibility of the two-stage approach, which allows efficient culling, level-of-detail techniques as well as procedural generation. Compared to the traditional pipeline, the mesh shaders allow easy access to the topology of the generated primitives and developers are free to repurpose the threads to do both vertex shading and primitive shading work. This is in contrast to tessellation shaders, which, while fast, provide very limited control over the triangles created, and geometry shaders, which use a single thread programming model that is inefficient for modern streaming processors. In addition to improving graphics performance, using the task and mesh shader stages without feeding into rasterization can also perform simple nested compute operations. Geometry Representation [2022-blog-] Figure 1: Pipeline comparison Figure 2: The Stanford bunny model represented as triangle clusters When rasterizing geometry, mesh shaders typically make use of pre-computed triangle clusters (see Figure 2) of an upper bound in the number of vertices and triangles, also sometimes referred to as meshlets. Because task and mesh shaders, like compute, have only workgroup and invocation indices as input, all data fetching is handled by the application directly, which entirely removes fixed-function vertex processing and input assembly. This allows developers to be flexible in the storage of mesh data in both vertex and primitive topology representations. Another very common technique is to leverage the task shader and let one local invocation test one cluster for visibility. Through the use of subgroup operations developers can compute and write out information about the visible clusters into the task shader payload. Portability Compatibility with DirectX 12 was very important for this extension, therefore it follows the same capabilities, minimum limitations and restrictions. While it shares a lot of commonality with the existing VK_NV_mesh_shader extension, changes were made and the table below compares key details of all three definitions of mesh shading. DirectX 12 VK_EXT_mesh_shader VK_NV_mesh_shader Optional Amplification shader Task shader Task shader expansion stage Supported triangles, lines triangles, lines, points triangles, lines, points primitives Grid 3D 3D 1D dimensions Task shader groupshared Type taskPayloadSharedEXT Type out taskNV { ... }; output variable; variable; single interface block, read/ Up to one such Up to one such variable write access variable is allowed is allowed and is and can be passed to implicitly used by DispatchMesh. EmitMeshTasksEXT. Behaves like shared memory. Task shader Single Single workgroup-uniform Uses value written to dispatching workgroup-uniform call call to gl_TaskCountNV as task shader mesh shader to workgroup completes. workgroups DispatchMesh(x, y ,z, EmitMeshTasksEXT(x, y, [optional payload z); variable]); Mesh shader in payload Type taskPayloadSharedEXT Type in taskNV { ... }; input variable variable; single interface block, can exist only once, can exist only once, read-only read-only read-only Mesh shader out vertices Type layout( layout( output vertices[ VERTS ], max_vertices = VERTS, max_vertices = VERTS, maximum size out indices uint3 max_primitives = PRIMS) max_primitives = PRIMS) out; indices[ PRIMS ] out; Mesh shader SetMeshOutputCounts( SetMeshOutputsEXT( Vertex count always output counts vertexCount, vertexCount, max_vertices, primitive count primitiveCount); primitiveCount); set by gl_PrimitiveCountNV Mesh shader Write-only, after Write-only, after Read/write at any point (allows output SetMeshOutputCounts SetMeshOutputsEXT to avoid shared memory) attributes Mesh shader Indices are an array Indices are an array of Indices are an array of flat output of vectors. Write vectors. Write entire values (uint). Can write partial primitive entire primitive at primitive at once primitives. indices once (uvec3 for triangle, (uint3 for triangle, uvec2 for lines, uint for Also has special intrinsic to uint2 for lines) points) fill indices writePackedPrimitiveIndices4x8NV Mesh shader primitives gl_MeshPrimitivesEXT Not directly supported per-primitive [idx].SV_CullPrimitive [idx].gl_CullPrimitiveEXT culling Basic DispatchMesh(x, y, z); vkCmdDrawMeshTasksEXT(... vkCmdDrawMeshTasksNV(... x, function call x, y, z); xOffset); It is important to note, that while portability between APIs can be achieved, portability in performance among vendors is much harder. This is one of the reasons why this extension has not been released as a ratified KHR extension and Khronos continues to investigate improvements to geometry rasterization. To improve the situation a little bit, VK_EXT_mesh_shader introduces various preferences that can be queried through VkPhysicalDeviceMeshShaderPropertiesEXT, and developers are encouraged to respect these in order to generate optimal shader permutations. VkPhysicalDeviceMeshShaderPropertiesEXT Description of mesh shader behavior members for vendor preferences maxPreferredTaskWorkGroupInvocations While the minimum for maxTaskWorkGroupInvocations and maxPreferredMeshWorkGroupInvocations maxMeshWorkGroupInvocations does match DirectX 12, these values reflect the preferred sizing of the workgroup. It is recommended to use a compile-time loop for processing vertices and primitives, so that the shader can cater to the case when the workgroup size is lower than the number of output vertices/primitives. This enables the developer to use the same meshlet size across different vendors. prefersLocalInvocationVertexOutput If true, the vertex/primitive output arrays should be indexed by the prefersLocalInvocationPrimitiveOutput gl_LocalInvocationIndex. This also implies that the mesh shader workgroup size should match the number of output vertices and primitives. For example: gl_MeshVerticesEXT [gl_LocalInvocationIndex].gl_Position = pos; gl_PrimitiveTriangleIndicesEXT [gl_LocalInvocationIndex] = indices; prefersCompactVertexOutput Indicates that the vertex output array should be compact (without gaps between vertices). This way only as much output space may be reserved as needed, which may improve performance. When false, compaction is not required for optimal performance, and the output vertex count can be left at the max_vertices value (or highest used vertex index + 1). A benefit of this is that the primitive indices do not have to be adjusted for vertex compaction. prefersCompactPrimitiveOutput Similar to the above. Indicates whether the primitive output array should be compact (without gaps). There are further aspects that can influence the performance of mesh shaders in a vendor dependent way: * The number of maximum output vertices and primitives that a mesh shader is compiled with. * The number of per-vertex and per-primitive output attributes that are passed to fragment shaders. For example, it may be beneficial to fetch additional attributes in the fragment shader and interpolate them via hardware barycentrics to reduce the output space of the mesh shader. * The complexity of the culling performed in the mesh shader. For example details regarding the per-vertex and/or per-primitive culling with compact outputs compared to letting the hardware perform culling. * The usage of additional shared memory. If possible developers should use subgroup operations (such as shuffle) instead. * The task payload size. * Task shaders may add overhead, use them only when they can cull a meaningful number of primitives or when actual geometry amplification is desired. * Do not try to reimplement the fixed-function pipeline, strive for simpler algorithms instead. The meshlet / primitive cluster dimensions can have an especially big impact for the developer, as when streaming it is ideal to store assets with a fixed clustering in advance. Vendors may have different performance recommendations and so we suggest the use of smaller cluster sizes that work equally well across multiple vendors and process multiple small clusters at once on implementations that perform better with larger clusters. In this area we advise developers to experiment and consult with their hardware vendors for recommendations. The open source sample https://github.com/nvpro-samples/ gl_vk_meshlet_cadscene has been updated to support and showcase the VK_EXT_mesh_shader extension. Please note that the shaderc library in the Vulkan SDK may not be updated to the necessary version yet, but this is coming soon. Further reading * Introduction to Turing Mesh Shaders | NVIDIA Technical Blog * Using Mesh Shaders for Professional Graphics | NVIDIA Technical Blog * AMD GPU Open SAMPLER FEEDBACK & MESH SHADERS * Mesh and task shader intro and basics | Timur's Blog Comments Blog Links Short Link: [https://khr.io/z8 ] Archives * September, 2022 * April, 2022 * March, 2022 * February, 2022 * January, 2022 * December, 2021 * November, 2021 * October, 2021 * September, 2021 * August, 2021 * June, 2021 * May, 2021 * April, 2021 * March, 2021 * February, 2021 * January, 2021 * December, 2020 * November, 2020 * October, 2020 * September, 2020 * August, 2020 * July, 2020 * May, 2020 * April, 2020 * March, 2020 * February, 2020 * January, 2020 * December, 2019 * November, 2019 * October, 2019 * September, 2019 * July, 2019 * June, 2019 * May, 2019 * March, 2019 * February, 2019 * January, 2019 * December, 2018 * November, 2018 * September, 2018 * August, 2018 * July, 2018 * June, 2018 * May, 2018 * April, 2018 * March, 2018 * February, 2018 * January, 2018 * December, 2017 * November, 2017 Feed Tags 3d 3dcommerce anari api ar blender blog browser collada conference conformance education egl event gaming gdc glsl gltf gpu hpc iwocl khronos ecosystem ktx library llvm machinelearning members nnef opencl opengl opengles openvx openxr presentation raytracing safetycritical siggraph specification spir spirv sycl training tutorials video vr vulkan vulkansc webgl webinar windows [ ] Go Page footer starts here. Return to main content Khronos Logo 9450 SW Gemini Drive #45043 Beaverton, OR 97008-6018 USA Office: +1 (415) 869-8627 sign up for our newsletter * * * * * * * * Diversity & Inclusion * Legal Notices * Privacy Policy * Trademark Usage Language: EN CN JP KR (c) The Khronos^(r) Group Inc. 2022. All rights reserved. Hosting provided by DigitalOcean Khronos(r) and Vulkan(r) are registered trademarks, and ANARI(tm), WebGL(tm), glTF(tm), NNEF(tm), OpenVX(tm), SPIR(tm), SPIR-V(tm), SYCL(tm), OpenVG(tm), and 3D Commerce(tm) are trademarks of The Khronos Group Inc. OpenXR(tm) is a trademark owned by The Khronos Group Inc. and is registered as a trademark in China, the European Union, Japan and the United Kingdom. OpenCL(tm), OpenGL(r) and the OpenGL ES(tm) and OpenGL SC(tm) logos are registered trademarks or trademarks used under license by Khronos. All other product names, trademarks, and/or company names are used solely for identification and belong to their respective owners. devilish