Use an internal event to more timely release old effect states
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 } }
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user