AsyncGPUReadback
AsyncGPUReadback in Unity is a feature that allows developers to copy data, such as a specific pixel's color, from textures on the GPU to code on the CPU. This function is similar to Texture2D.GetPixels
except it does not block tasks on the main thread as it runs asynchronously.
By performing the data transfer asynchronously, Unity ensures that the process does not negatively affect the application's frame rate and overall performance. AsyncGPUReadback helps developers avoid stalling the rendering pipeline, as the data transfer occurs in the background, parallel to the main thread.
Common use cases for AsyncGPUReadback include generating CPU-side data based on the rendered output, such as creating a texture mipmap chain, implementing custom post-processing effects, or analyzing rendered frames for AI and computer vision purposes.
Differences between Unity AsyncGpuReadback and VRCAsyncGpuReadback
VRChat's implementation of AsyncGpuReadback employs a wrapper that calls the Unity functions. This wrapper uses a different interface. The differences are as follows:
- Rather than calling AsyncGpuReadback, you need to use VRCAsyncGpuReadback.
- Rather than providing
Action<AsyncGPUReadbackRequest> callback
, you provide an UdonBehaviour, and then that UdonBehaviour will receiveOnAsyncGpuReadbackComplete
when the readback is complete. - Rather than using
GetData
on the completed readback, you need to useTryGetData
.
See Unity's documentation on this feature for other shared details:
Using VRCAsyncGpuReadback
When using VRCAsyncGpuReadback, there are 4 main steps that you need to follow:
- Set up an array of data to be used.
- Make the AsyncGpuReadback request
- Receive the message when the request is complete
- Get the data out of the request
Udon Node Graph Example
UdonSharp Example
using UdonSharp;
using UnityEngine;
using VRC.SDK3.Rendering;
using VRC.Udon.Common.Interfaces;
public class AGPURB : UdonSharpBehaviour
{
public Texture texture;
void Start()
{
VRCAsyncGPUReadback.Request(texture, 0, (IUdonEventReceiver)this);
}
public void OnAsyncGpuReadbackComplete(VRCAsyncGPUReadbackRequest request)
{
if (request.hasError)
{
Debug.LogError("GPU readback error!");
return;
}
else
{
var px = new Color32[texture.width * texture.height];
Debug.Log("GPU readback success: " + request.TryGetData(px));
Debug.Log("GPU readback data: " + px[0]);
}
}
}