删除GLSL着色器的正确方法是什么?

61
我的代码管理GLSL着色器的方式是,它创建每个着色器和相关程序,并删除每个着色器和程序。我最近阅读了http://www.opengl.org/wiki/GLSL_Object,其中指出:
由于着色器对象被附加到程序对象上,因此即使您删除着色器对象,它也将继续存在。只有当它不再附加到任何程序对象(当然,用户要求删除它时)时,系统才会删除它。
如果我在链接到程序后调用glDeleteShader()来删除着色器对象,我是否理解正确,我只需要跟踪程序?可以安全地假设这总是正确的吗?
4个回答

71

是的——事实上尽快分离和删除您的着色器对象非常理想。这样,驱动程序可以释放用于保存着色器源代码和未链接对象代码的所有内存,这可能相当大。我所做的测量表明,不删除着色器对象会使每个着色器的增量内存使用量增加5-10倍。


17
虽然根据官方文档你所说的是正确的(“在链接操作之后,应用程序可以自由修改已附加的着色器对象、编译已附加的着色器对象、分离着色器对象、删除着色器对象和附加附加的着色器对象。”),但我遇到了一些不良驱动程序,当您在移动平台上分离着色器时它们可能会出现问题。因为我曾经因此问题苦恼了几天,所以我建议在链接之后不要再分离着色器(删除则无妨)。 - Logan Pickup
4
问题在于仅仅删除着色器而不将其分离可能无法释放内存——它只能减少一个引用计数,直到你分离着色器才会归零。只要着色器仍然附加在程序上,用户可能会调用link函数重新链接程序,因此驱动程序需要保留足够的信息以执行该操作。所以你需要在内存使用和兼容性问题之间进行权衡... - Chris Dodd
1
大多数人不知道这一点,但着色器程序会记住它们的uniform变量。如果你想利用这一点来避免将未更改的uniform变量重新上传到GPU,可以使用相同的着色器对象链接多个着色器程序。这是在OpenGL ES 2.0中的一个不错的技巧,因为你不能使用UBO。 - mchiasson

13

一般来说,着色器对象管理的方式很简单。着色器对象本身并不真正做什么事情,所以根本没有必要去追踪它们。着色器对象应当存在足够长的时间来成功地链接一个程序对象。之后,这些着色器应当从程序对象中分离并删除。

以上假设您不想使用着色器对象来链接到另一个程序,当然如果有这种需要的话,也是可以的。在那种情况下,您应该在链接所有程序之后删除着色器对象。


8
简而言之,在调用glLinkProgram()后,对于每个着色器都要调用glDeleteShader(),这将标记它们以进行删除。当不再需要该程序时,请调用glDeleteProgram() - 这个调用不仅会删除程序,还会分离所有附加到它的着色器并将它们删除(如果没有被任何其他程序使用)。
因此,通常情况下您不必调用glDetachShader()。 请阅读glDeleteProgram()的文档。

阅读后我才意识到我使用的是glDeleteShader而不是glDeleteProgram。有时候人们会错过一些简单的东西。 - Mike O

6
是的。您可以安全地删除着色器。实际上,这是首选的方法,因为您需要进行较少的维护。您不需要跟踪要删除的内容,也不会忘记这样做。而且,它仍然可以正常工作。
“删除”着色器,就像所有 OpenGL 对象一样,只是设置了一个标志,表示不再需要它。OpenGL 会保留它,直到自己需要它时才会实际删除它(最有可能,在程序被删除后)。

1
实际上,您甚至可以在链接后分离着色器(它们实际上只包含代码,然后完全进入程序),因此它们会立即被删除。 - Christian Rau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接