GLSL uniform array allocation

Hi everyone,

I’m running into some unexpected behavior when allocating uniform array buffers in a GLSL TOP and would appreciate some insight.

Context:
I have two CHOPs, each with a length of n , representing x and y coordinates that I want to draw with GLSL.

In my GLSL shader, I try to allocate arrays like this:

uniform float xPoints[n];
uniform float yPoints[n];

The issue is that the CHOP length (n ) can change at runtime, but the uniform array allocation in GLSL cannot. To work around this, I tried allocating the arrays with more elements than I’d ever need, and then limiting the number of points drawn using:

int numPoints = n;
for (int i = 0; i < numPoints; i++) {
    if (i >= numPoints){
        break;
    }
    // ...draw points...
}

Problems I’m seeing:

  • Allocating more memory than needed seems to cause problems. numPoints is ignored, and points are drawn at y=0 or at seemingly random positions. The x values mostly work as expected.
  • I understand that uninitialized memory can be garbage or zero, depending on the hardware, driver, or memory state. I tried padding my CHOPs with some value, but that didn’t solve the issue.
  • I’m also aware there are size limits on allocations, but the behavior seems inconsistent. For example, in my example tox:
    • When drawing 50 points, I can allocate up to 4096 points without problems.
    • When drawing realworld data with 3000+ points, even allocating the exact size needed for the array doesn’t seem to work.

I’m sure i can find a solution to get this to work via CHOP->TOP and using it as a 2D sampler - but i’ve been fighting this issue for some time now and would really like to understand whats going on here.

Any insights or suggestions would be greatly appreciated!
uniform_array_allocation.tox (258.3 KB)

You should use a texture buffer instead of a uniform array for this usage case. The size can be variable for texture buffer, and the size limitations are far large (usually 2GB+)

Hopefully we’ll have better access to storage buffers in the future for this kind of use case.

I’d note that in either case, the shader could be improved. You’re doing 5000 iterations per fragment which is a very inefficient way to render this data. I’m not sure if this is a representation of what you’re actually trying to do, but you’d likely be better served by instancing some geometry and then using the position data to displace the instances (either by using TD’s Geo COMP or manually in the vertex shader). Your example project is running at 60fps on my computer so maybe not an issue for your use case but thought I’d point that out. As alway, profile on your real project before taking performance advice from strangers.

Also, at least on my computer, your reference data and the two “unexpected” GLSL shaders all look the same. Which does suggest you’re running into some driver wonkiness, if I’m interpreting the network corectly.

1 Like

Yes, with POPs you have access to the buffers of data much more freely.

1 Like

Thank you malcolm and also Tim from yfx who helped me on the discord with this.
I wasn’t aware that chops can be used as a texture buffer. Its written in the documentation but my mind didn’t really comprehent CHOPS and texturebuffers together.

For future reference for anyone to stumble upon:
Instead of

uniform float xPoints[n];
uniform float yPoints[n];
//.....
float x = xPoints[i];
float y = yPoints[i];

change the ‘Array Type’ on the array page to Texture buffer and use

uniform samplerBuffer xPoints; 
uniform samplerBuffer yPoints; 
//.....
float x = texelFetch(xPoints, i).x;
float y = texelFetch(yPoints, i).x;

When set to vec2, the data can also be sampled from a single chop

uniform samplerBuffer Points; 
//.....
vec2 points = texelFetch(Points, i).xy;

Happy to help. Note that you’ll likely want to only use one texelFetch() call for that, rather than two. Depending on driver/optimizer, you may get much better performance by reducing the calls.

1 Like