Quick answer: Use the callback overload AsyncGPUReadback.Request(rt, callback) or poll request.done in Update. Never WaitForCompletion in a hot path. Readback once per several frames, not every frame.
You readback a render texture for a screen-color sampler. WaitForCompletion blocks the main thread for ~16ms each frame; FPS halves.
The Symptom
Frame time spikes correlate with readback calls. Profiler shows blocking time inside AsyncGPUReadback.WaitForCompletion.
The Fix
private AsyncGPUReadbackRequest? _req;
void RequestSample()
{
_req = AsyncGPUReadback.Request(myRT, 0, request =>
{
if (request.hasError) return;
var data = request.GetData<byte>();
// process on main thread; safe to touch UnityEngine
UpdateUI(data);
});
}
Callback fires on the main thread when the readback completes (1-3 frames later). No blocking.
Polling Alternative
void Update()
{
if (_req.HasValue && _req.Value.done)
{
var data = _req.Value.GetData<byte>();
UpdateUI(data);
_req = null;
}
}
Poll done; consume when ready. Useful if you need explicit control over when the data is processed.
Frequency Budget
Don’t fire a readback every frame; fire every ~10 frames or on event:
if (Time.frameCount % 10 == 0) RequestSample();
Verifying
Profiler shows AsyncGPUReadback in worker threads, not main. Frame time stable. WaitForCompletion does not appear.
“Callback or poll. Never wait. Frame stays smooth.”
Related Issues
For Niagara CPU/GPU readback, see Niagara readback. For async unobserved, see async exceptions.
Async stays async. No stalls.