diff --git a/Common/Data/Collections/FixedSizeQueue.h b/Common/Data/Collections/FixedSizeQueue.h index 68c96e829c..27b267d6de 100644 --- a/Common/Data/Collections/FixedSizeQueue.h +++ b/Common/Data/Collections/FixedSizeQueue.h @@ -161,6 +161,43 @@ public: p.DoMarker("FixedSizeQueue"); } + // Compact serialization: stores only the live [head_, head_+count_) region + // instead of the whole fixed storage. NOT format-compatible with DoState(); + // callers must gate on their own section version. + void DoStateCompact(PointerWrap &p) { + int size = N; + Do(p, size); + if (size != N) { + ERROR_LOG(Log::Common, "Savestate failure: Incompatible queue size."); + p.SetError(p.ERROR_FAILURE); + return; + } + Do(p, count_); + if (count_ < 0 || count_ > N) { + ERROR_LOG(Log::Common, "Savestate failure: Bad compact queue count."); + p.SetError(p.ERROR_FAILURE); + return; + } + if (p.mode == PointerWrap::MODE_READ) { + // Restore linearized: live data starts at the front of storage. + head_ = 0; + tail_ = count_ == N ? 0 : count_; + DoArray(p, storage_, count_); + } else { + if (head_ + count_ <= N) { + DoArray(p, storage_ + head_, count_); + } else { + // Live region wraps; write the two pieces in pop order. Raw + // bytes only (POD DoArray has no per-call header), so the + // single linear read above consumes them identically. + const int firstPart = N - head_; + DoArray(p, storage_ + head_, firstPart); + DoArray(p, storage_, count_ - firstPart); + } + } + p.DoMarker("FixedSizeQueue"); + } + private: T *storage_; int head_; diff --git a/Core/HLE/sceAudio.cpp b/Core/HLE/sceAudio.cpp index abf3b8e7fb..072b430872 100644 --- a/Core/HLE/sceAudio.cpp +++ b/Core/HLE/sceAudio.cpp @@ -44,7 +44,7 @@ AudioChannel g_audioChans[PSP_AUDIO_CHANNEL_MAX + 1]; void AudioChannel::DoState(PointerWrap &p) { - auto s = p.Section("AudioChannel", 1, 2); + auto s = p.Section("AudioChannel", 1, 3); if (!s) return; @@ -59,7 +59,15 @@ void AudioChannel::DoState(PointerWrap &p) Do(p, defaultRoutingMode); Do(p, defaultRoutingVolMode); } - chanSampleQueues[index].DoState(p); + if (s >= 3) { + // v3: compact queue form — only the live samples, not the whole 512KB + // fixed storage per channel. Cuts ~4.6MB of dead bytes from every + // savestate. Old savestates (s < 3) still load through the + // full-storage path below. + chanSampleQueues[index].DoStateCompact(p); + } else { + chanSampleQueues[index].DoState(p); + } } void AudioChannel::reset()