When the GPU is two frames behind, begin_frame waits for the next
staging buffer's MapAsync. It used to spin on ProcessEvents, holding a
whole core busy for as long as the GPU took. It now calls ProcessEvents,
checks for device loss, then sleeps on a condition variable until the
map callback lands or 1 ms passes.
The map state also carries a generation, so a callback from a request
that shutdown or a rotation already retired can no longer mark the
current buffer mapped or unmapped.
From upstream patchzyy/Wiicompiled 6f14bde (#244, KartPad batch).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wg7mB8ogCWmp9GH19Uc82B
Incomplete primitives no longer emit indices: quads drop a one- or
two-vertex tail and draw a three-vertex tail as a triangle, triangle
lists ignore leftover vertices, and fans or strips under three vertices
emit nothing. Draws with no complete primitive are skipped. Previously an
incomplete quad indexed vertices that belonged to the next merged draw,
or past the end of the buffer.
Merging now stops before the 16-bit index offset would wrap, never folds
triangles into a single-instance line or point draw, and breaks after
GXInvalidateVtxCache or a vertex-format switch, so the next draw uploads
fresh arrays and uses its own format's shader.
From upstream patchzyy/Wiicompiled 6f14bde (#244, KartPad batch).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wg7mB8ogCWmp9GH19Uc82B