OpenGL 统一缓冲区混淆
有人可以告诉我关于看似不必要的复杂统一缓冲区吗?我读过 OpenGL Superbible 5 中的部分,我看过博客上的一些示例,我读过官方规范,但我仍然不明白。
具体来说,所有示例似乎都需要一个着色器程序来开始,以便最初使用 glGetActiveUniformsiv 设置统一缓冲区。我不明白这一点。为什么该接口不允许您在不引用着色器程序的情况下定义结构,在链接时根据程序验证缓冲区格式?
其次,如果我从一个程序获得结构布局,假设使用一组制服的所有程序的结构布局都相同,那么该结构是否保证具有相同的偏移量、数据大小等?我想是这样。
第三,我不明白结合点。我必须使用索引调用 glBindBufferBase,然后使用块索引和我传递给 glBindBufferBase 的索引调用 glUniformBlockBinding。我很难想象到底发生了什么。 Superbible 缺乏清晰度,规格和我见过的样品也是如此。
Can someone tell me about the seemingly needlessly complicated Uniform Buffers? I've read the section in OpenGL Superbible 5, I've looked at some examples on blogs and I've read the official spec, and I still don't get it.
Specifically, all examples seem to require a shader program to begin with in order to setup the uniform buffer initially with glGetActiveUniformsiv. I don't understand this. Why doesn't the interface allow you to define the structure without referring to a shader program, validating the buffer/s formats against the program at link time?
Secondly, if I get the structure layout from one program, assuming the structure layout is the same for all programs that use the set of uniforms, is the structure guaranteed to have the same offsets, data sizes and so on? I would assume so.
Thirdly, I don't understand binding points. I have to call glBindBufferBase with an index, and then call glUniformBlockBinding with a block index and the index I passed into glBindBufferBase. I'm having trouble visualising exactly what's going on here. The Superbible lacks clarity, as does the spec and the samples I've seen.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您到底为什么想要这样做?就我个人而言,除非您遇到严重的数据短缺问题并且需要每个字节,否则我认为没有理由使用除
std140
之外的任何内容。它使代码如此更加简洁。但是,如果您坚决要避免使用
std140
,请继续阅读。规范彻底解释了这一点:一切都在布局限定符中。
总共有 3 个布局限定符:
packed
、shared
和std140
。packed
意味着实现可以自由地按照它想要的方式安排所有内容。这包括删除当前程序不使用的制服。因此布局是实现定义的,并且该布局中的某些制服可能已被优化掉。共享
意味着实现可以像打包
一样自由地排列数据。但是,它必须为每件制服提供存储空间。这使得在程序之间共享统一布局成为可能,因此得名。shared
还要求实现提供一致的布局,以实现跨程序的一致定义。因此,您只需要查询一种布局即可。为了回答你的第一个问题,如果你愿意的话,你可以创建一个具有
共享
布局的假程序。您可以使用它来查询统一块的布局。然后,只要布局在其他程序中保持一致(使用共享
布局),布局就会全部相同。因此不需要专门的 API。然而,
std140
意味着统一块的布局是由 OpenGL 实现逐字节显式定义的。这隐含地允许共享,因为在该规范下两个相同的统一块将具有相同的布局。由于实现无法优化std140
布局块中的制服,因此一切都很完美。同样,几乎没有理由避免
std140
。除非您受到非常非常严重的内存限制。这与纹理的机制完全相同。唯一的区别是统一的块名称本身并不是统一的。
使用
glActiveTexture(GL_TEXTURE0 + i);glBindTexture()
将纹理对象绑定到纹理图像单元,其中i
是纹理图像单元索引。您现在需要告诉着色器哪个采样器使用该图像单元。然而,OpenGL 不允许您直接与名称进行关联;您必须将采样器名称转换为索引位置。因此,您可以使用glGetUniformLocation
获取特定采样器的统一位置。获得统一位置后,您可以通过调用glUniform1i(loc, i)将纹理图像单元与该位置关联起来,其中i
也是您绑定的纹理图像单元纹理到。使用
glBindBufferRange(GL_UNIFORM_BUFFER, i, ...)
将统一缓冲区对象绑定到统一缓冲区绑定点,其中i
是统一缓冲区绑定点。您现在需要告诉着色器哪个统一块使用该绑定点。然而,OpenGL 不允许您直接与名称进行关联;您必须将统一块转换为索引位置。因此,您可以使用glGetUniformBlockIndex 获取特定统一块的索引。获得索引后,您可以通过调用 glUniformBlockBinding(program, index, i) 来将统一缓冲区绑定点与该索引关联起来,其中i
也是统一缓冲区绑定将统一缓冲区绑定到的点。看到了吗?完全一样。它们使用不同的术语,但结构上是相同的。如果您需要图片,那么您可以找到更彻底的讨论,其中包括这里有一个图表。
Why exactly would you want to? Personally, unless you have a serious data shortage problem and need every byte, I see no reason to use anything other than
std140
. It makes the code so much cleaner.However, if you're dead-set on avoiding
std140
, read on.The specification thoroughly explained this: it's all in the layout qualifiers.
There are exactly 3 layout qualifiers:
packed
,shared
, andstd140
.packed
means that the implementation is free to arrange everything pretty much as it wants. This includes removing uniforms that the current program does not use. So the layout is implementation-defined, and certain uniforms within that layout may have been optimized away.shared
means that the implementation is free to arrange the data just likepacked
. However, it must provide storage for each of the uniforms. This makes it possible to share uniform layout among programs, hence the name.shared
also requires that the implementation will provide a consistent layout for consistent definitions across programs. Therefore, you only need to do the querying for one layout.To answer your first question, you could if you so desire create a fake program with
shared
layout. You could use it just to query the layout for the uniform block. Then, as long as the layout is consistent across other programs (with theshared
layout), the layouts will all be the same. So there's no need for a special API for it.std140
however means that the layout of a uniform block is defined explicitly by the OpenGL implementation, byte for byte. This implicitly allows sharing, since two identical uniform blocks under this specification will have the identical layout. And since the implementation cannot optimize away uniforms in astd140
layout block, everything is perfect.Again, there is almost no reason to avoid
std140
. Not unless you are under very, very severe memory constraints.It's the exact same mechanism as for textures. The only difference is that uniform block names are not themselves uniforms.
Texture objects are bound to texture image units, using
glActiveTexture(GL_TEXTURE0 + i);glBindTexture()
, wherei
is the texture image unit index. You now need to tell the shader which sampler uses that image unit. However, OpenGL doesn't let you do the association directly with the name; you have to convert the sampler name into an index location. So you get the uniform location to a particular sampler withglGetUniformLocation
. Once you have the uniform location, you can associate the texture image unit with that location by callingglUniform1i(loc, i)
, where againi
is the texture image unit you bound the texture to.Uniform buffer objects are bound to uniform buffer binding points, using
glBindBufferRange(GL_UNIFORM_BUFFER, i, ...)
, wherei
is the uniform buffer binding point. You now need to tell the shader which uniform block uses that binding point. However, OpenGL doesn't let you do the association directly with the name; you have to convert the uniform block into an index location. So you get the index to a particular uniform block withglGetUniformBlockIndex
. Once you have the index, you can associate the uniform buffer binding point with that index by callingglUniformBlockBinding(program, index, i)
, where againi
is the uniform buffer binding points you bound the uniform buffer to.See? Exactly the same. They use different terms, but structurally, they're the same. If you need a picture, then you can find a more thorough discussion that includes a diagram here.