How can I read in the actual elements from an Append Compute Buffer?
I have a Compute Shader in my game that runs every FixedUpdate() call. It has two passes/kernels:
1) clears out an Append buffer by "consuming" every element
2) appends several new elements into said Append buffer.
After running it, I need to read the elements of that Append buffer onto the CPU. I know that the ComputeBuffer
class has a GetData(Array data)
method, but from what I understand it would grab the entire buffer, including data that isn't actually allocated yet. I'd like to only spend bandwidth on actual appended elements, instead of getting the full reserved buffer. Additionally, I don't even know how to find the number of existing elements in the buffer in the first place. So how can I get the number of elements currently in an Append buffer, and how can I read in just those values from the GPU?
Answer by SunnySunshine · Sep 24, 2017 at 05:38 AM
// Reset append buffer count for this dispatch.
appendBuffer.SetCounterValue(0);
shader.SetBuffer(0, "appendBuffer", appendBuffer);
shader.Dispatch(0, 1, 1, 1);
// Buffer to store count in.
// You shouldn't be creating this each frame, but rather create it once
// and then reuse it. Here solely to show its creation.
var countBuffer = new ComputeBuffer(1, sizeof(int), ComputeBufferType.IndirectArguments);
// Copy the count.
ComputeBuffer.CopyCount(appendBuffer, countBuffer, 0);
// Retrieve it into array.
int[] counter = new int[1] { 0 };
countBuffer.GetData(counter);
// Actual count in append buffer.
int count = counter[0]; // <-- This is the answer
// Get the append buffer data.
var data = new WhateverData[count];
appendBuffer.GetData(data);
// Don't do this every frame.
countBuffer.Dispose();
Thank you so much. This is really going to help me on my project where I need to use compute shaders for voxel stuff! And even better - your comments were actually useful! A++ :D
I'm trying to do this but my count is always 0 even though in the compute shader I am appending 1 to the buffer on all threads if that makes sense.
Answer by Summit_Peak · Nov 30, 2015 at 01:00 PM
To read in the actual elements from an Append Compute Buffer (pseudocode):
Assign the appendBuffer:
appendBuffer = new AppendStructuredBuffer<int>(maxAppendBufferN);
Dispatch to append items:
AppendBufferItems();
Next, declare a buffer to retrieve only the actual appended elements:
buffer = new RWStructuredBuffer<int>(appendBuffer.InstanceN);
If you have difficulty retrieving the number of elements in the append buffer, you can use InterlockedAdd() to count the items.
Next, connect buffer to appendBuffer with a pointer:
SetBuffer(kernel_gpuFunction, "buffer ", appendBuffer);
Now, all items in the appendBuffer can be accessed on the gpu using buffer:
Dispatch(kernel_gpuFunction, gpuFunction, appendBuffer.InstanceN);
These appended items can be transfered to the cpu using:
buffer.GetData();
Finally:
ConsumeBufferItems();