2
\$\begingroup\$

I'm trying to create a compute shader that will generate and manage the movement of a point cloud.

The shader needs several thousand points to work on and I want to pull back the first dozen or so.

Currently I'm trying to crate a minimal working example, where the compute shader populates a buffer of ~8k values and I read the first 10 back.

Compute Shader:

RWStructuredBuffer<float3> starLocationBuffer;
[numthreads(64, 1, 1)]
void BuildStars(uint id : SV_GroupIndex) {
    starLocationBuffer[id] = float3(id, 1, 1);
}

Calling class:

    private ComputeBuffer starLocations;
    private int numStars = 8192;
    private int numLocations = 10;


    private void Build() {
        starLocations = new ComputeBuffer(
            numStars,
            Marshal.SizeOf(typeof(Vector3)),
            ComputeBufferType.Default,
            ComputeBufferMode.Dynamic);

        mapComputeShader.SetBuffer(Kernel("BuildStars"), "starLocationBuffer", starLocations);

        int y = (int)(Mathf.Ceil(numStars / 64f));
        Debug.LogFormat("Building star map [64, {0}, 1] for a total of {1:#,0}", y, y * 64);
        mapComputeShader.Dispatch(Kernel("BuildStars"), 64, y, 1);

    }

    private void Read() {
        var locs = new Vector3[numLocations];
        starLocations.GetData(locs, 0, 0, numLocations);
        Debug.Log(String.Join(", ", locs.Select(x => x.ToString())));
    }

I'd expect that to return an array of Vector3 with values (0,0,0), (1,0,0), (2,0,0), etc...

What I actually get back varies. Initially, I was getting mostly-zero values with some unusual values thrown in (NaN and large numbers). Now, I get consistent zeros.

I'd assume this was an issue with the array being uninitialised, however, the compute shader is supposed to write every value before I go and look at the data.

My next thought is that there may be a race condition... Perhaps the compute shader hadn't had time to write those values before I went looking, however, this post by a Unity engineer indicates it enforces sequential execution.

What am I missing?

\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

I believe the problem is the arguments you are passing to Dispatch. The value that you are calling y is actually the number of threadGroups in the X dimension (the total number of objects to operate on, divided by how many threads are in each group). So, the line should be

mapComputeShader.Dispatch(Kernel("BuildStars"), y, 1, 1);

Also, I think you are using the wrong id in the shader. You are getting the id of the thread group, but what you actually want is the id of each individual thread. You can get that like this:

void BuildStars(uint3 id : SV_DispatchThread) {
    starLocationBuffer[id.x] = float3(id.x, 1, 1);
}
\$\endgroup\$
1
  • \$\begingroup\$ Thanks for the response. You're right about the thread ID. I was hoping to avoid the uint3 as I couldn't see any way to reliably determine how many threads are dispatched from inside the shader and thus couldn't see how to get a definitive multiplier to get a unique ID. Unfortunately, changing the dispatch dimensions doesn't result in any change [I actually started on 8192/1/1 and messed around from there] \$\endgroup\$
    – Basic
    Commented Oct 24, 2022 at 8:43
3
\$\begingroup\$

Turns out it was an issue with the way I was setting up the compute buffer.

Specifically, it was ComputeBufferMode.Dynamic that was incorrect.

https://forum.unity.com/threads/clarification-on-computebuffermode-immutable.1150250/

Immutable buffers should be used. It's a doc and naming bug. Immutable buffer is actually the most mutable of them all. Dynamic buffers are meant only for meshes etc, as they're CPU visible. Users shouldn't need to change the buffer mode at all. The default one works on C# side. We're delaying the doc fix for now.

Switching to ComputeBufferMode.Immutable [which isn't actually immutable] solved the problem.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .