Skip to content

Savestate: store only live audio queue data (AudioChannel section v3) - #21989

Open
Arkadyzja wants to merge 1 commit into
hrydgard:masterfrom
Arkadyzja:savestate-compact-audio-queues
Open

Savestate: store only live audio queue data (AudioChannel section v3)#21989
Arkadyzja wants to merge 1 commit into
hrydgard:masterfrom
Arkadyzja:savestate-compact-audio-queues

Conversation

@Arkadyzja

Copy link
Copy Markdown

What

Adds FixedSizeQueue::DoStateCompact() and bumps the AudioChannel section to v3 to use it. This addresses the existing TODO in FixedSizeQueue::DoState:

// TODO: This is quite wasteful, could just store the actual data. Would be slightly more complex though.

Why

DoState serializes the entire fixed backing store. Each sceAudio channel queue is FixedSizeQueue<s16, 32768 * 8> = 512KB, and there are nine of them — ~4.6MB of almost entirely dead bytes in every savestate, while the live sample count at any moment is typically a few KB. That's wasted memcpy, wasted compression input, and wasted size in every save — manual saves, save slots, and the rewind feature's periodic in-memory states alike.

How

DoStateCompact() stores only the live [head, head+count) region:

  • Save: if the live region wraps around the end of storage, it is written as its two pieces in pop order. The POD DoArray path writes raw bytes with no per-element or per-call header, so the concatenation is byte-identical to a single linear write of the logical queue contents.
  • Load: the data is restored linearized at the front of storage (head = 0, tail = count % N), which is an equivalent queue state.
  • The count is validated on load; a bad value fails the load cleanly via p.SetError() instead of desyncing the stream.

The old full-storage DoState() is untouched; the two formats are not interchangeable, so callers opt in via their own section version — which AudioChannel (the only caller changed here) does with v3.

Compatibility

  • Old states (v2/v1 AudioChannel sections) load exactly as before through the full-storage path.
  • States written by this build won't load on older builds — standard section-bump consequence.

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.
@hrydgard hrydgard added this to the v1.21 milestone Jul 27, 2026
@hrydgard hrydgard added Audio Code Cleanup Cleanup to make future work easier. Needs to be done sometimes. labels Jul 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Audio Code Cleanup Cleanup to make future work easier. Needs to be done sometimes.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants