Swapping Compute Shaders

I am editing some point cloud volume data in Unity, on the GPU.

My issue is that I have to edit my data in multiple passes (applying multiple different compute shaders to the same data). Is it possible to pass the output from one compute shader to another one? You know, stopping the current compute shader, starting another one, and pointing it to the same data in the GPU memory?

How would that be done? We have the ComputeShader.Dispatch to begin with (in unity), which starts one compute shader, and then what? Can I somehow just make multiple ComputeShader objects and then do secondComputeShader.SetBuffer(--existingGPUBuffer--) and then .Dispatch()?
(note: it wouldn’t be necessary or optimal for me to run multiple compute shaders in the same frame, unless there’s no other option)

I am using DX11, with HLSL. My data structure is in a RWStructuredBuffer, which according to MSDN, is synced across the entire GPU – and indeed I can access this StructuredBuffer in my regular shader for display purposes.

Ideally I would be able to define a layering order “CS-A, CS-B, CS-A, CS-C”; if that is at all possible (but not all in the same frame).

Cheers!

[EDIT]

Alright, after Ben’s comment, I’m posting what I’m doing right now:

public List<ComputeShader> computeShaderList;
ComputeBuffer particleBuffer;
struct Particle
{
	public Vector3 position;
	public Vector3 velocity;
};
ComputeShader currentComputeShader; 

void Start () 
{
	Particle[] particleArray = new Particle[particleCount];//remember to initialize for each Particle (position and velocity)
				
	//create new compute buffer instance, and initialize it with your data.
	particleBuffer = new ComputeBuffer(particleCount, 24); // 24 = "stride" = size allocated for each particle, probably in bytes, no idea what happens with this
	particleBuffer.SetData(particleArray);
	//so now we should have all our point data stored on the GPU, right?
				
	foreach(ComputeShader cs in computeShaderList)
	{
		cs.SetBuffer(0, "particleBuffer", particleBuffer);
	}
	material.SetBuffer ("particleBuffer", particleBuffer);//this is for the regular shader
	//and now we have told each of our (compute) shaders to reference that data we have stored on the GPU
}
			
void Update()
{
	switch(currentState)// you don't need to run this each frame
	{
	case ComputeStates.CS_One:
		currentComputeShader =  computeShaderList[0];
		break;
	case ComputeStates.CS_Two:
		currentComputeShader = computeShaderList[1];
		break;
	}
				
	//currentComputeShader.SetFloat(  ...set all your stuff
	
	//Start the current compute shader to work this frame on your particles.
	currentComputeShader.Dispatch(0, threadCount, 1, 1);
}
//note: you also need your OnRender with Graphics.DrawProcedural...

The Unity documentation on compute shaders is lacking, and the exposed ComputeShader object isn’t very transparent. All I can say is that according to the Profiler, there seems to be no performance impact from having a bunch of different compute shaders, and choosing which one of them you want to dispatch at what time.

As per all OpenGL buffers (IDK about D3D, but I’d assume it’s the same), Unity uploads the data when you set it. For Texture2D that would be Apply, for compute buffers it’s SetBuffer. Once the buffer is uploaded to the GPU it will stay there until you either delete the buffer or use SetBuffer again.

When the “data” for a material/shader is “set”, if it’s a pre-uploaded buffer, it gets simply passed a reference, like a pointer, to the data. Just like textures, compute buffers won’t get re-uploaded when they are set on a shader. This is actually true for all buffers, as long as the implementation on the drivers is somewhat sane :wink:

You should be able to freely pass around buffers between materials and shaders without much of an overhead.

That said, I am not familiar with the new OpenGL 4.X api, but I am versed in both OpenGL 3.X and OpenCL, so I shouldn’t be too far from the truth.