Root cause: CaptureFrame returned null and was assigned to CapturedFrame,
overwriting the data that ReadCapturedBuffer had just set at the start
of the same frame.
Fix: CaptureFrame is now void — only records GPU copy commands.
ReadCapturedBuffer runs at start of next frame (after WaitFrame/fence)
and sets CapturedFrame with actual pixel data.
Program.cs reads CapturedFrame after RenderWorld — now contains data
from the previous frame's GPU copy.