diff options
-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) |