Open expenses opened 2 years ago
Given that EXT mesh shaders are in the works, I'd rather wait for that.
yes, VK_EXT_mesh_shader is here! just joining to get updates.. :-)
Made prototype on a weekend: https://github.com/Try/SPIRV-Cross/commit/d83153a1d85277128f4dd66c763b9f4af110ca38 Proper varyings, per-primitive outputs are still TODO, as well as many other things
Here is a code-gen example: https://shader-playground.timjones.io/85579774a9971f99157fb3c41f8d215e
Some design questions:
Metal shader, unlike glsl, must provide per-vertex output as one write mesh.set(i, all_vertex);
Current workaround for me is to declare all outputs as threadgroup
variables and then run post process step:
// ideally max_vertex<=thread_count and loop should have exactly one iteration
for (uint spvI = gl_LocalInvocationIndex, spvThreadCount = (gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z);
spvI < 24 /* max_vertex */; spvI += spvThreadCount)
{
spvPerVertex spvV = {}; // merged struct with gl_Position and varyings
spvV.gl_MeshVerticesEXT = gl_MeshVerticesEXT[spvI];
spvV.gl_MeshVerticesEXT.gl_Position.y = -spvV.gl_MeshVerticesEXT.gl_Position.y;
spvV.perVertex = perVertex[spvI];
spvMesh.set_vertex(spvI, spvV);
}
I know that post-process write-out is not desirable, but so far that is the only idea.
Copy-loop doesn't really work - it assumes that all threads are still active, when loop need to run
Can be fixed by extracting application code into mesh_main
(HLSL-like), and have post-process in a real main.
I noticed, that MSL backend doesn't do proxy-main, as HLSL - is there a reason to have this design? In other words, what else can break?
SPV_NV_mesh_shader
seems to map quite well to Metal 3 mesh shaders and we'd need to be able to translate them for https://github.com/KhronosGroup/MoltenVK/issues/1618.I looked into implementing this for naga and got fairly far, but ran into a potential driver issue without much ability to debug it. I'm dumping some thoughts on how mesh shaders could be translated for SPIRV-Cross here.
Here's a sample mesh shader, adapted from http://zone.dog/braindump/mesh_shaders/:
The SPIR-V disassembly for this shader compiled with
glslc
looks like:Metal mesh shaders are marked with
[[mesh]]
and take amesh<V, P, NV, NP, T>
as input whereV
is the per-vertex data, in this caseP
is the per-primitive data, which should bevoid
as there is noneNV
is the number of vertices, which is theOutputVertices
OpExecutionMode
in SPIR-V (4)NP
is the number of primitives, which is theOutputPrimitivesNV
OpExecutionMode
in SPIR-V (2)T
is the topology which ismetal::topology::triangle
here as marked by theOutputTrianglesNV
OpExecutionMode
.All together you have an input of
metal::mesh<Vertex, void, 4, 2, metal::topology::triangle> mesh
The current output of SPIRV-Cross looks like this: (truncated for bevity)
gl_BuiltIn_5276
maps pretty easily tomesh.set_index
.gl_BuiltIn_5275
maps pretty easily tomesh.set_primitive_count
(might want to only do this per-workgroup).mesh.set_vertex
takes an index and aVertex
struct, which makes mapping the SPIR-V where you set the vertex data values individually a bit tricker as you need to zip them together.You probably want to end up with an output that looks like: