如何在OpenGL中的着色阶段共享着色器代码

时间:2016-09-09 09:10:37

标签: opengl compilation glsl shader

我有一些用GLSL编写的数学函数,我想在同一着色器程序的TES,几何和片段阶段使用它们。所有这些着色器类型都非常有效,现在代码只是在着色器文件中复制粘贴。

我想从着色器文件中提取函数并将它们放入一个单独的文件中,从而产生一个着色器“库”。我至少可以看到两种方法:

  • 制作着色器源预处理器,在适当的情况下将“库”代码插入到着色器源中。
  • 创建其他着色器对象,每个着色器类型一个,从库源代码编译,并将它们链接在一起。这样,“库”可执行代码将在编译器和链接器级别的着色器阶段中复制。实际上,这就是“库”着色器的使用方式,但在这个变体中,它们是特定于阶段的,不能在管道阶段之间共享。

是否可以仅编译着色器源一次(有适当的限制),将其链接到着色器程序并在管道的任何阶段使用它?我的意思是这样的:

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.

当然,库着色器不应包含inout个全局变量,但可以使用uniform s。此外,函数原型应在每个着色器源中使用之前声明,因为在将多个相同类型的着色器链接到一个程序时可以这样做。

如果上述情况不可能,那么为什么?对于GLSL的C类编译模型,这种“库”着色器看起来非常符合逻辑。

2 个答案:

答案 0 :(得分:2)

  

是否可以仅编译着色器源一次(有适当的限制),将其链接到着色器程序并在管道的任何阶段使用它?

没有。我建议,如果你必须这样做,只需将文本添加到各种着色器。好吧,不要直接添加到实际的字符串中;相反,将其添加到您通过glShaderSource/glCreateShaderProgram提供的着色器字符串列表中。

  

如果上述情况不可能,那么为什么?

因为每个着色器阶段都是独立的。

应该注意的是,甚至Vulkan都没有改变这一点。好吧,不是你想要的方式。 允许您在一个SPIR-V模块中进行反向:多个着色器阶段。但它没有(在API级别)允许您有多个模块为单个阶段提供代码。

答案 1 :(得分:0)

结构,功能,模块链接等所有高级构造都大多只是API提供的细节,使您的生活更容易输入。例如,HLSL允许您使用#include,但要在GLSL中执行类似的操作,您需要自己执行该预处理步骤。

当GPU必须执行着色器时,它每帧运行相同的代码数百,数千,甚至数百万次 - 驱动程序将您的着色器转换为自己的HW特定指令集并将其优化为最小可用于保证其指令缓存和着色器引擎的最佳性能的指令数。