1

I use C# with OpenTK to access OpenGL API. My project uses tessellation to render a heightmap. My tessellation control shader splits a square into a grid of 64 squares and my tessellation evaluation shader adds vertical offsets to those points. Vertical offsets are stored in a uniform float buffer like this:

uniform float HeightmapBuffer[65 * 65];

Everything works fine, when I run the project on my laptop with AMD Radeon 8250 GPU. The problems start when I try to run it on Nvidia graphic cards. I tried an older GT 430 and a brand new GTX 1060, but results are same:

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

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. It's a little strange, since my array actually uses only 16.9 kB, so I am not even sure if the "BLOCK SIZE" actually limits the size of one variable. Maybe it limits the size of all uniforms passed to one shader? Even so, I can't believe that my program would use 65 kB.

Note that I also tried to go the 'common' way by using a texture, but I think there were problems with interpolation, so when placing two adjacent heightmaps together, the borders didn't match. With a uniform buffer array on the other side, things work perfectly.

So what is the actual meaning of GL_MAX_UNIFORM_BLOCK_SIZE? Why is this value on Nvidia GPUs so low? Is there any other way to pass a large array to my shader?

Jaka Kordež
  • 137
  • 1
  • 7
  • 1
    `float` uniforms are actually the size of a `vec4` so you have `4 bytes * 4 * 65 * 65` = `67.6 KiB`. – genpfault Dec 21 '17 at 21:03
  • Hrm, I'm having a hard time sourcing that info in the GL spec so take it with a grain of salt. I *might* be remembering the ES 2.0 spec. – genpfault Dec 21 '17 at 21:09
  • Possible duplicate of [Error in Geometry Shader from large array](https://stackoverflow.com/questions/29262469/error-in-geometry-shader-from-large-array) – Gusman Dec 21 '17 at 21:39

1 Answers1

4

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 is the wrong limit. That applies only to Uniform Buffer Objects.

You just declare an array

uniform float HeightmapBuffer[65 * 65];

outside of a uniform block. Since you seem to use this in a tesselation evaluation shader, the relevant limit is MAX_TESS_EVALUATION_UNIFORM_COMPONENTS (there is a separate such limit for each programmable stage). This component limit counts just the number of float components, so a vec4 will consume 4 components, a float just one.

In your particular case, the latest GL spec, [GL 4.6 core profile] (https://www.khronos.org/registry/OpenGL/specs/gl/glspec46.core.pdf) at the time of this writing, just guarantees a minimum value of 1024 for that (=4kiB), and you are way beyond that limit.

It is actually a very bad idea to use plain uniforms for such amounts of data. You should consider using UBOs, Texture Buffer Objects, Shader Storage Buffer Objects or even plain textures to store your array. UBOs would probably be the most natural choice in your scenario.

derhass
  • 43,833
  • 2
  • 57
  • 78
  • @PeterMcG: the question clearly states that this is about the tesselation evaluation shader, not the control one. The default uniform block isn't a uniform block in the sense of `GL_MAX_UNIFORM_BLOCK_SIZE`, which only applies to UBOs. The naming might be unfortunate, but the spec is very clear on that. – derhass Dec 21 '17 at 22:07