diff options
author | Chris Robinson <[email protected]> | 2016-08-25 04:57:58 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2016-08-25 04:57:58 -0700 |
commit | 4e4e597fa54cc3498ae28bea9c2684e1fee05389 (patch) | |
tree | 16757d48abbc6f70ae37bd6903811dd465ff8447 | |
parent | 0fbf34fb4592aa29fcbf4e725719cb253e7d3a78 (diff) |
Track all references for effect states
This allows us to not have to play around with trying to avoid duplicate state
pointers, since the reference count will ensure they're deleted as appropriate.
The only caveat is that the mixer is not allowed to decrement references, since
that can cause the object to be freed (which the mixer code is not allowed to
do).
-rw-r--r-- | Alc/ALu.c | 15 | ||||
-rw-r--r-- | OpenAL32/alAuxEffectSlot.c | 68 |
2 files changed, 53 insertions, 30 deletions
@@ -319,18 +319,15 @@ static void CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) slot->Params.DecayTime = 0.0f; slot->Params.AirAbsorptionGainHF = 1.0f; } - state = ATOMIC_EXCHANGE(ALeffectState*, &props->State, NULL, almemory_order_relaxed); - /* If the state object is changed, exchange it with the current one so it - * remains in the freelist and isn't leaked. + /* Swap effect states. No need to play with the ref counts since they keep + * the same number of refs. */ - if(state != slot->Params.EffectState) - { - ATOMIC_STORE(&props->State, slot->Params.EffectState, almemory_order_relaxed); - slot->Params.EffectState = state; - } + state = ATOMIC_EXCHANGE(ALeffectState*, &props->State, slot->Params.EffectState, + almemory_order_relaxed); + slot->Params.EffectState = state; - V(slot->Params.EffectState,update)(device, slot, &props->Props); + V(state,update)(device, slot, &props->Props); /* WARNING: A livelock is theoretically possible if another thread keeps * changing the freelist head without giving this a chance to actually swap diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 1a20952b..85be5c6d 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -44,7 +44,6 @@ extern inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint static void RemoveEffectSlotList(ALCcontext *Context, const ALeffectslot *slot); - static UIntMap EffectStateFactoryMap; static inline ALeffectStateFactory *getFactoryByType(ALenum type) { @@ -54,6 +53,9 @@ static inline ALeffectStateFactory *getFactoryByType(ALenum type) return NULL; } +static void ALeffectState_IncRef(ALeffectState *state); +static void ALeffectState_DecRef(ALeffectState *state); + AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots) { @@ -86,7 +88,9 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo if(err != AL_NO_ERROR) { FreeThunkEntry(slot->id); - DELETE_OBJ(slot->Params.EffectState); + ALeffectState_DecRef(slot->Effect.State); + if(slot->Params.EffectState) + ALeffectState_DecRef(slot->Params.EffectState); al_free(slot); alDeleteAuxiliaryEffectSlots(cur, effectslots); @@ -469,11 +473,12 @@ void DeinitEffectFactoryMap(void) ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *effect) { ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL); - ALeffectStateFactory *factory; + struct ALeffectslotProps *props; + ALeffectState *State; if(newtype != EffectSlot->Effect.Type) { - ALeffectState *State; + ALeffectStateFactory *factory; FPUCtl oldMode; factory = getFactoryByType(newtype); @@ -493,7 +498,7 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e { almtx_unlock(&Device->BackendLock); RestoreFPUMode(&oldMode); - DELETE_OBJ(State); + ALeffectState_DecRef(State); return AL_OUT_OF_MEMORY; } almtx_unlock(&Device->BackendLock); @@ -510,6 +515,7 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e EffectSlot->Effect.Props = effect->Props; } + ALeffectState_DecRef(EffectSlot->Effect.State); EffectSlot->Effect.State = State; UpdateEffectSlotProps(EffectSlot); } @@ -519,10 +525,35 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e UpdateEffectSlotProps(EffectSlot); } + /* Remove state references from old effect slot property updates. */ + props = ATOMIC_LOAD(&EffectSlot->FreeList); + while(props) + { + State = ATOMIC_EXCHANGE(ALeffectState*, &props->State, NULL, almemory_order_relaxed); + if(State) ALeffectState_DecRef(State); + ATOMIC_LOAD(&props->next, almemory_order_relaxed); + } + return AL_NO_ERROR; } +static void ALeffectState_IncRef(ALeffectState *state) +{ + uint ref; + ref = IncrementRef(&state->Ref); + TRACEREF("%p increasing refcount to %u\n", state, ref); +} + +static void ALeffectState_DecRef(ALeffectState *state) +{ + uint ref; + ref = DecrementRef(&state->Ref); + TRACEREF("%p decreasing refcount to %u\n", state, ref); + if(ref == 0) DELETE_OBJ(state); +} + + void ALeffectState_Construct(ALeffectState *state) { InitRef(&state->Ref, 1); @@ -555,6 +586,7 @@ ALenum InitEffectSlot(ALeffectslot *slot) slot->Params.Gain = 1.0f; slot->Params.AuxSendAuto = AL_TRUE; + ALeffectState_IncRef(slot->Effect.State); slot->Params.EffectState = slot->Effect.State; slot->Params.RoomRolloff = 0.0f; slot->Params.DecayTime = 0.0f; @@ -575,8 +607,7 @@ void DeinitEffectSlot(ALeffectslot *slot) if(props) { state = ATOMIC_LOAD(&props->State, almemory_order_relaxed); - if(state != slot->Params.EffectState) - DELETE_OBJ(state); + if(state) ALeffectState_DecRef(state); TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props); al_free(props); } @@ -586,14 +617,16 @@ void DeinitEffectSlot(ALeffectslot *slot) struct ALeffectslotProps *next; state = ATOMIC_LOAD(&props->State, almemory_order_relaxed); next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); - DELETE_OBJ(state); + if(state) ALeffectState_DecRef(state); al_free(props); props = next; ++count; } TRACE("Freed "SZFMT" AuxiliaryEffectSlot property object%s\n", count, (count==1)?"":"s"); - DELETE_OBJ(slot->Params.EffectState); + ALeffectState_DecRef(slot->Effect.State); + if(slot->Params.EffectState) + ALeffectState_DecRef(slot->Params.EffectState); } void UpdateEffectSlotProps(ALeffectslot *slot) @@ -602,17 +635,7 @@ void UpdateEffectSlotProps(ALeffectslot *slot) ALeffectState *oldstate; props = ATOMIC_EXCHANGE(struct ALeffectslotProps*, &slot->Update, NULL); - if(props) - { - /* If there was an unapplied update, check if its state object is the - * same as the current in-use one, or the one that will be set. If - * neither, delete it. - */ - oldstate = ATOMIC_EXCHANGE(ALeffectState*, &props->State, NULL, almemory_order_relaxed); - if(oldstate != slot->Params.EffectState && oldstate != slot->Effect.State) - DELETE_OBJ(oldstate); - } - else + if(!props) { /* Get an unused property container, or allocate a new one as needed. */ props = ATOMIC_LOAD(&slot->FreeList, almemory_order_relaxed); @@ -638,6 +661,8 @@ void UpdateEffectSlotProps(ALeffectslot *slot) /* Swap out any stale effect state object there may be in the container, to * delete it. */ + if(slot->Effect.State) + ALeffectState_IncRef(slot->Effect.State); oldstate = ATOMIC_EXCHANGE(ALeffectState*, &props->State, slot->Effect.State, almemory_order_relaxed); @@ -656,7 +681,8 @@ void UpdateEffectSlotProps(ALeffectslot *slot) &slot->FreeList, &first, props) == 0); } - DELETE_OBJ(oldstate); + if(oldstate) + ALeffectState_DecRef(oldstate); } ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context) |