diff options
author | Chris Robinson <[email protected]> | 2020-03-04 21:15:32 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2020-03-04 23:18:05 -0800 |
commit | 78251fd7e6dc11c63481970be9fa453540951dbd (patch) | |
tree | 63f4497c0438ea3ad1ef2a59b2b9bd68b7c49991 /alc | |
parent | 48b9b541ec55dc5498409fda6f0a0c788ebe234e (diff) |
Fix voices being forced to update without valid properties
When starting a voice, the source ID was set before its first update struct was
provided, creating a small window where a listener or effect slot update could
force a voice to update without it having any valid properties to update with.
Supplying the update struct first would create a different race, where the
mixer could see a voice without a source but with an update struct, causing the
update struct to be 'freed' without being applied.
The fix here is to provide the update struct before setting the source ID, and
change the mixer to ignore update structs for voices without a source ID. This
can pseudo-orphan the updates that get set on a voice just as it stops, leaving
the struct unusable until the voice is used again, or the voice gets deleted
which will clear it. But it allows the update struct to stay in place and get
applied once the voice gets a source ID.
Diffstat (limited to 'alc')
-rw-r--r-- | alc/alu.cpp | 21 |
1 files changed, 7 insertions, 14 deletions
diff --git a/alc/alu.cpp b/alc/alu.cpp index 862ba9a2..ae65fbcb 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -1576,17 +1576,7 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A void CalcSourceParams(ALvoice *voice, ALCcontext *context, bool force) { ALvoiceProps *props{voice->mUpdate.exchange(nullptr, std::memory_order_acq_rel)}; - if(voice->mSourceID.load(std::memory_order_relaxed) == 0) - { - /* Don't update voices that no longer have a source. But make sure any - * update struct it has is returned to the free list. - */ - if UNLIKELY(props) - AtomicReplaceHead(context->mFreeVoiceProps, props); - return; - } - if(!props && !force) - return; + if(!props && !force) return; if(props) { @@ -1723,9 +1713,12 @@ void ProcessParamUpdates(ALCcontext *ctx, const ALeffectslotArray &slots, for(ALeffectslot *slot : slots) force |= CalcEffectSlotParams(slot, sorted_slots, ctx); - auto calc_params = [ctx,force](ALvoice *voice) -> void - { CalcSourceParams(voice, ctx, force); }; - std::for_each(voices.begin(), voices.end(), calc_params); + for(ALvoice *voice : voices) + { + /* Only update voices that have a source. */ + if(voice->mSourceID.load(std::memory_order_relaxed) != 0) + CalcSourceParams(voice, ctx, force); + } } IncrementRef(ctx->mUpdateCount); } |