与常规缓冲区和制服相比,OpenGL 纹理单元背后的原因是啥?
Posted
技术标签:
【中文标题】与常规缓冲区和制服相比,OpenGL 纹理单元背后的原因是啥?【英文标题】:What is the reasoning behind OpenGL texture units as opposed to regular buffers and uniforms?与常规缓冲区和制服相比,OpenGL 纹理单元背后的原因是什么? 【发布时间】:2017-08-27 15:08:54 【问题描述】:我对 OpenGL API 非常陌生,刚刚发现了纹理以及如何使用它们。生成的纹理缓冲区的绑定方式与常规制服的绑定方式不同,而是使用glActiveTexture
,然后进行绑定,而不是像我们使用其他常量那样仅通过glUniform
将纹理提供给着色器。
这个约定背后的原因是什么?
我能想到的唯一原因是利用显卡的全部潜力和纹理处理能力,而不是直接绑定缓冲区。这是正确的推理,还是仅仅是 API 的实现方式?
官方 wiki 上没有给出任何理由,只是说这很奇怪:“在 OpenGL 中使用绑定纹理有点奇怪”https://www.khronos.org/opengl/wiki/Texture
【问题讨论】:
Related if not duplicate 我会看看它是否回答了我的问题,谢谢。没看到那个。 如果您使用“直接状态访问”(DSA),API 会更有意义。假设您使用的是 GL core 4.5 或更高版本。 【参考方案1】:您的问题可以用两种方式解释。
“为什么我们将纹理绑定到上下文而不是着色器?”
因为这会使多个着色器使用相同的纹理变得不必要地困难。请注意,几乎没有图形 API 直接将纹理附加到程序。不是任何版本的 D3D,不是 Metal,甚至是 Vulkan。
纹理是着色器使用的资源。但它们不是着色器的一部分。
“为什么我们对待纹理不同于一般的值数组?”
在现代 OpenGL 中,着色器可以访问多种不同类型的资源:UBO、SSBO、纹理和图像。这些资源中的每一种最终都代表了图形硬件的潜在不同部分。
存储块不仅仅是一个可以更大的统一块。存储缓冲区代表着色器进行全局内存访问,而统一块通常直接复制到着色器执行单元中。在后一种情况下,访问它们的数据要快得多,但这也意味着您受限于这些执行单元可以拥有多少存储空间。
现在,并非所有硬件都如此(AMD 的 GCN 硬件对两者的处理方式几乎相同,这就是 their UBO limits are so large 的原因)。但对于很多硬件来说都是如此。
纹理更加复杂,因为出于性能原因,实现需要能够以最佳方式存储它们的数据。因此,纹理存储格式是不透明的。它们甚至在 Vulkan 等表面上低级的 API 中是不透明的。哦,当然,存在线性格式,但根本不需要实现来让您读取它们。
所以纹理不仅仅是常量数组。
【讨论】:
谢谢。这很好地回答了我的问题。 :)【参考方案2】:你在比较两个完全不同的东西
可以(以某种方式)将纹理对象与缓冲区对象进行比较。纹理由glActiveTexture
和glBindTexture
的组合绑定到纹理单元,而缓冲区由glBindBuffer
绑定,这有点相似。
纹理采样器制服是着色器中的制服,因此应该与其他制服进行比较。此采样器由glUniform1i
调用设置。
【讨论】:
所以采样器是由统一调用设置的,它们从纹理单元中获取纹理数据。知道了。但是,这样做背后的原因是什么,而不是仅仅将大量像素颜色(纹理)正常发送到着色器?硬件优势? @Timothy:“但是,这样做背后的原因是什么,而不是通常将大量像素颜色(纹理)发送到着色器?” “通常”是什么意思?没有“正常”的方式可以将“巨大的像素颜色数组”发送到着色器。大多数纹理很容易超过统一数组甚至 UBO 的存储限制。 @NicolBolas 大纹理可能会超出限制,但较小的纹理不会。所以你说答案只是存储大小问题? @Timothy:不,我的意思是这个问题没有意义。纹理不是统一的数组,因此以统一方式访问纹理是没有意义的。以上是关于与常规缓冲区和制服相比,OpenGL 纹理单元背后的原因是啥?的主要内容,如果未能解决你的问题,请参考以下文章
使用制服时 Xamarin OpenGL 片段着色器的奇怪行为
使用 OpenGL 渲染时 CPU 和 GPU 之间的数据丢失