From 5cc545f157877d5ae6911c9778a90e9400e3fbd2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 26 Dec 2018 12:25:34 -0800 Subject: More aggressively try to decrement an effect's refcount in-place --- Alc/alu.cpp | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) (limited to 'Alc') diff --git a/Alc/alu.cpp b/Alc/alu.cpp index fec574d8..07ad540d 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -397,27 +397,31 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) state = props->State; props->State = nullptr; + EffectState *oldstate{slot->Params.mEffectState}; + slot->Params.mEffectState = state; - if(state == slot->Params.mEffectState) + /* Manually decrement the old effect state's refcount if it's greater + * than 1. We need to be a bit clever here to avoid the refcount + * reaching 0 since it can't be deleted in the mixer. + */ + ALuint oldval{oldstate->mRef.load(std::memory_order_acquire)}; + while(oldval > 1 && !oldstate->mRef.compare_exchange_weak(oldval, oldval-1, + std::memory_order_acq_rel, std::memory_order_acquire)) { - /* If the effect state is the same as current, we can decrement its - * count safely to remove it from the update object (it can't reach - * 0 refs since the current params also hold a reference). + /* oldval was updated with the current value on failure, so just + * try again. */ - DecrementRef(&state->mRef); } - else + + if(oldval < 2) { - /* Otherwise, replace it and send off the old one with a release + /* Otherwise, if it would be deleted, send it off with a release * event. */ - EffectState *oldstate{slot->Params.mEffectState}; - slot->Params.mEffectState = state; - - auto evt_data = ll_ringbuffer_get_write_vector(context->AsyncEvents).first; - if(LIKELY(evt_data.len > 0)) + auto evt_vec = ll_ringbuffer_get_write_vector(context->AsyncEvents); + if(LIKELY(evt_vec.first.len > 0)) { - AsyncEvent *evt{new (evt_data.buf) AsyncEvent{EventType_ReleaseEffectState}}; + AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_ReleaseEffectState}}; evt->u.mEffectState = oldstate; ll_ringbuffer_write_advance(context->AsyncEvents, 1); context->EventSem.post(); -- cgit v1.2.3