From 10cecae4c223150ed9cab9bd2b9325f37502d883 Mon Sep 17 00:00:00 2001 From: AllanCat <0937388@gmail.com> Date: Sat, 7 Mar 2026 01:11:38 +0800 Subject: [PATCH] [XMA] Fixed min output space gating to match Consume() write granularity The decoder gate required a full frame of free blocks (4 mono / 8 stereo + padding) before allowing a decode pass, but Consume() only writes subframe_decode_count blocks per call. Games like TGM Ace with subframe_decode_count=2 on a small ring buffer could never meet the old threshold, causing a permanent decoder stall. --- src/xenia/apu/xma_context_new.cc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/xenia/apu/xma_context_new.cc b/src/xenia/apu/xma_context_new.cc index 1ef7a3192..a085211db 100644 --- a/src/xenia/apu/xma_context_new.cc +++ b/src/xenia/apu/xma_context_new.cc @@ -142,9 +142,17 @@ bool XmaContextNew::Work() { return true; } + // Minimum free blocks needed before attempting a decode. + // Use the number of subframes Consume() will actually write per iteration + // (= subframe_decode_count, clamped to 1) plus any headroom requested by + // output_buffer_padding. Using a full-frame worth of space (the old + // formula) was far too restrictive: games like TGM Ace use + // subframe_decode_count=2 on a small ring buffer and never had 8 free + // blocks available, causing the decoder to permanently stall. + const uint32_t effective_sdc = + std::max(static_cast(1), data.subframe_decode_count); const int32_t minimum_subframe_decode_count = - ((kBytesPerFrameChannel / kOutputBytesPerBlock) << data.is_stereo) + - data.output_buffer_padding; + static_cast(effective_sdc) + data.output_buffer_padding; // We don't have enough space to even make one pass // Waiting for decoder to return more space.