aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Alc/ALu.c15
-rw-r--r--OpenAL32/alAuxEffectSlot.c68
2 files changed, 53 insertions, 30 deletions
diff --git a/Alc/ALu.c b/Alc/ALu.c
index 80a031fc..d2aa381c 100644
--- a/Alc/ALu.c
+++ b/Alc/ALu.c
@@ -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)