Nvidia GPU 上的统一缓冲区大小

Uniform buffer size on Nvidia GPUs

我使用 C# 和 OpenTK 来访问 OpenGL API。我的项目使用曲面细分来渲染高度图。我的曲面细分控制着色器将一个正方形拆分为 64 个正方形的网格,我的曲面细分评估着色器为这些点添加了垂直偏移。垂直偏移量存储在一个统一的浮动缓冲区中,如下所示:

uniform float HeightmapBuffer[65 * 65];

当我 运行 使用 AMD Radeon 8250 GPU 的笔记本电脑上的项目时,一切正常。当我尝试在 Nvidia 显卡上 运行 时,问题就开始了。我尝试了旧的 GT 430 和全新的 GTX 1060,但结果是一样的:

Tessellation evaluation info
----------------------------
0(13) : error C5041: cannot locate suitable resource to bind variable "HeightmapBuffer". Possibly large array.

当我研究这个问题时,我发现 GL_MAX_UNIFORM_BLOCK_SIZE 变量在 AMD 上 returns ~500MB,在两个 Nvidia 芯片上都是 65.54 kB。这有点奇怪,因为我的数组实际上只使用了 16.9 kB,所以我什至不确定 "BLOCK SIZE" 是否真的限制了一个变量的大小。也许它限制了传递给一个着色器的所有制服的大小?即便如此,我还是不敢相信我的程序会使用 65 kB。

请注意,我也尝试过 'common' 使用纹理的方式,但我认为插值存在问题,因此当将两个相邻的高度图放在一起时,边界不匹配。在另一边有一个统一的缓冲区数组,事情就完美了。

那么GL_MAX_UNIFORM_BLOCK_SIZE的实际含义是什么?为什么 Nvidia GPU 上的这个值这么低?有没有其他方法可以将大数组传递给我的着色器?

As I researched this problem, I found GL_MAX_UNIFORM_BLOCK_SIZE variable which returns ~500MB on the AMD and 65.54 kB on both Nvidia chips.

GL_MAX_UNIFORM_BLOCK_SIZE 是错误的限制。这仅适用于 Uniform Buffer Objects.

你只需声明一个数组

uniform float HeightmapBuffer[65 * 65];

在统一块之外。由于您似乎在曲面细分评估着色器中使用了它,因此相关限制是 MAX_TESS_EVALUATION_UNIFORM_COMPONENTS(每个可编程阶段都有一个单独的此类限制)。此 component 限制只计算浮动组件的数量,因此 vec4 将消耗 4 个组件, float 仅一个。

在您的特定情况下,最新的 GL 规范,[GL 4.6 核心配置文件] (https://www.khronos.org/registry/OpenGL/specs/gl/glspec46.core.pdf) 在撰写本文时,仅保证该值的最小值为 1024 (=4kiB),而您 方式 超出了该限制。

对如此大量的数据使用普通制服实际上是一个非常糟糕的主意。您应该考虑使用 UBOs, Texture Buffer Objects, Shader Storage Buffer Objects 甚至纯纹理来存储您的数组。在您的场景中,最终受益人可能是最自然的选择。