【问题标题】:Uniform buffer size on Nvidia GPUsNvidia GPU 上的统一缓冲区大小
【发布时间】:2017-12-21 20:57:22
【问题描述】:

我使用 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 上返回 ~500MB,在两个 Nvidia 芯片上返回 65.54 kB。有点奇怪,因为我的数组实际上只使用了 16.9 kB,所以我什至不确定“块大小”是否真的限制了一个变量的大小。也许它限制了传递给一个着色器的所有制服的大小?即便如此,我还是不敢相信我的程序会使用 65 kB。

请注意,我也尝试通过使用纹理来采用“常见”方式,但我认为插值存在问题,因此当将两个相邻的高度图放在一起时,边界不匹配。另一边有一个统一的缓冲区数组,一切都很好。

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

【问题讨论】:

  • float 制服实际上是vec4 的大小,所以你有4 bytes * 4 * 65 * 65 = 67.6 KiB。
  • Hrm,我很难在 GL 规范中获取该信息,因此请谨慎对待。我可能记得 ES 2.0 规范。

标签: c# opengl nvidia


【解决方案1】:

当我研究这个问题时,我发现 GL_MAX_UNIFORM_BLOCK_SIZE 变量在 AMD 上返回 ~500MB,在两个 Nvidia 芯片上返回 65.54 kB。

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 core profile] (https://www.khronos.org/registry/OpenGL/specs/gl/glspec46.core.pdf) 在撰写本文时,只需保证该值的最小值为 1024 (=4kiB),而您远远超出了该限制。

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

【讨论】:

  • @PeterMcG:问题清楚地表明这是关于镶嵌评估着色器,而不是控制着色器。默认的统一块不是GL_MAX_UNIFORM_BLOCK_SIZE 意义上的统一块,它仅适用于 UBO。命名可能很不幸,但规范对此非常清楚。
猜你喜欢
  • 2022-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-10
  • 2012-06-07
  • 2020-09-05
  • 1970-01-01
  • 2014-06-10
相关资源
最近更新 更多