【问题标题】:How to share shader code across shading stages in OpenGL如何在 OpenGL 中跨着色阶段共享着色器代码
【发布时间】:2016-09-09 22:31:44
【问题描述】:

我有一些用 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全局变量,但它可以使用uniforms。此外,函数原型应在每个着色器源中使用之前声明,因为可以将多个相同类型的着色器链接到一个程序中。

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

【问题讨论】:

  • 我个人使用预处理器方法。这很容易理解,您只需使用#include 之类的关键字即可使其工作,并且您可以通过一些索引工作轻松地将任何 GLSL 错误解析回原始库文件。这确实意味着您的驱动程序将编译更多代码,并且该代码将占用更多空间。但我发现这两个问题完全无关紧要。

标签: opengl compilation glsl shader


【解决方案1】:

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

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

如果以上这些都不可能,那为什么?

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

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-09-06
      • 2011-04-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-19
      相关资源
      最近更新 更多