Regarding https://mastodon.gamedev.place/@gob/112450371375832518, the best system for shader code I've used was at Media Molecule on Dreams:

- Any C++ file could embed a PSSL shader with macro begin/end, gets automatically compiled as part of the build process.
- PSSL and C++ shared headers of structs/defines/enums so always in sync.
- Lots of systems supported compiling as both C++ and PSSL (e.g. the whole maths lib, which used clang ext_vector for shader-like syntax/swizzles in C++ too)

...

Hugo Devillers (@[email protected])

All shading languages suck. Moreover, they’re an outdated concept and they’re failing us. https://xol.io/blah/death-to-shading-languages/

Gamedev Mastodon

- Also *no bindings*, all shader resources were passed using shared structs, that directly embedded buffer/texture descriptors or pointers to other structs. Easy to describe and easy to change.
- And had great hot reload support for iteration/debugging, press a key in VS to recompile the shaders in that file and instantly replace in live game.

...

Anyhow, best system I've used. Super easy to add new shaders, share code between CPU and GPU, and iterate live.

Likely only practical due to having fixed platforms (PS4/Pro) and compilers (clang and psslc), and shaders being code not content, but is the benchmark I judge shader pipelines against. :)

@sjb3d yeah, that “using structs to pass resources” approach wasn’t something you could do on PC until bindless became a thing. And even then you have to pass handles or indices, and not descriptors. But still much much nicer than classic bindings! Unfortunately cbuffer layout is still a thing in D3D which is very annoying.

@mjp @sjb3d you don't need to pass such a struct directly into the shader though. A shader compiler could code-generate C-structs for the uniform data expected by the shader, and a separate struct for the resource bindings. A 3D wrapper API can then consume the bindings struct and map that to traditional 3D API resource binding calls.

This wouldn't be faster, but a lot more 'type-safe'.

@mjp @sjb3d in sokol-gfx (which is a wrapper for 'traditional' 3D APIs) I code-generate a C struct for uniform data in the offline-shader compiler - along with a lot more reflection data from the shader, like the expected resource types and their bind slots.

I didn't go the last step to code-generate a struct for the resource bindings too, but tbh the more I think about it, the more I like the idea...

@floooh @mjp yeah on PC, even though there is no standard GPU memory layout I still find structs useful to manage a whole "descriptor set" of resources at once.

If you are using Slang for shader code, there is "ParameterBlock" syntax that maps really well to this, and avoids the need to specify bindings at all.

@sjb3d @mjp stuff like this is in a nutshell why I'd like CPU and GPU languages and compilers to be merged into one, and what little would need to remain of '3D APIs' to move into the respective language stdlibs ;)
@sjb3d @mjp e.g. if the CPU-side compiler would have all the knowledge that the GPU-side compiler has, a lot of the 3D API surface would disappear, since most of that is just concerned with describing the structure of the data that's pushed from the CPU to the GPU :)
@floooh @mjp yep I demand that all vendors go all-in on scalar loads like GCN does, then we can have standard (or at least standard-sized) GPU memory layout for device pointers, buffer resources, texture resources etc. Never going to happen but that would delete all binding APIs so a person can dream... :)
VK_EXT_descriptor_buffer

We’ve just released an extension that I think will completely change how engines approach descriptors going forward. Descriptor sets are now backed by VkBuffer objects where you memcpy in descriptors. Delete VkDescriptorPool and VkDescriptorSet from the API, and have fun!

The Khronos Group