aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2016-08-25 04:57:58 -0700
committerChris Robinson <[email protected]>2016-08-25 04:57:58 -0700
commit4e4e597fa54cc3498ae28bea9c2684e1fee05389 (patch)
tree16757d48abbc6f70ae37bd6903811dd465ff8447
parent0fbf34fb4592aa29fcbf4e725719cb253e7d3a78 (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.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)