与常规缓冲区和制服相比,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】:

你在比较两个完全不同的东西

可以(以某种方式)将纹理对象与缓冲区对象进行比较。纹理由glActiveTextureglBindTexture 的组合绑定到纹理单元,而缓冲区由glBindBuffer 绑定,这有点相似。

纹理采样器制服是着色器中的制服,因此应该与其他制服进行比较。此采样器glUniform1i 调用设置。

【讨论】:

所以采样器是由统一调用设置的,它们从纹理单元中获取纹理数据。知道了。但是,这样做背后的原因是什么,而不是仅仅将大量像素颜色(纹理)正常发送到着色器?硬件优势? @Timothy:“但是,这样做背后的原因是什么,而不是通常将大量像素颜色(纹理)发送到着色器?” “通常”是什么意思?没有“正常”的方式可以将“巨大的像素颜色数组”发送到着色器。大多数纹理很容易超过统一数组甚至 UBO 的存储限制。 @NicolBolas 大纹理可能会超出限制,但较小的纹理不会。所以你说答案只是存储大小问题? @Timothy:不,我的意思是这个问题没有意义。纹理不是统一的数组,因此以统一方式访问纹理是没有意义的。

以上是关于与常规缓冲区和制服相比,OpenGL 纹理单元背后的原因是啥?的主要内容,如果未能解决你的问题,请参考以下文章

使用制服时 Xamarin OpenGL 片段着色器的奇怪行为

使用 OpenGL 渲染时 CPU 和 GPU 之间的数据丢失

OpenGL 索引和数组纹理

OpenGL-载入纹理

Opengl 和 Webgl:从附加到当前帧缓冲区的纹理中采样

✠OpenGL-5-纹理贴图