Is there a way to compile part of a shader into a spirv?

I want to have separate files for common things for shaders precompiled into a spirv.

For example PBR, I've got these functions and implementations for them

float NDFGGX(float NdotH, float roughness);
float GeometrySchlickGGX(float NdotV, float k);
float GeometrySmith(float NdotL, float NdotV, float roughness);
vec3 FresnelSchlick(float cosTheta, vec3 F0);


and I don't want to generate binaries for them every time I use it in a new shader. What I want is to generate a SPIRV binary file once and do whatever I want with it. Is this possible? What I've tried is to use shaderc library and create the binary as if it were a vertex shader, but it then needs glsl version and entry point. Not every file'd have entry point, doe.

What you want is generally not possible for OpenGL's SPIR-V support. SPIR-V compiles to shader objects, and shader objects theoretically allow you to link multiple objects of the same stage in a program. However, OpenGL's usage of SPIR-V requires that each SPIR-V shader be a complete shader stage with its entrypoint function.

So the requirement of shaderc mirrors the requirements of OpenGL.

The best you could do is combine multiple SPIR-V binaries into a single binary before handing it off to OpenGL. But that's a non-trivial process, since you basically have to renumber every reference in at least one of them, and combine any references that map to the same type.

• Actually, I want to do something like you described. Create multiple spir-v binaries and then just copy these binaries into one big binary, but I cannot create spir-v binary without specifying a version and an entry point and functions like above don't need the entry point, they are meant to be included in a shader. So, if what I want to achieve is impossible, do big game engines like unity or unreal generate binaries for whole shader when one small thing has changed in a material? From my measurements it is not that fast operation to generate spir-v binaries (using shaderc). – JanuszGrafiki Feb 15 at 15:19
• @JanuszGrafiki: "I cannot create spir-v binary without specifying a version and an entry point" Then either use better tools or ask your toolmaker to add the ability to build stand-alone modules from GLSL. This is not a SPIR-V problem; it's a shaderc problem. – Nicol Bolas Feb 15 at 15:22
• Gotcha, thanks! – JanuszGrafiki Feb 15 at 15:26

Consider #include.

We use the tools provided by Khronos to make our own compiler that is part of a larger tool providing lots of specific functionality. Like handing out binding numbers, compiling spirv into linkable objects (with the restriction noted above), and others to numerous to mention here. If linking smaller SPIRV code snippets into a larger SPIRV program is something you really need then these tools could support the type of environment you are talking about, but it would take some programming. We haven't needed to go there...yet...because:

Or, you could use the google include directive:

#extension GL_GOOGLE_include_directive : enable


If that extension is available in your environment, which you can find out just by throwing at the top of a shader that already compiles correctly then recompiling. Then that might be "good enough". But if your environment is a long term project then it may be worth the effort to dig into the tools....happy programming!

If there is interest in this question I will add more specifics on using the khronos tools. Like linking, getting info about shaders, setting info in shaders, the list is long and mighty. Also Khronos provides tutorials for using the tools on GitHub at the link above, though some of them are a bit hard to follow, but all in all these tools are outstanding.

Also spirv-link.exe will combine existing SPIRV modules into a library with the --create-library option. The entry points need to have unique names and can't all be "main". Then when loaded the code specifies the entry point for the module. Here is an example command line to help get anyone reading this going:

spirv-link.exe -o libraryname.spv --target-env spv1.5 input1.spv input2.spv


Add --create-library to make an spv library.(which requires unique entry point names)

Here is a link explaining how to set the entry points in opengl.