[Fix] (MG_Backend/DirectVulkan): fence-backed GL sync objects and per-frame descriptor rewind

- Track every graphics-queue submission with a real fence: pooled fences
  for mid-frame flushes, the frame slot's fence for Present and readback.
  Completion advances a submit counter via vkGetFenceStatus polls,
  slot-fence waits, and device-idle points, and raises the buffer-manager
  serial floor from the frame serial each submission carried.
- GL sync objects now capture the submission index that will carry the
  commands recorded so far; ClientWaitSync honors
  GL_SYNC_FLUSH_COMMANDS_BIT with a mid-frame submit (gated on the index
  still being unsubmitted so poll loops cannot split the render pass), and
  blocking waits flush then vkWaitForFences with the caller timeout.
- FlushPendingCommands retires the submitted command buffer and restarts
  recording on a fresh one; retired buffers are freed once the slot fence
  is next waited, so an executing buffer is never reset.
- Rewind descriptor-set cursors exactly once per frame in Present (after
  the slot-fence wait), plus after the synchronous readback drain,
  replacing the ten lazy per-draw-path rewinds.

Verified: host tests 168/168, trace-replay 70/70.
This commit is contained in:
2026-07-10 10:55:10 +00:00
parent 7b00255b11
commit eb090c6170
7 changed files with 436 additions and 58 deletions
@@ -75,6 +75,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void BeginFrame(Uint32 frameIndex);
// All previously submitted GPU work has completed (vkDeviceWaitIdle).
void NotifyDeviceIdle();
// A frame slot's submission fence has been waited: every serial up to
// and including `serial` is complete. Raises the completed floor so
// GetCompletedSerial reflects real fence progress instead of only the
// frameSerial-minus-frameCount inference.
void NotifyFrameSerialComplete(Uint64 serial);
void SetCopyCommandProvider(IBufferCopyCommandProvider* provider);
Bool UploadTransient(BufferKind kind, Uint32 frameIndex, const void* data, VkDeviceSize size,