From 80ed563475e895e04d2013d27418c69cbeb74837 Mon Sep 17 00:00:00 2001 From: Alban Gicquel Date: Sun, 11 Oct 2026 16:08:26 -0400 Subject: [PATCH] winit-host: flush queued writes when the frame cannot be acquired A Timeout or Occluded surface returned before any submit, leaving every write_buffer of the frame pending in the queue. While a window stays hidden or occluded that grows without bound (about 50 MB/s in a sprite scene: one staging buffer per write). Submitting an empty batch flushes them; Outdated/Lost do the same before reconfiguring. --- native/rust/winit-host/src/graphics.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/native/rust/winit-host/src/graphics.rs b/native/rust/winit-host/src/graphics.rs index 3b8efe8a..18b06b59 100644 --- a/native/rust/winit-host/src/graphics.rs +++ b/native/rust/winit-host/src/graphics.rs @@ -1930,12 +1930,18 @@ impl Graphics { CurrentSurfaceTexture::Success(frame) => (Some(frame), false), CurrentSurfaceTexture::Suboptimal(frame) => (Some(frame), true), CurrentSurfaceTexture::Timeout | CurrentSurfaceTexture::Occluded => { - return Ok(false) + // The frame's buffer writes are already queued. Submitting + // nothing still flushes them; returning without a submit + // leaves every write's staging buffer pending, and a hidden + // or occluded window then grows without bound. + self.queue.submit(std::iter::empty()); + return Ok(false); } CurrentSurfaceTexture::Outdated | CurrentSurfaceTexture::Lost => { // Both mean the surface no longer matches the window. Rebuilt // here and drawn next frame, which is one dropped frame rather - // than a dead window. + // than a dead window. The queued writes are flushed as above. + self.queue.submit(std::iter::empty()); if let Some(surface) = &self.surface { surface.configure(&self.device, &self.config); }