I never found an easy way, but the overall approach I used is this convoluted hack:
Use two different AsyncGPUReadbacks, one for the triangle count buffer and the other for the actual triangles
Pass the frame number of the current frame when requesting inside the callback delegate, so that you know “which frame” requested each when you receive them
Do your final operation on results regularly (for example in LateUpdate), but first check that both buffers returned and both buffers originated from the same request frame, so we know they’re “in sync”
It looks something like this:
private ComputeBuffer triangleCountBuffer;
private ComputeBuffer trianglesBuffer;
private int triangleCount;
private GpuTriangle[] triangles;
private bool triangleCountAvailable;
private bool trianglesAvailable;
private int triangleCountRequestFrame;
private int trianglesRequestFrame;
void LateUpdate()
{
Request();
Operate();
}
void Request()
{
// (... etc, prepare your request here)
ComputeBuffer.CopyCount(trianglesBuffer, triangleCountBuffer, 0);
AsyncGPUReadback.Request(triangleCountBuffer, r1 => OnTriangleCountAvailable(r1, Time.frameCount));
AsyncGPUReadback.Request(trianglesBuffer, r2 => OnTrianglesAvailable(r2, Time.frameCount));
}
private void OnTriangleCountAvailable(AsyncGPUReadbackRequest request, int requestFrame)
{
if (request.hasError || // Something wrong happened
!Application.isPlaying) // Callback happened in edit mode afterwards
{
triangleCountAvailable = false;
return;
}
triangleCount = request.GetData<int>()[0];
triangleCountAvailable = true;
triangleCountRequestFrame = requestFrame;
}
private void OnTrianglesAvailable(AsyncGPUReadbackRequest request, int requestFrame)
{
if (request.hasError || // Something wrong happened
!Application.isPlaying) // Callback happened in edit mode afterwards
{
trianglesAvailable = false;
return;
}
var data = request.GetData<GpuTriangle>();
trianglesAvailable = data.Length == triangles.Length;
trianglesRequestFrame = requestFrame;
if (trianglesAvailable)
{
data.CopyTo(triangles);
}
else
{
// Debug.LogWarning("Triangle count mismatch. Grid was likely resized.");
}
}
private void Operate()
{
if (!triangleCountAvailable || !trianglesAvailable)
{
return;
}
if (triangleCountRequestFrame != trianglesRequestFrame)
{
// Debug.LogWarning("Out of sync readbacks, skipping meshification.");
return;
}
// (etc... operate on the data here, you know it's in sync!)
}
Just tried a similar approach today hahaha (I was about to post it when I noticed that AsyncGPUReadback causes memory leaks at least in my case… I’ll try with your approach, who knows xD) but yeah, having two requests seems to be the only workaround right now… anyway, thank you for your time ;D