Sounds recycle their voices instead of churning through them
Recovering the soundbanks took voice demand per sound from about one zone to about two and a half, and the audio path allocated an OpenAL source for every sound event and destroyed it again on release. Sources are a hard per-context resource - this driver grants 256 - so that churn doubled at exactly the moment it got more expensive. Sources are now generated once and recycled through a free list: measured, three sources generated across twelve thousand acquisitions. The BT tree reached the same conclusion the expensive way, from field logs full of failed acquisitions: raising the source budget is not the fix, because the ceiling also acts as a governor and more voices mixing is real CPU during exactly the busiest moments. Recycling is the fix, and it costs nothing. Two older bugs were sitting underneath, both reproduced against the driver rather than assumed: Releasing a set leaked it. alDeleteSources is atomic - one bad name in the array and nothing at all is deleted. ReleaseSourceSet handed it the whole fixed-size array and then parked the slots at -1, so any partial set, and any double release, leaked every source it held. Sources are now handed back one at a time and slots park at 0, which is never a valid name. A source set began life uninitialised. The constructor set only the count, and the acquire path decided whether a slot was already filled by asking OpenAL about uninitialised stack garbage. Garbage that happened to match a live name meant two sounds silently sharing one source. Pooling would have made that more likely, not less, since it keeps small names in circulation. Recycled sources are scrubbed before parking - stopped, buffer detached, looping, gain, pitch, relative flag, position and velocity reset, and the EFX filter and reverb send dropped. Without that last part a dry cockpit sound inherits the wet send of whatever 3D source held the name before it. Verified: a deliberately dirtied source comes back clean. Builds clean. Runs with memory and handle count flat. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -702,6 +702,19 @@ L4AudioSource::L4AudioSource(
|
||||
AudioSource(stream, entity)
|
||||
{
|
||||
channelSet.count = GetAudioVoiceCount();
|
||||
|
||||
//
|
||||
// sources[] was left uninitialized here, and RequestAudioChannels decides
|
||||
// whether a slot already holds a source by asking alIsSource about it.
|
||||
// Garbage that happened to match a live name meant silently sharing another
|
||||
// source -- a real hazard now that the pool recycles small integer names.
|
||||
// 0 is never a valid AL name.
|
||||
//
|
||||
for (int i = 0; i < (int)(sizeof(channelSet.sources) / sizeof(channelSet.sources[0])); i++)
|
||||
{
|
||||
channelSet.sources[i] = 0;
|
||||
}
|
||||
|
||||
L4AudioSourceX();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user