Search code examples
c#unity-game-enginecompute-shader

Sending and Getting float array to and from compute shader in unity


I am having a problem with compute shaders in Unity that I don't fully understand. I'm getting an error saying:

ArgumentException: Array passed to ComputeBuffer.SetData(array) must be blittable. Data.i is not blittable because it is not of value type (System.Double[]) Data.w is not blittable because it is not of value type (System.Double[])

UnityEngine.ComputeBuffer.SetData (System.Array data) (at <3be1a7ff939c43f181c0a10b5a0189ac>:0) Script1.Compute () (at Assets/Script1.cs:46) Script1.Start () (at Assets/Script1.cs:37)

As far as I know, the data I'm sending is of type double[]. Here is the C# code:


public class Script1 : MonoBehaviour
{
    public double[] inputs;
    public double[] weights = { 3.1, 2.1, 8.7 };
    float bias = 3;
    float output = 0;

    public ComputeShader compute1;
    ComputeBuffer buffer;
    public struct Data
    {
        public double[] i;
        public double[] w;
        public float b;
        public float o;
    }
    Data[] d;
    
    // Start is called before the first frame update
    void Start()
    {
        d = new Data[1];
        d[0] = new Data
        {
            i = new double[] { 1.2, 5.1, 2.1 },
            w = weights,
            b = bias,
            o = output
        };
        buffer = new ComputeBuffer(d.Length, 56);

        Compute();
    }


    void Compute()
    {
        float[] result = new float[2];
        int kernelHandle = compute1.FindKernel("CSMain");
        compute1.SetBuffer(kernelHandle, "buffer", buffer);
        buffer.SetData(d);
        buffer.SetData(result);
        compute1.Dispatch(kernelHandle, 24, 1, 1);
        buffer.GetData(result);
    }
    private void OnDestroy()
    {
        buffer.Dispose();
    }
}

And here is the code in the Compute Shader.

// Each #kernel tells which function to compile; you can have many kernels
#pragma kernel CSMain

// Create a RenderTexture with enableRandomWrite flag and set it
// with cs.SetTexture
RWTexture2D<float4> Result;
struct d 
{
    double i[3], w[3];
    float b, o;
};
RWStructuredBuffer<d> buffer;


[numthreads(24,1,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
    // TODO: insert actual code here!

    float result[] = { buffer[0].i[0] * buffer[0].w[0] + buffer[0].i[1] * buffer[0].w[1] + buffer[0].i[2] * buffer[0].w[2] + buffer[0].b, 0 };

}

Is there a different way to send a double array to and from Compute Shaders? I've tried casting as (System.Double) and it just says that it's not necessary and gives the same error.


Solution

  • You can not pass types to compute shaders that are non-blittable.

    While your double[] itself actually would be blittable as it only contains values of a blittable type (double) it becomes non-blittable since you nest it within another struct.

    One-dimensional arrays of blittable primitive types, such as an array of integers. However, a type that contains a variable array of blittable types is not itself blittable.

    You could try to rather use e.g. a NativeArray<double>