[Resolved] How do you Create and Allocate Textures for use in ComputeShader?

Hi,
I want to create an image at runtime and modify it in a Compute Shader. However, none of my changes appear to make it back to the CPU.
Simple example script :

using UnityEngine;

public class ImAnIdiotTests : MonoBehaviour
{
    private int size = 16;
    public ComputeShader fillShader;

    void Start () {
        var tempTex = new Texture2D(size, size,TextureFormat.ARGB32,false,true);

        int[] data = new int[size*size];
        tempTex.SetPixels(new Color[size*size]);
        tempTex.Apply();

        var cB = new ComputeBuffer(size*size,sizeof(int)); // computeBuffers work, so I use it to make sure the ComputeShader itself is working

        Debug.Log(tempTex.GetPixel(0,0)*255); // Values prior to CS

        int kernelIndex = fillShader.FindKernel("CSMain");

        fillShader.SetTexture(kernelIndex,"Result",tempTex);
        fillShader.SetFloat("val",2f); // should be assigned to all pixels in Result/tempTex
        fillShader.SetInt("bufferWidth",size);
        fillShader.SetBuffer(kernelIndex,"buff",cB);
        fillShader.Dispatch(0,size/8,size/8,1); // threadgroups of 8

        cB.GetData(data);

        //tempTex.SetPixel(0, 0, new Color(1f, 0f, 0f, 0f)); // This DOES change the texture

        int l = 0;
        foreach (var color32 in tempTex.GetPixels32())
        {
            Debug.Log(color32 + " " + data[l]); // all should return (2,2,2,2) and 1 if working properly
            l++;
        }
    }

}
#pragma kernel CSMain

RWStructuredBuffer<int> buff;
RWTexture2D<float4> Result;
int bufferWidth;

float val = 1;

[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
    Result[id.xy] = float4(val,val,val,val);
    buff[id.y * bufferWidth + id.x] = 1;
}

The resulting log is nothing but (0,0,0,0) 1, meaning the texture wasn’t set but the buffer was.
What am I doing wrong? I tried it with an imported read/write enabled texture too, same results. None of the tutorials on compute shaders seem to mention anything special, so what am I missing?

Thanks

Making it back to the main memory can be fairly slow. You can copy from the RenderTexture to a Texture2D to get it back to main memory.

1 Like

Why does it need to come back cpu side? You need to save it or something? If it has to come back cpu side it is slow, and might defeat the purpose of doing work on the gpu…

It should go directly into a shader, but I wanted to debug it first. I assumed there was a bug where perhaps everything was fine.
Using RenderTextures and copy via active works great, thank you.

Edit : I assume you’d use Graphics.CopyTexture for Texture2DArrays

If you want to debug them, use RenderDoc. Capture a frame and then go to the appropriate Dispatch call and check the output of the ComputeShader. No need to get them back to CPU side and dump them.

1 Like