Repository navigation
Hot Path Audio Span Based Fetch
Reviewed: November 1, 2026 · Source:
b7140848
State: Partial delivery: live SGE descriptor mappings #190 and bounded ADPCM payload mappings #275.
Release availability: Those mapping changes are main only at this review; absent from v0.8.136-0-g458730bf5373 (September 30, 2026).
Current main reuses callback-owned RAM mappings while reading fresh guest-written descriptor values and ADPCM payload words. A general VoiceSpan engine with bulk PCM conversion and SIMD kernels remains research. Mapping reuse must not be described as a cache of descriptor values or permission to reuse stale samples.
| Mechanism | Current state | Boundary |
|---|---|---|
| SGE descriptor RAM mapping | Merged #190 | Reuse mapping, reload descriptor contents on each access |
| ADPCM payload RAM mapping | Merged #275 | Bounded cached word reads; current table base and descriptor observed per word |
| Decoded ADPCM block | Merged #187 | Separate per-voice content cache with fresh-byte comparison |
| Callback-local format decode | Merged #191 | One local CFG_FMT value; see Prepared Voice Controls |
| General VoiceSpan / bulk PCM conversion | Unimplemented research | Must prove all mapping, stream, loop and completion boundaries |
| Format-specific SIMD kernels | Unimplemented research | Separate measured experiment after scalar semantics are isolated |
flowchart LR
A[Next sample or ADPCM word] --> B[Read SGE descriptor through generic physical access]
B --> C[Resolve payload address]
C --> D[Read payload through general access path]
D --> E[Convert / decode]
E --> A
flowchart TD
A[voice_get_samples needs a new block] --> B[mcpx_apu_read_adpcm_block]
B --> C[For each encoded word: read current SGE table base]
C --> D[mcpx_apu_sample_word_address]
D --> E[Reload descriptor through valid cached mapping or fallback]
E --> F[mcpx_apu_sample_read_word]
F --> G{RAM mapping / FlatView / bounds valid?}
G -->|Yes| H[Read current payload word with ldl_le_phys_cached]
G -->|No| I[Try bounded mapping or use ldl_le_phys]
H --> J[Next encoded word]
I --> J
J -->|More| C
J -->|Complete| K[mcpx_apu_adpcm_decode_cached]
K --> L[Bounds-check and emit requested samples]
MCPXAPUSampleReadCache owns an SGE mapping and payload mapping for one voice_get_samples() call. g_auto cleanup destroys both at callback exit. The streaming ADPCM path still copies from the established RAM path; it is not converted into a universal span engine. PCM still uses get_data_ptr() with the descriptor cache and its existing sample-format conversion loop.
mcpx_apu_sge_read_descriptor() admits only a suitable RAM mapping, checks descriptor address and current FlatView identity, and reloads the descriptor word through ldl_le_phys_cached(). It does not cache the page-address value. On an unsuitable or changed mapping it rebuilds or uses ldl_le_phys().
mcpx_apu_sample_read_word() checks the payload range, four-byte footprint and current view. A cold payload mapping is bounded by remaining page bytes, and is avoided for one trailing word. Non-RAM, short or otherwise unsuitable mappings fall back to the ordinary physical read. mcpx_apu_read_adpcm_block() retains the previous per-word observation of the SGE base register and live descriptor. The helper also preserves existing 32-bit payload-address arithmetic.
These are address-translation savings under a limited lifetime. They do not establish that arbitrary guest pointers, PCM page crossings, or mutable voice state are safe to cache indefinitely.
#190 and #275 contain implementation and qualification history. Issue #310 retains adverse Deck Morrowind cadence/tail observations for the accepted mapping stack despite faster component reads. A component-read reduction is not a demonstrated overall game gain. Keep that result visible when comparing future mapping changes; this documentation repair did not run a new campaign.
The broader proposal resolves the largest safe contiguous span and selects one scalar conversion kernel outside the sample loop. This is unimplemented pseudocode:
typedef struct VoiceSpan {
const uint8_t *host_ptr;
hwaddr guest_address;
size_t guest_bytes;
size_t sample_count;
unsigned format;
unsigned channels;
unsigned segment;
} VoiceSpan;flowchart LR
A[Resolve live source and bounded span] --> B[Clamp page / SGE / segment / loop / block / output limits]
B --> C[Select scalar conversion kernel]
C --> D[Convert admitted samples]
D --> E[Advance existing position / completion / notifier state]
E --> A
A span ends before any page/SGE, source buffer, loop, streaming segment, required ADPCM block, requested-output, stride/channel footprint, mapping or notification boundary. It must retain ordinary behavior for MMIO/non-RAM, unsupported interleave and ambiguous ownership. Kernel selection does not own loop/completion policy. SIMD is a later independent experiment.
The ownership window must prove which guest writes remain observable. Simply assuming all mid-block guest writes wait until the next block is an approximation and must be labeled and tested separately.
Start with counters for elements fetched, SGE reads, address translations, span lengths and split/fallback reasons, plus VP/APU and whole-game cost. Introduce scalar spans before changing conversion arithmetic. Compare every PCM format/channel layout, odd strides, noncontiguous SGEs, ADPCM splits, starvation, loops, completion/notifiers, remaps, voice reuse and snapshots. Negative controls must change descriptor and payload bytes at the same address and around boundaries.
Accept a future engine only when output/state contracts pass and matched Release measurements show useful overall cadence, tails or efficiency. If spans are usually tiny or ownership/setup cost dominates, narrow or stop the experiment. Proposed counters and VoiceSpan are not current-main APIs.
DSP tooling guide and navigation updated November 2, 2026 for experimental PR #384, source 8f51d237. Capture/replay usage and limits.
The earlier wiki-wide review was published November 1, 2026. Emulator source: b7140848. Reviewed wiki content: 1d2b671. Current status · Release availability · Publication process.
- Home
- Current status
- Stable versus main
- Implemented mechanisms
- Controls and defaults
- Measured results and limits
- Complete change register
- System
- CPU and vCPU
- Memory and DMA
- Graphics / NV2A
- APU and audio
- Timing and timers
- Platform and I/O
- Hardware observations
- Fidelity boundaries
- Methodology
- PGR2 routes
- Debugging lag / hot paths
- Tools and commands
- DSP capture, replay and fuzzing
- HLE readiness and public XISO proof
- Concurrent DSP shadow and OpenAL proof
- DSP HLE operation inventory
- DSP HLE fix examples and testing
- Development
- Upstream shortlist
- Wiki maintenance
- Research / retired work
- Optimization catalog
- Hot-path shortcuts
- Researched experiments
- Unproven proposal directory
- PR lessons
- September26 snapshot
Repository · PRs · Issues