GLSL 多个着色器程序 VS 制服开关
我正在研究着色器管理器架构,并且我有几个问题需要向更高级的人员询问。 我当前的选择反对两种设计,它们是:
1. 每个材质着色器程序
=> Create one shader program per material used in the program.潜在的缺点:
- 考虑到每个对象可能有自己的材质,它涉及大量的 glUseProgram 调用。
- 意味着创建很多shaderprogram对象。
- 比 #2 更复杂的架构。
优点:
- 可以专门为材质中使用的每个“选项”生成着色器代码。
- 如果我没记错的话,制服只需设置一次(在创建着色器程序时)。
2. 全局着色器程序
=> Create one shader program per shader functionality (lightning, reflection, parallax mapping...) and use configuration variables to enable or discard options depending on the material to render.潜在缺点:
- 每帧必须多次更改制服。
优点:
- 着色器程序数量较少。
- 减少 SP 开关 (glUseProgram)。
您可能会注意到我目前的倾向是#1,但我想知道您对此的看法。
- 初始制服设置是否抵消了 glUseProgram 调用开销(我不是特别速度狂)?
- 在情况 #1 中,出于任何内存或性能考虑,我应该在创建 SP 时仅调用一次 glLinkProgram,还是每次调用 glUseProgram 时都必须取消链接/链接?
- 有更好的解决方案吗?
谢谢!
I'm working on a shader manager architecture and I have several questions for more advanced people.
My current choice oppose two designs which are:
1. Per material shader program
=> Create one shader program per material used in the program.
Potential cons:
- Considering every object might have its own material, it involves a lot of glUseProgram calls.
- Implies the creation of a lot of shaderprogram objects.
- More complex architecture that #2.
Pros:
- Shader code can be generated specifically for each "options" used in the material.
- If i'm not wrong, uniforms have to be set only one time (when the shaderprogram is created).
2. Global shader programs
=> Create one shader program per shader functionality (lightning, reflection, parallax mapping...) and use configuration variables to enable or discard options depending on the material to render.
Potential cons:
- Uniforms have to be changed many times per frame.
Pros:
- Lower shader programs count.
- Less SP swich (glUseProgram).
You might notice that my current tendency is #1, but I wanted to know your opinion about it.
- Does initial uniforms setting offset the glUseProgram call overhead (I'm not especially speed freak) ?
- In the case #1, for any memory or performance consideration, should I call glLinkProgram only once when I create the SP, or I must unlink/link each time I call glUseProgram?
- Are there better solutions ?
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
让我们看看#1:
这其实没什么大不了的。交换程序很困难,但你也会交换纹理,所以这并不是说你还没有改变重要的状态。
这会很痛。事实上,#1 的主要问题是着色器的爆炸性组合。虽然 ARB_separate_program_objects 会有所帮助,但它仍然意味着您必须编写大量着色器,或者想出一种不编写大量着色器的方法。
或者您可以使用延迟渲染,这有助于缓解这种情况。其众多优点之一是它将材质数据的生成与将该材质数据转换为光反射率(颜色)的计算分开。因此,您可以使用的着色器要少得多。您有一组生成材质数据的着色器,以及一组使用材质数据进行光照计算的着色器。
所以我想说使用 #1 和延迟渲染。
Let's look at #1:
This isn't that big of a deal, really. Swapping programs is hard, but you'd be swapping textures too, so it's not like you're not already changing important state.
This is going to hurt. Indeed, the main problem with #1 is the explosive combination of shaders. While ARB_separate_program_objects will help, it still means you have to write a lot of shaders, or come up with a way to not write a lot of shaders.
Or you can use deferred rendering, which helps to mitigate this. Among its many advantages is that it separates the generation of the material data from the computations that transform this material data into light reflectance (colors). Because of that, you have far fewer shaders to work with. You have a set of shaders that produces material data, and a set that uses the material data to do lighting computations.
So I would say to use #1 with deferred rendering.
这实际上取决于您的硬件和应用程序的具体要求。
#2 的另一个缺点是,您的着色器通常最终效率不高,因为它必须根据您传入的制服进行一些条件分支。因此,您基本上是在减少状态切换时间与减少着色器吞吐量之间进行权衡。这取决于哪一个更糟糕。
每个着色器绝对应该只调用一次 glLinkProgram。编译着色器比切换已编译的着色器花费的时间要长得多。
确实没有更好的解决方案。几乎每个编写渲染引擎的人都必须做出所面临的决定。
It really depends on your hardware and the specific demands of your app.
Another con of #2 is that your shader usually ends up not being as efficient because it has to do some conditional branching based on the uniforms you pass in. So you're basically trading off between less time switching state versus decreased throughput in your shader. It depends on which one is worse.
You should definitely only call glLinkProgram once per shader. Compiling a shader takes much longer than switching out already-compiled shaders.
There aren't really any better solutions. Pretty much everyone writing a rendering engine has to make the decision you're faced with.
在移动设备上,着色器中的分支大大增加了渲染时间。您应该对切换程序的时间与与每个顶点/每个纹素重复操作中的分支相关的降低的绘制率进行一些测量。我推荐方法 #1 并看看如何设置 GPUImage 以实现良好的 oop 友好着色器架构。
https://github.com/BradLarson/GPUImage
On mobile devices, branching in a shader greatly increases time to render. You should do some measuring on the time to switch programs vs the reduced draw rate associated with branching in a per vertex / per texel repeating operation. I'd recommend method #1 and take a look at how GPUImage is set up for a good oop friendly shader architecture.
https://github.com/BradLarson/GPUImage