Metal Shader Converter Help

So I have been working on using the new Metal Shader Converter to create a graphics abstraction between D3D12 and Metal. One thing I cannot wrap my head around is how someone would do bindless buffers in Metal. Take this for example... the metal shader converter easily converts this code into Metal

`ByteAdressBuffer bindless_buffers[] : register(space1);

v2f vertMain(vertIn in){

Mesh m = bindless_buffers[1].Load<Mesh>(0);

v2f out;

out.pos = in.pos * m.pos;

return out;`

And using the new Shader Converter one can easily create a DescriptorTable from a root signature that holds this unbounded array of ByteAdressBuffers. But when you try to fill an argument buffer using the DescriptorTableEntry struct, it looks like you can only place one resource at a time and cannot even access the array in the descriptor. For textures this is okay because you can supply a MTLTexture that holds other textures. But you can't have a MTLBuffer hold different kinds of buffers. Is it possible to do this ByteAdressBuffer style of full bindless in Metal? The shader converter allows it but I don't know how to get the API to supply the shaders with the correct data...

Any Help would be GREATLY appreciated and all the work I do will be posted online for others to learn about using Metal :)

Replies

Setting up the host-side for leveraging unbounded resources requires introducing an extra level of indirection in how you bind data to your pipelines.

First, you need to provide a root signature at conversion time to specify that your top-level Argument Buffer references descriptor tables corresponding to unbounded arrays. For each descriptor table corresponding to an unbounded array in the shader, your root signature needs to specify how many resources you plan on storing in it. It is not possible to use unbounded resource an automatic layout.

Next, when binding resources to your pipelines, your top level Argument Buffer references the descriptor table(s) that themselves reference the unbounded resources.

Visually, this means your hierarchy will roughly look like this:

Top-Level Argument Buffer --(uint64_t)--> descriptor table --(IRDescriptorTableEntry)--> shader resource

When using a root signature, your top-level Argument Buffer consists of the GPU addresses of the descriptor table Argument Buffers (a uint64_t). These descriptor tables are Metal buffers themselves, and each entry on this table references a shader resource. You may have as many entries as your root signature specifies, with each corresponding to the memory layout of IRDescriptorTableEntry.