mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
Savestate: store only live audio queue data (AudioChannel section v3)
FixedSizeQueue::DoState serializes the entire fixed backing store. For the sceAudio channel queues that is 512KB per channel (32768*8 s16 samples), or ~4.6MB of mostly dead bytes in every savestate across the nine channels - the live sample count at any moment is normally a few KB. This addresses the existing TODO in DoState. Add DoStateCompact(), which stores only the live [head, head+count) region and restores it linearized at the front of storage. A wrapped live region is written as its two pieces in pop order; since the POD DoArray path writes raw bytes with no per-element or per-call header, the single linear read on load consumes them identically. The count is validated on load and a bad value fails the load cleanly via p.SetError. AudioChannel bumps its section to v3 to use the compact form; old states still load through the unchanged full-storage path. This shrinks every savestate by several MB uncompressed and cuts the copy/compress cost of each save, including the rewind feature's periodic states.
This commit is contained in:
1 parent
a6e4d691ef
commit
3abb56e7f5
2 files changed
+47
-2
No files matched your search
@@ -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<T>(p, storage_, count_);
|
||||
} else {
|
||||
if (head_ + count_ <= N) {
|
||||
DoArray<T>(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<T>(p, storage_ + head_, firstPart);
|
||||
DoArray<T>(p, storage_, count_ - firstPart);
|
||||
}
|
||||
}
|
||||
p.DoMarker("FixedSizeQueue");
|
||||
}
|
||||
|
||||
private:
|
||||
T *storage_;
|
||||
int head_;
|
||||
|
||||
+10
-2
@@ -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()
|
||||
|
||||
Reference in new issue
Block a user