From ced9e97c4a2127b5c0e756f4844fbc411065a2fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Kozlovsk=C3=BD?= <100806068+MatejKozlovsky@users.noreply.github.com> Date: Sat, 10 Oct 2026 19:05:30 +0200 Subject: [PATCH] GPU: log why the GPU compositor declined a frame before the CPU renders it, instead of falling back silently (#640) --- crates/gpu/src/lib.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/crates/gpu/src/lib.rs b/crates/gpu/src/lib.rs index 8879ab86..4d3f6c77 100644 --- a/crates/gpu/src/lib.rs +++ b/crates/gpu/src/lib.rs @@ -287,6 +287,17 @@ impl Gpu { } } + /// Why a frame was not rendered (best effort: device health, else size / support). + fn decline_reason(&self) -> String { + match self.ctx.check_health() { + Err(e) => format!("device failure / out of memory: {e}"), + Ok(()) => format!( + "the GPU compositor did not handle the frame (unsupported content, a frame over the {} px texture limit, or an allocation failed)", + self.ctx.max_dim + ), + } + } + /// Wait for submitted GPU work with the readback deadline (benchmarks). pub fn wait(&self) { let _ = self.ctx.poll_readbacks(wgpu::PollType::Wait { submission_index: None, timeout: Some(crate::readback::TIMEOUT) }); @@ -299,7 +310,13 @@ impl Accelerator for Gpu { } fn comp_frame(&self, r: &Renderer, comp: ItemId, t: Tick) -> Option { - self.render(r, comp, t) + let img = self.render(r, comp, t); + if img.is_none() { + // The caller renders the frame on the CPU; say so and why, or an export that falls + // back frame after frame (a nested comp the GPU declines) is only mysteriously slow. + log::warn!(target: "effectcraft_gpu", "GPU declined the frame at {:.3} s, the CPU renders it: {}", t.seconds(), self.decline_reason()); + } + img } fn supports_effect(&self, id: &str) -> bool {