Spir-V and OpenGL: Entry points and pipeline stages - opengl

Is there a built-in way in OpenGL to find which entry points and shader stages a compiled spir-v shader supports, or do I have to use a separate library like https://github.com/KhronosGroup/SPIRV-Reflect ?
Edit:
I ended up using SPIRV-Reflect:
My asset pipeline links all stages that need to be linked into a program into a single binary blob, then I'm using
uint32_t GetEntryPointCount() const;
const char* GetEntryPointName(uint32_t index) const;
SpvReflectShaderStageFlagBits GetEntryPointShaderStage(uint32_t index) const;
to enumerate the entry points and attach the corresponding shader to the program.

OpenGL only has introspection facilities for linked programs. Program linking requires compiling shader objects first. And SPIR-V loading produces shader objects which replace "compilation" with specialization. And specialization of a SPIR-V shader requires knowing what entry point you want to use.
So no, OpenGL has no way to look at what entrypoints are available in a SPIR-V module. Besides, it wouldn't be that useful. SPIR-V can only be loaded into shader objects, and shader objects are created for a specific shader stage. So unless you had multiple entrypoints for the same stage, there's only really one entrypoint you could be looking for: the one whose stage matches the shader object type.
So OpenGL already expects that you have some additional information associated with any particular SPIR-V module loading operation. Just put the entrypoint name in that additional information, or establish a convention for the names of entrypoints for particular shader stages.

Related

Vulkan; Get list of uniforms & attribs from SPIR-V shader

Looking for a Vulkan alternative for this; In OpenGL is there a way to get a list of all uniforms & attribs used by a shader program?
Vulkan, as a general rule, does not have querying APIs for any information you have provided to the API. If you give something to the API, and you need to know something about that data, then you're expected to remember what it was.
SPIR-V contains all of the definitions of the various resources and interfaces used by a shader. And SPIR-V is a pretty well-specified format. Since you gave the SPIR-V to Vulkan, you therefore have ample opportunity to know what all of the "uniforms & attribs" in that shader are. So Vulkan has no shader querying API.
There are several tools for introspecting into SPIR-V binaries to extract this kind of information. But Vulkan itself isn't one of them.

OpenGL Compute stage with other stages

I want to have a single shader program that has a Compute stage along with the standard graphics stages (vertex, tess control, tess eval, fragment).
Unfortunately if I attach the Compute stage to the rest of the program and then link it, calls to location queries such as glGetAttribLocation (for uniforms/attributes in any stage) start returning -1, indicating they failed to find the named objects. I also tried using layout(location=N), which resulted in nothing being drawn.
If I attach the stages to two different shader programs and use them one right after the other, both work well (the compute shader writes to a VBO and the draw shader reads from the same VBO), except that I have to switch between them.
Are there limitations on combining Compute stage with the standard graphics stages? All the examples I can find have two programs, but I have not found an explanation for why that would need to be the case.
OpenGL actively forbids linking a program that contains a compute shader with any non-compute shader types. You should have gotten a linker error when you tried it.
Also, there's really no reason to do so. The only hypothetical benefit you might have gotten from it is having the two sets of shaders sharing uniform values. There just isn't much to gain from having them in the same program.

How to share shader code across shading stages in OpenGL

I have some math functions written in GLSL and I want to use them in TES, geometry and fragment stages of the same shader program. All of them are pretty valid for all these shader types, and for now the code is just copy-pasted across shader files.
I want to extract the functions from the shader files and put them into a separate file, yielding a shader "library". I can see at least two ways to do it:
Make a shader source preprocessor which will insert "library" code into shader source where appropriate.
Create additional shader objects, one per shader type, which are compiled from the library source code, and link them together. This way the "library" executable code will be duplicated across shader stages on compiler and linker level. Actually, this is how "library" shaders may be used, but in this variant they are stage-specific and cannot be shared across pipeline stages.
Is it possible to compile shader source only once (with appropriate restrictions), link it to a shader program and use it in any stage of the pipeline? I mean something like this:
GLuint shaderLib = glCreateShader(GL_LIBRARY_SHADER);
//...add source and compile....
glAttachShader(shProg, vertexShader);
glAttachShader(shProg, tesShader);
glAttachShader(shProg, geomShader);
glAttachShader(shProg, fragShader);
glAttachShader(shProg, shaderLib);
glLinkProgram(shProg); // Links OK; vertex, TES, geom and frag shader successfully use functions from shaderLib.
Of course, library shader should not have in or out global variables, but it may use uniforms. Also, function prototypes should be declared before usage in each shader source, as it is possible to do when linking several shaders of the same type into one program.
And if the above is not possible, then WHY? Such "library" shaders look very logical for the C-like compilation model of GLSL.
Is it possible to compile shader source only once (with appropriate restrictions), link it to a shader program and use it in any stage of the pipeline?
No. I'd suggest, if you have to do this, to just add the text to the various shaders. Well, don't add it directly to the actual string; instead, add it to the list of shader strings you provide via glShaderSource/glCreateShaderProgram.
And if the above is not possible, then WHY?
Because each shader stage is separate.
It should be noted that not even Vulkan changes this. Well, not the way you want. It does allows you to have the reverse: multiple shader stages all in a single SPIR-V module. But it doesn't (at the API level) allow you to have multiple modules provide code for a single stage.
All the high level constructs of structs, functions, linking of modules, etc, are mostly all just niceties that the APIs provide to make your life easier on input. HLSL for example allows you to do use #include's, but to do something similar in GLSL you need to perform that pre-process step yourself.
When the GPU has to execute your shader it is running the same code hundreds, thousands, if not millions of times per frame - the driver will have converted your shader into its own HW specific instruction set and optimised it down to the smallest number of instructions practicable to guarantee best performance of their instruction caches and shader engines.

How to remove unused resources from an OpenGL program

I am trying to create something like effect system for OpenGL, and I want to be able to define a number of shaders in the same file. But I discovered the following problem. Say I have two shaders: A and B. Shader A uses texA and shader B uses texB. Then despite the fact that neither shader A uses texB nor shader B uses texA, both textures will be enumerated in both programs (I am using separate programs, so every shader corresponds to one program). One consequence is that I cannot have many textures defined in one file since the shader will fail to link (it compiles successfully but the linker then complains that the number of texture samplers exceeds the HW limit). Other problem is that I am doing automatic resource binding and my shaders have lots of false resource dependencies.
So is there a way to tell the shader compiler/linker to remove all unused resources from the separate program?
Shader sampler units are not there to select textures, but to pass texture units to the shader. The textures themself are bound to the texture units. So the selection which texture to use should not be done in the shader, but in the host program.
Or you could use bindless textures if your OpenGL implementation (=GPU driver) supports these.

Transform Feedback varyings

From some examples of using OpenGL transform feedback I see that the glTransformFeedbackVaryings​ are mapped after program compilation and before it is linking.Is this way enforced for all OpenGL versions?Can't layout qualifier be used to set the indices just like for vertex arrays?I am asking because in my code shader programs creation process is abstracted from other routines and before splitting it to controllable compile/link methods I would like to know if there's a way around.
Update:
How is it done when using separable shader objects?There is no explicit linkage step.
UPDATE:
It is still not clear to me how to set glTransformFeedbackVaryings when using separate shader objects.
This explantion is completely unclear to me:
If separable program objects are in use, the set of attributes
captured is taken from the program object active on the last shader
stage processing the primitives captured by transform feedback. The
set of attributes to capture in transform feedback mode for any other
program active on a previous shader stage is ignored.
I actually thought I could activate a pipeline object and do the query.But it seem to have no effect.My transform feedback writes nothing.Then I found this discussion in Transform Feedback docs:
Can you output varyings from a seperate shader program created
with glCreateShaderProgramEXT?
RESOLVED: No.
glTransformFeedbackVaryings requires a re-link to take effect on a
program. glCreateShaderProgramEXT detaches and deletes the shader
object use to create the program so a glLinkProgram will fail.
You can still create a vertex or geometry shader program
with the standard GLSL creation process where you could use
glTransformFeedbackVaryings and glLinkProgram.
This is unclear too.Does the answer mean that to set transform feedback varyings one should use the regular shader programs only?I don't get it.
What you are asking is possible using 4.4.2.1 Transform Feedback Layout Qualifiers, unfortunately it is an OpenGL 4.4 feature. It is available in extension form through GL_ARB_enhanced_layouts, but this is a relatively new extension and adoption is sparse at the moment.
It is considerably more complicated than any of the more traditional layout qualifiers in GLSL, so your best bet for the foreseeable future is to manage the varyings from the GL API instead of in your shader.
As far as varyings in SSO (separable shader object) programs, the OpenGL specification states the following:
OpenGL 4.4 (Core Profile) - 13.2 Transform Feedback - pp. 392
If separable program objects are in use, the set of attributes captured is taken
from the program object active on the last shader stage processing the primitives
captured by transform feedback. The set of attributes to capture in transform feedback mode for any other program active on a previous shader stage is ignored.
Ordinarily linking identifies varyings (denoted in/out in modern GLSL) that are actually used between stages and establishes the set of "active" uniforms for a GLSL program. Linking trims the dead weight that is not shared across multiple stages and performs static interface validation between stages and it is also when binding locations for any remaining varyings or uniforms are set. Since each program object can be a single stage when using SSOs, the linker is not going to reduce the number of inputs/outputs (varyings) and you can ignore a lot of language in the specification that says it must occur before or after linking.
Since linking is not a step in creating a program object for use with separate shader objects, your transform feedback has to be relative to a single stage (which can mean a different program object depending on which stage you select). OpenGL uses the program associated with the final vertex processing stage enabled in your pipeline for this purpose; this could be a vertex shader, tessellation evaluation shader, or geometry shader (in that order). Whichever program provides the final vertex processing stage for your pipeline is the program object that transform feedback varyings are relative to.