Compute shader - how iterate by each thread in all thread groups?

Hi,

i have script and compute shader like below. My OutputData array length are equal to overall threads number in compute shader. How i should access my OutputData array, to set 1 on each array element by every individual thread?

Script

using System;
using System.Collections;
using System.IO;
using UnityEngine;

public class ComputeShadersManager : MonoBehaviour
{
    private const int INPUT_DATA_ARRAY_SIZE = 32768;
    private const string KERNEL_NAME = "Main";
    private const string OUTPUT_PROPERTY_NAME = "OutputData";
 
    private readonly int[] EMPTY_OUTPUT_DATA = new int[INPUT_DATA_ARRAY_SIZE];

    [SerializeField]
    private ComputeShader computeShaderKernel;

    private int computeShaderKernelIndex;
    private ComputeBuffer outputDataBuffer;
    private int[] outputData;

    private void Awake()
    {
        computeShaderKernelIndex = computeShaderKernel.FindKernel(KERNEL_NAME);
        outputDataBuffer = new ComputeBuffer(INPUT_DATA_ARRAY_SIZE, sizeof(int));
        outputData = EMPTY_OUTPUT_DATA;
        computeShaderKernel.SetBuffer(computeShaderKernelIndex, OUTPUT_PROPERTY_NAME, outputDataBuffer);
    }

    private IEnumerator Start()
    {
        while (true)
        {
            outputDataBuffer.SetData(EMPTY_OUTPUT_DATA);
            computeShaderKernel.Dispatch(computeShaderKernelIndex, 8, 8, 8);

            yield return null;
     
            outputDataBuffer.GetData(outputData);
     
            File.WriteAllText(@"D:\Results.txt", String.Join("\n", outputData));
        }
    }
}

Compute shader

#pragma kernel Main

RWStructuredBuffer<int> OutputData;

[numthreads(8,8,1)]
void Main (uint3 groupID : SV_GroupID, uint3 groupThreadID : SV_GroupThreadID, uint groupIndex : SV_GroupIndex, uint3 id : SV_DispatchThreadID)
{
    OutputData[???] = 1;
}

If you are using 1-dimensional data which you want to put into a StructuredBuffer, you could just use the id (SV_DispatchThreadID) as your index? i.e:

OutputData[id.x] = 1;

Now each thread will write value of 1 to the corresponding index, and they won’t overwrite anything written by the other threads.

And in case of multidimensional data, 2D for example, you could use 2D to 1D indexing and then 1D to 2D to put your data back to an image.

When testing these things it’s best to read the data back to CPU side, and print the values out see what actually happened.

I’ve trying it already and if i use just id.x value 1 is set to only firsts 64 elements, whereas i want to set all 32768 (88881) array elements.

You got a few things a bit wrong I think - you are using a 3D dispatch when you are handling a StructuredBuffer, which is 1D.

You need to calculate the correct size of thread groups needed that matches your threads in the actual shader. i.e. if you got 32k items to process, you would calculate the value correctly so that there is n count of thread groups dispatched.

If your threads X dimensions was 32, then with 32768 you would get exactly 1024 thread groups (32768 / 32 = 1024.) In this case your compute shader thread declaration would look like this:

[numthreads(32, 1, 1)]

And in this case with 32768 items to process your dispatch would be something like this:

compute.Dispatch(kernel, 1024, 1, 1);

So the data would be processed in 1024 groups size of 32 units.

It’s not that smart to use hardcoded values, instead It might be better to calculate the correct dispatch size as the data being processed might vary in size.

(Hopefully I didn’t write anything wrong in hurry.)

I can write an example after I get finished with other things here.

1 Like

No, it’s not necessary. You already told me enough and i understood how to do it. Thank you very much for help :).