diff options
-rw-r--r-- | Alc/ALu.c | 38 | ||||
-rw-r--r-- | OpenAL32/Include/alMain.h | 4 | ||||
-rw-r--r-- | OpenAL32/alAuxEffectSlot.c | 3 | ||||
-rw-r--r-- | OpenAL32/event.c | 7 |
4 files changed, 47 insertions, 5 deletions
@@ -462,12 +462,40 @@ static bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool f slot->Params.AirAbsorptionGainHF = 1.0f; } - /* Swap effect states. No need to play with the ref counts since they - * keep the same number of refs. - */ state = props->State; - props->State = slot->Params.EffectState; - slot->Params.EffectState = state; + + if(state == slot->Params.EffectState) + { + /* 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). + */ + DecrementRef(&state->Ref); + props->State = NULL; + } + else + { + /* Otherwise, replace it and send off the old one with a release + * event. + */ + AsyncEvent evt = ASYNC_EVENT(EventType_ReleaseEffectState); + evt.u.EffectState = slot->Params.EffectState; + + slot->Params.EffectState = state; + props->State = NULL; + + if(LIKELY(ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1) != 0)) + alsem_post(&context->EventSem); + else + { + /* If writing the event failed, the queue was probably full. + * Store the old state in the property object where it can + * eventually be cleaned up sometime later (not ideal, but + * better than blocking or leaking). + */ + props->State = evt.u.EffectState; + } + } ATOMIC_REPLACE_HEAD(struct ALeffectslotProps*, &context->FreeEffectslotProps, props); } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 3a08e8c1..3e328157 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -760,6 +760,9 @@ enum { EventType_Performance = 1<<3, EventType_Deprecated = 1<<4, EventType_Disconnected = 1<<5, + + /* Internal events. */ + EventType_ReleaseEffectState = 65536, }; typedef struct AsyncEvent { @@ -772,6 +775,7 @@ typedef struct AsyncEvent { ALuint param; ALchar msg[1008]; } user; + struct ALeffectState *EffectState; } u; } AsyncEvent; #define ASYNC_EVENT(t) { t, { 0 } } diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index b293b6a5..8141e0f6 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -753,6 +753,9 @@ void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) /* If there was an unused update container, put it back in the * freelist. */ + if(props->State) + ALeffectState_DecRef(props->State); + props->State = NULL; ATOMIC_REPLACE_HEAD(struct ALeffectslotProps*, &context->FreeEffectslotProps, props); } diff --git a/OpenAL32/event.c b/OpenAL32/event.c index c0bf4204..4c9c0be2 100644 --- a/OpenAL32/event.c +++ b/OpenAL32/event.c @@ -6,6 +6,7 @@ #include "AL/alext.h" #include "alMain.h" #include "alError.h" +#include "alAuxEffectSlot.h" #include "ringbuffer.h" @@ -30,6 +31,12 @@ int EventThread(void *arg) quitnow = evt.EnumType == EventType_KillThread; if(quitnow) break; + if(evt.EnumType == EventType_ReleaseEffectState) + { + ALeffectState_DecRef(evt.u.EffectState); + continue; + } + enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire); if(context->EventCb && (enabledevts&evt.EnumType) == evt.EnumType) context->EventCb(evt.u.user.type, evt.u.user.id, evt.u.user.param, |