Working with multiple shader compilation units in Vulkan


My GLSL shaders are built up using multiple compilation units within a single shader stage. GLSLang will correctly merge these and generate a single SPIR-V shader out of them. However, it doesn’t seem like this workflow is compatible with Aftermath since you don’t have a single source file to cross reference the line numbers in the SPIR-V with. Any suggestions on ways to improve this? I would think if Nsight could use spirv-dis to disassemble the SPIR-V, I could get a close-enough version of the shader that would allow me to debug issues.

Somewhat related, the SPIR-V with debug information embeds in it the plain-text of the original GLSL (when a single compilation unit is used). Is this used, or is the only the file on disk used as the source reference for the GLSL code? In my case all of my shaders are compiled on-demand at runtime, is there a way for me to embed this information into the dump information so I can see the shaders when diagnosing the crash? A lot of the time the shaders are generated by an end-user, so I wouldn’t have access to their source directly.


Thank you for using Nsight Aftermath and your questions. I will contact the engineering manager responsible for Nsight Aftermath and one of us will close the loop with you on your questions. We will get back to you.


Related to this: if instead of multiple compilation units I was to rework my workflow to use #include statements, would that help? GLSLang will ultimately create a single GLSL program after working through all of the includes, but it’s unclear to me of the way Aftermath correlates SPIR-V to GLSL would be able to match up the line numbers to the final source. Again in this case all of the code is generated at runtime, there are no files on disk. If I just save out the final combined GLSL source to disk will this be enough, or do I need to save out each of the #include source separate due to the way SPIR-V will be tagging line numbers?

Ok so I got much farther by using #include statements instead. GLSLang handles those much more nicely than multiple compilation units.
I do notice however that NSight is ignoring the OpString that the OpLine instructions are referring to, and is assuming that the first OpString source is the one that has the line number in question (incorrectly often). I’ve reported this to the Nvidia bug database.

I do wonder though, why aren’t the OpSource that’s included in the SPIR-V used instead of external GLSL source files? These contain the full source from the original shader, and likely more closely match what GLSLang converted to SPIR-V than what is on disk, due to work the preprocessor has to do. Seems like a cleaner workflow, if OpSource is available.
Any chance OpSource can start being consumed by NSight?

Generate and include debug information during the shader compilation process. This information should include line mappings between the compiled SPIR-V shader and the original GLSL source code. By enabling debug information, you can correlate errors in the SPIR-V shader back to the specific lines of code in the original GLSL source, even when using multiple compilation units.

Thanks for the reply. The extra debug information is indeed there when using #includes, although NSight doesn’t seem to handle those great. However with multiple compilation unit, GLSLang will strip a lot of that information.