From ade7e610bb2ea7da1cc18a7940285d21289a4e83 Mon Sep 17 00:00:00 2001 From: "Herman S." <429230+has207@users.noreply.github.com> Date: Mon, 6 Apr 2026 09:06:53 +0900 Subject: [PATCH] [XMA] Fix stall detection false positive in Work loop Stall detection was triggering during multi-pass subframe consumption (e.g. stereo with subframe_decode_count < total subframes), breaking audio looping in games like Tomb Raider. Now only detects a stall when no subframes were pending, so Consume-only iterations aren't mistaken for no-progress cycles. Fixes Halo 4 without regressing Tomb Raider. --- src/xenia/apu/xma_context_new.cc | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/xenia/apu/xma_context_new.cc b/src/xenia/apu/xma_context_new.cc index 253206bff..e43fc50d0 100644 --- a/src/xenia/apu/xma_context_new.cc +++ b/src/xenia/apu/xma_context_new.cc @@ -176,6 +176,9 @@ bool XmaContextNew::Work() { data.output_buffer_valid, data.subframe_decode_count, data.output_buffer_padding); + const uint32_t pre_decode_offset = data.input_buffer_read_offset; + const uint8_t pre_remaining_subframes = current_frame_remaining_subframes_; + Decode(&data); Consume(&output_rb, &data); @@ -185,6 +188,21 @@ bool XmaContextNew::Work() { id(), data.IsAnyInputBufferValid(), data.error_status); break; } + + // If Decode didn't advance the read offset and produced no new frame, + // we can't make progress. Break to avoid spinning. + // Only check when there were no pending subframes — if we entered this + // iteration with subframes remaining, Decode() intentionally skipped + // (offset unchanged) while Consume() drained the frame. + if (pre_remaining_subframes == 0 && + data.input_buffer_read_offset == pre_decode_offset && + current_frame_remaining_subframes_ == 0) { + XELOGAPU( + "XmaContext {}: Decode stalled at offset {} (no progress), " + "waiting for next buffer", + id(), pre_decode_offset); + break; + } } data.output_buffer_write_offset =