aboutsummaryrefslogtreecommitdiffstats
path: root/Alc
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2018-12-26 12:25:34 -0800
committerChris Robinson <[email protected]>2018-12-26 12:25:34 -0800
commit5cc545f157877d5ae6911c9778a90e9400e3fbd2 (patch)
tree13551725174bce1988f39712f1297b8be774a3d6 /Alc
parent38537a35ccc2ad713a31943bb699d013b004d075 (diff)
More aggressively try to decrement an effect's refcount in-place
Diffstat (limited to 'Alc')
-rw-r--r--Alc/alu.cpp30
1 files changed, 17 insertions, 13 deletions
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();