Use a lockless method for updating listener and context properties
This uses a separate container to provide the relevant properties to the internal update method, using atomic pointer swaps. A free-list is used to avoid having too many individual containers. This allows the mixer to update the internal listener properties without requiring the lock to protect against async updates. It also allows concurrent read access to the user-facing property values, even the multi-value ones (e.g. the vectors).
This commit is contained in:
parent
21bc0f5ef8
commit
186b54aa3d
35
Alc/ALc.c
35
Alc/ALc.c
@ -2064,7 +2064,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
|
||||
{
|
||||
ALsizei pos;
|
||||
|
||||
ATOMIC_STORE(&context->UpdateSources, AL_FALSE);
|
||||
LockUIntMapRead(&context->EffectSlotMap);
|
||||
for(pos = 0;pos < context->EffectSlotMap.size;pos++)
|
||||
{
|
||||
@ -2272,11 +2271,16 @@ static ALCboolean VerifyDevice(ALCdevice **device)
|
||||
static ALvoid InitContext(ALCcontext *Context)
|
||||
{
|
||||
ALlistener *listener = Context->Listener;
|
||||
|
||||
//Initialise listener
|
||||
listener->Gain = 1.0f;
|
||||
listener->MetersPerUnit = 1.0f;
|
||||
aluVectorSet(&listener->Position, 0.0f, 0.0f, 0.0f, 1.0f);
|
||||
aluVectorSet(&listener->Velocity, 0.0f, 0.0f, 0.0f, 0.0f);
|
||||
listener->Position[0] = 0.0f;
|
||||
listener->Position[1] = 0.0f;
|
||||
listener->Position[2] = 0.0f;
|
||||
listener->Velocity[0] = 0.0f;
|
||||
listener->Velocity[1] = 0.0f;
|
||||
listener->Velocity[2] = 0.0f;
|
||||
listener->Forward[0] = 0.0f;
|
||||
listener->Forward[1] = 0.0f;
|
||||
listener->Forward[2] = -1.0f;
|
||||
@ -2296,9 +2300,12 @@ static ALvoid InitContext(ALCcontext *Context)
|
||||
listener->Params.DopplerFactor = 1.0f;
|
||||
listener->Params.SpeedOfSound = SPEEDOFSOUNDMETRESPERSEC;
|
||||
|
||||
ATOMIC_INIT(&listener->Update, NULL);
|
||||
ATOMIC_INIT(&listener->FreeList, NULL);
|
||||
|
||||
//Validate Context
|
||||
RWLockInit(&Context->PropLock);
|
||||
ATOMIC_INIT(&Context->LastError, AL_NO_ERROR);
|
||||
ATOMIC_INIT(&Context->UpdateSources, AL_FALSE);
|
||||
InitUIntMap(&Context->SourceMap, Context->Device->MaxNoOfSources);
|
||||
InitUIntMap(&Context->EffectSlotMap, Context->Device->AuxiliaryEffectSlotMax);
|
||||
|
||||
@ -2321,6 +2328,10 @@ static ALvoid InitContext(ALCcontext *Context)
|
||||
*/
|
||||
static void FreeContext(ALCcontext *context)
|
||||
{
|
||||
ALlistener *listener = context->Listener;
|
||||
struct ALlistenerProps *lprops;
|
||||
size_t count;
|
||||
|
||||
TRACE("%p\n", context);
|
||||
|
||||
if(context->SourceMap.size > 0)
|
||||
@ -2344,6 +2355,22 @@ static void FreeContext(ALCcontext *context)
|
||||
|
||||
VECTOR_DEINIT(context->ActiveAuxSlots);
|
||||
|
||||
if((lprops=ATOMIC_LOAD(&listener->Update, almemory_order_acquire)) != NULL)
|
||||
{
|
||||
TRACE("Freed unapplied listener update %p\n", lprops);
|
||||
al_free(lprops);
|
||||
}
|
||||
count = 0;
|
||||
lprops = ATOMIC_LOAD(&listener->FreeList, almemory_order_consume);
|
||||
while(lprops)
|
||||
{
|
||||
struct ALlistenerProps *next = ATOMIC_LOAD(&lprops->next, almemory_order_consume);
|
||||
al_free(lprops);
|
||||
lprops = next;
|
||||
++count;
|
||||
}
|
||||
TRACE("Freed "SZFMT" listener property object%s\n", count, (count==1)?"":"s");
|
||||
|
||||
ALCdevice_DecRef(context->Device);
|
||||
context->Device = NULL;
|
||||
|
||||
|
58
Alc/ALu.c
58
Alc/ALu.c
@ -266,19 +266,25 @@ static ALboolean BsincPrepare(const ALuint increment, BsincState *state)
|
||||
}
|
||||
|
||||
|
||||
static ALvoid CalcListenerParams(ALCcontext *Context)
|
||||
static ALboolean CalcListenerParams(ALCcontext *Context)
|
||||
{
|
||||
ALlistener *Listener = Context->Listener;
|
||||
ALdouble N[3], V[3], U[3], P[3];
|
||||
struct ALlistenerProps *first;
|
||||
struct ALlistenerProps *props;
|
||||
aluVector vel;
|
||||
|
||||
props = ATOMIC_EXCHANGE(struct ALlistenerProps*, &Listener->Update, NULL, almemory_order_acq_rel);
|
||||
if(!props) return AL_FALSE;
|
||||
|
||||
/* AT then UP */
|
||||
N[0] = Listener->Forward[0];
|
||||
N[1] = Listener->Forward[1];
|
||||
N[2] = Listener->Forward[2];
|
||||
N[0] = ATOMIC_LOAD(&props->Forward[0], almemory_order_relaxed);
|
||||
N[1] = ATOMIC_LOAD(&props->Forward[1], almemory_order_relaxed);
|
||||
N[2] = ATOMIC_LOAD(&props->Forward[2], almemory_order_relaxed);
|
||||
aluNormalized(N);
|
||||
V[0] = Listener->Up[0];
|
||||
V[1] = Listener->Up[1];
|
||||
V[2] = Listener->Up[2];
|
||||
V[0] = ATOMIC_LOAD(&props->Up[0], almemory_order_relaxed);
|
||||
V[1] = ATOMIC_LOAD(&props->Up[1], almemory_order_relaxed);
|
||||
V[2] = ATOMIC_LOAD(&props->Up[2], almemory_order_relaxed);
|
||||
aluNormalized(V);
|
||||
/* Build and normalize right-vector */
|
||||
aluCrossproductd(N, V, U);
|
||||
@ -291,19 +297,37 @@ static ALvoid CalcListenerParams(ALCcontext *Context)
|
||||
0.0, 0.0, 0.0, 1.0
|
||||
);
|
||||
|
||||
P[0] = Listener->Position.v[0];
|
||||
P[1] = Listener->Position.v[1];
|
||||
P[2] = Listener->Position.v[2];
|
||||
P[0] = ATOMIC_LOAD(&props->Position[0], almemory_order_relaxed);
|
||||
P[1] = ATOMIC_LOAD(&props->Position[1], almemory_order_relaxed);
|
||||
P[2] = ATOMIC_LOAD(&props->Position[2], almemory_order_relaxed);
|
||||
aluMatrixdDouble3(P, 1.0, &Listener->Params.Matrix);
|
||||
aluMatrixdSetRow(&Listener->Params.Matrix, 3, -P[0], -P[1], -P[2], 1.0f);
|
||||
|
||||
Listener->Params.Velocity = aluMatrixdVector(&Listener->Params.Matrix, &Listener->Velocity);
|
||||
aluVectorSet(&vel, ATOMIC_LOAD(&props->Velocity[0], almemory_order_relaxed),
|
||||
ATOMIC_LOAD(&props->Velocity[1], almemory_order_relaxed),
|
||||
ATOMIC_LOAD(&props->Velocity[2], almemory_order_relaxed),
|
||||
0.0f);
|
||||
Listener->Params.Velocity = aluMatrixdVector(&Listener->Params.Matrix, &vel);
|
||||
|
||||
Listener->Params.Gain = Listener->Gain;
|
||||
Listener->Params.MetersPerUnit = Listener->MetersPerUnit;
|
||||
Listener->Params.Gain = ATOMIC_LOAD(&props->Gain, almemory_order_relaxed);
|
||||
Listener->Params.MetersPerUnit = ATOMIC_LOAD(&props->MetersPerUnit, almemory_order_relaxed);
|
||||
|
||||
Listener->Params.DopplerFactor = Context->DopplerFactor;
|
||||
Listener->Params.SpeedOfSound = Context->SpeedOfSound * Context->DopplerVelocity;
|
||||
Listener->Params.DopplerFactor = ATOMIC_LOAD(&props->DopplerFactor, almemory_order_relaxed);
|
||||
Listener->Params.SpeedOfSound = ATOMIC_LOAD(&props->SpeedOfSound, almemory_order_relaxed) *
|
||||
ATOMIC_LOAD(&props->DopplerVelocity, almemory_order_relaxed);
|
||||
|
||||
/* WARNING: A livelock is theoretically possible if another thread keeps
|
||||
* changing the freelist head without giving this a chance to actually swap
|
||||
* in the old container (practically impossible with this little code,
|
||||
* but...).
|
||||
*/
|
||||
first = ATOMIC_LOAD(&Listener->FreeList);
|
||||
do {
|
||||
ATOMIC_STORE(&props->next, first, almemory_order_relaxed);
|
||||
} while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALlistenerProps*,
|
||||
&Listener->FreeList, &first, props) == 0);
|
||||
|
||||
return AL_TRUE;
|
||||
}
|
||||
|
||||
ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer *ALBuffer, const ALCcontext *ALContext)
|
||||
@ -1223,10 +1247,8 @@ void UpdateContextSources(ALCcontext *ctx)
|
||||
ALvoice *voice, *voice_end;
|
||||
ALsource *source;
|
||||
|
||||
if(ATOMIC_EXCHANGE(ALenum, &ctx->UpdateSources, AL_FALSE))
|
||||
if(CalcListenerParams(ctx))
|
||||
{
|
||||
CalcListenerParams(ctx);
|
||||
|
||||
voice = ctx->Voices;
|
||||
voice_end = voice + ctx->VoiceCount;
|
||||
for(;voice != voice_end;++voice)
|
||||
|
@ -8,14 +8,38 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ALlistenerProps {
|
||||
ATOMIC(ALfloat) Position[3];
|
||||
ATOMIC(ALfloat) Velocity[3];
|
||||
ATOMIC(ALfloat) Forward[3];
|
||||
ATOMIC(ALfloat) Up[3];
|
||||
ATOMIC(ALfloat) Gain;
|
||||
ATOMIC(ALfloat) MetersPerUnit;
|
||||
|
||||
ATOMIC(ALfloat) DopplerFactor;
|
||||
ATOMIC(ALfloat) DopplerVelocity;
|
||||
ATOMIC(ALfloat) SpeedOfSound;
|
||||
|
||||
ATOMIC(struct ALlistenerProps*) next;
|
||||
};
|
||||
|
||||
typedef struct ALlistener {
|
||||
aluVector Position;
|
||||
aluVector Velocity;
|
||||
volatile ALfloat Position[3];
|
||||
volatile ALfloat Velocity[3];
|
||||
volatile ALfloat Forward[3];
|
||||
volatile ALfloat Up[3];
|
||||
volatile ALfloat Gain;
|
||||
volatile ALfloat MetersPerUnit;
|
||||
|
||||
/* Pointer to the most recent property values that are awaiting an update.
|
||||
*/
|
||||
ATOMIC(struct ALlistenerProps*) Update;
|
||||
|
||||
/* A linked list of unused property containers, free to use for future
|
||||
* updates.
|
||||
*/
|
||||
ATOMIC(struct ALlistenerProps*) FreeList;
|
||||
|
||||
struct {
|
||||
aluMatrixd Matrix;
|
||||
aluVector Velocity;
|
||||
@ -28,6 +52,8 @@ typedef struct ALlistener {
|
||||
} Params;
|
||||
} ALlistener;
|
||||
|
||||
void UpdateListenerProps(ALCcontext *context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -679,8 +679,7 @@ struct ALCdevice_struct
|
||||
#define RECORD_THREAD_NAME "alsoft-record"
|
||||
|
||||
|
||||
struct ALCcontext_struct
|
||||
{
|
||||
struct ALCcontext_struct {
|
||||
RefCount ref;
|
||||
|
||||
struct ALlistener *Listener;
|
||||
@ -690,8 +689,6 @@ struct ALCcontext_struct
|
||||
|
||||
ATOMIC(ALenum) LastError;
|
||||
|
||||
ATOMIC(ALenum) UpdateSources;
|
||||
|
||||
volatile enum DistanceModel DistanceModel;
|
||||
volatile ALboolean SourceDistanceModel;
|
||||
|
||||
@ -700,6 +697,8 @@ struct ALCcontext_struct
|
||||
volatile ALfloat SpeedOfSound;
|
||||
volatile ALenum DeferUpdates;
|
||||
|
||||
RWLock PropLock;
|
||||
|
||||
struct ALvoice *Voices;
|
||||
ALsizei VoiceCount;
|
||||
ALsizei MaxVoices;
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "alAuxEffectSlot.h"
|
||||
#include "alThunk.h"
|
||||
#include "alError.h"
|
||||
#include "alListener.h"
|
||||
#include "alSource.h"
|
||||
|
||||
#include "almalloc.h"
|
||||
@ -187,7 +188,6 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param
|
||||
err = InitializeEffect(device, slot, effect);
|
||||
if(err != AL_NO_ERROR)
|
||||
SET_ERROR_AND_GOTO(context, err, done);
|
||||
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
|
||||
break;
|
||||
|
||||
case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
|
||||
@ -195,12 +195,15 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
||||
|
||||
slot->AuxSendAuto = value;
|
||||
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
|
||||
}
|
||||
/* HACK: Force sources to update by doing a listener update */
|
||||
ReadLock(&context->PropLock);
|
||||
UpdateListenerProps(context);
|
||||
ReadUnlock(&context->PropLock);
|
||||
|
||||
done:
|
||||
ALCcontext_DecRef(context);
|
||||
|
@ -33,29 +33,28 @@ AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value)
|
||||
context = GetContextRef();
|
||||
if(!context) return;
|
||||
|
||||
WriteLock(&context->PropLock);
|
||||
switch(param)
|
||||
{
|
||||
case AL_GAIN:
|
||||
if(!(value >= 0.0f && isfinite(value)))
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
||||
|
||||
context->Listener->Gain = value;
|
||||
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
|
||||
break;
|
||||
|
||||
case AL_METERS_PER_UNIT:
|
||||
if(!(value >= 0.0f && isfinite(value)))
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
||||
|
||||
context->Listener->MetersPerUnit = value;
|
||||
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
|
||||
}
|
||||
UpdateListenerProps(context);
|
||||
|
||||
done:
|
||||
WriteUnlock(&context->PropLock);
|
||||
ALCcontext_DecRef(context);
|
||||
}
|
||||
|
||||
@ -67,33 +66,32 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val
|
||||
context = GetContextRef();
|
||||
if(!context) return;
|
||||
|
||||
WriteLock(&context->PropLock);
|
||||
switch(param)
|
||||
{
|
||||
case AL_POSITION:
|
||||
if(!(isfinite(value1) && isfinite(value2) && isfinite(value3)))
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
||||
|
||||
LockContext(context);
|
||||
aluVectorSet(&context->Listener->Position, value1, value2, value3, 1.0f);
|
||||
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
|
||||
UnlockContext(context);
|
||||
context->Listener->Position[0] = value1;
|
||||
context->Listener->Position[1] = value2;
|
||||
context->Listener->Position[2] = value3;
|
||||
break;
|
||||
|
||||
case AL_VELOCITY:
|
||||
if(!(isfinite(value1) && isfinite(value2) && isfinite(value3)))
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
||||
|
||||
LockContext(context);
|
||||
aluVectorSet(&context->Listener->Velocity, value1, value2, value3, 0.0f);
|
||||
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
|
||||
UnlockContext(context);
|
||||
context->Listener->Velocity[0] = value1;
|
||||
context->Listener->Velocity[1] = value2;
|
||||
context->Listener->Velocity[2] = value3;
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
|
||||
}
|
||||
UpdateListenerProps(context);
|
||||
|
||||
done:
|
||||
WriteUnlock(&context->PropLock);
|
||||
ALCcontext_DecRef(context);
|
||||
}
|
||||
|
||||
@ -121,6 +119,7 @@ AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values)
|
||||
context = GetContextRef();
|
||||
if(!context) return;
|
||||
|
||||
WriteLock(&context->PropLock);
|
||||
if(!(values))
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
||||
switch(param)
|
||||
@ -129,8 +128,6 @@ AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values)
|
||||
if(!(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
|
||||
isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5])))
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
||||
|
||||
LockContext(context);
|
||||
/* AT then UP */
|
||||
context->Listener->Forward[0] = values[0];
|
||||
context->Listener->Forward[1] = values[1];
|
||||
@ -138,15 +135,15 @@ AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values)
|
||||
context->Listener->Up[0] = values[3];
|
||||
context->Listener->Up[1] = values[4];
|
||||
context->Listener->Up[2] = values[5];
|
||||
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
|
||||
UnlockContext(context);
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
|
||||
}
|
||||
UpdateListenerProps(context);
|
||||
|
||||
done:
|
||||
WriteUnlock(&context->PropLock);
|
||||
ALCcontext_DecRef(context);
|
||||
}
|
||||
|
||||
@ -158,13 +155,16 @@ AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint UNUSED(value))
|
||||
context = GetContextRef();
|
||||
if(!context) return;
|
||||
|
||||
WriteLock(&context->PropLock);
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
|
||||
}
|
||||
UpdateListenerProps(context);
|
||||
|
||||
done:
|
||||
WriteUnlock(&context->PropLock);
|
||||
ALCcontext_DecRef(context);
|
||||
}
|
||||
|
||||
@ -184,13 +184,16 @@ AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, A
|
||||
context = GetContextRef();
|
||||
if(!context) return;
|
||||
|
||||
WriteLock(&context->PropLock);
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
|
||||
}
|
||||
UpdateListenerProps(context);
|
||||
|
||||
done:
|
||||
WriteUnlock(&context->PropLock);
|
||||
ALCcontext_DecRef(context);
|
||||
}
|
||||
|
||||
@ -224,6 +227,7 @@ AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values)
|
||||
context = GetContextRef();
|
||||
if(!context) return;
|
||||
|
||||
WriteLock(&context->PropLock);
|
||||
if(!(values))
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
||||
switch(param)
|
||||
@ -231,8 +235,10 @@ AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values)
|
||||
default:
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
|
||||
}
|
||||
UpdateListenerProps(context);
|
||||
|
||||
done:
|
||||
WriteUnlock(&context->PropLock);
|
||||
ALCcontext_DecRef(context);
|
||||
}
|
||||
|
||||
@ -244,6 +250,7 @@ AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value)
|
||||
context = GetContextRef();
|
||||
if(!context) return;
|
||||
|
||||
ReadLock(&context->PropLock);
|
||||
if(!(value))
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
||||
switch(param)
|
||||
@ -261,6 +268,7 @@ AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value)
|
||||
}
|
||||
|
||||
done:
|
||||
ReadUnlock(&context->PropLock);
|
||||
ALCcontext_DecRef(context);
|
||||
}
|
||||
|
||||
@ -272,24 +280,21 @@ AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat
|
||||
context = GetContextRef();
|
||||
if(!context) return;
|
||||
|
||||
ReadLock(&context->PropLock);
|
||||
if(!(value1 && value2 && value3))
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
||||
switch(param)
|
||||
{
|
||||
case AL_POSITION:
|
||||
LockContext(context);
|
||||
*value1 = context->Listener->Position.v[0];
|
||||
*value2 = context->Listener->Position.v[1];
|
||||
*value3 = context->Listener->Position.v[2];
|
||||
UnlockContext(context);
|
||||
*value1 = context->Listener->Position[0];
|
||||
*value2 = context->Listener->Position[1];
|
||||
*value3 = context->Listener->Position[2];
|
||||
break;
|
||||
|
||||
case AL_VELOCITY:
|
||||
LockContext(context);
|
||||
*value1 = context->Listener->Velocity.v[0];
|
||||
*value2 = context->Listener->Velocity.v[1];
|
||||
*value3 = context->Listener->Velocity.v[2];
|
||||
UnlockContext(context);
|
||||
*value1 = context->Listener->Velocity[0];
|
||||
*value2 = context->Listener->Velocity[1];
|
||||
*value3 = context->Listener->Velocity[2];
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -297,6 +302,7 @@ AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat
|
||||
}
|
||||
|
||||
done:
|
||||
ReadUnlock(&context->PropLock);
|
||||
ALCcontext_DecRef(context);
|
||||
}
|
||||
|
||||
@ -321,12 +327,12 @@ AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values)
|
||||
context = GetContextRef();
|
||||
if(!context) return;
|
||||
|
||||
ReadLock(&context->PropLock);
|
||||
if(!(values))
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
||||
switch(param)
|
||||
{
|
||||
case AL_ORIENTATION:
|
||||
LockContext(context);
|
||||
// AT then UP
|
||||
values[0] = context->Listener->Forward[0];
|
||||
values[1] = context->Listener->Forward[1];
|
||||
@ -334,7 +340,6 @@ AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values)
|
||||
values[3] = context->Listener->Up[0];
|
||||
values[4] = context->Listener->Up[1];
|
||||
values[5] = context->Listener->Up[2];
|
||||
UnlockContext(context);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -342,6 +347,7 @@ AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values)
|
||||
}
|
||||
|
||||
done:
|
||||
ReadUnlock(&context->PropLock);
|
||||
ALCcontext_DecRef(context);
|
||||
}
|
||||
|
||||
@ -353,6 +359,7 @@ AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value)
|
||||
context = GetContextRef();
|
||||
if(!context) return;
|
||||
|
||||
ReadLock(&context->PropLock);
|
||||
if(!(value))
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
||||
switch(param)
|
||||
@ -362,6 +369,7 @@ AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value)
|
||||
}
|
||||
|
||||
done:
|
||||
ReadUnlock(&context->PropLock);
|
||||
ALCcontext_DecRef(context);
|
||||
}
|
||||
|
||||
@ -373,24 +381,21 @@ AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *valu
|
||||
context = GetContextRef();
|
||||
if(!context) return;
|
||||
|
||||
ReadLock(&context->PropLock);
|
||||
if(!(value1 && value2 && value3))
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
||||
switch (param)
|
||||
{
|
||||
case AL_POSITION:
|
||||
LockContext(context);
|
||||
*value1 = (ALint)context->Listener->Position.v[0];
|
||||
*value2 = (ALint)context->Listener->Position.v[1];
|
||||
*value3 = (ALint)context->Listener->Position.v[2];
|
||||
UnlockContext(context);
|
||||
*value1 = (ALint)context->Listener->Position[0];
|
||||
*value2 = (ALint)context->Listener->Position[1];
|
||||
*value3 = (ALint)context->Listener->Position[2];
|
||||
break;
|
||||
|
||||
case AL_VELOCITY:
|
||||
LockContext(context);
|
||||
*value1 = (ALint)context->Listener->Velocity.v[0];
|
||||
*value2 = (ALint)context->Listener->Velocity.v[1];
|
||||
*value3 = (ALint)context->Listener->Velocity.v[2];
|
||||
UnlockContext(context);
|
||||
*value1 = (ALint)context->Listener->Velocity[0];
|
||||
*value2 = (ALint)context->Listener->Velocity[1];
|
||||
*value3 = (ALint)context->Listener->Velocity[2];
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -398,6 +403,7 @@ AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *valu
|
||||
}
|
||||
|
||||
done:
|
||||
ReadUnlock(&context->PropLock);
|
||||
ALCcontext_DecRef(context);
|
||||
}
|
||||
|
||||
@ -417,12 +423,12 @@ AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values)
|
||||
context = GetContextRef();
|
||||
if(!context) return;
|
||||
|
||||
ReadLock(&context->PropLock);
|
||||
if(!(values))
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
||||
switch(param)
|
||||
{
|
||||
case AL_ORIENTATION:
|
||||
LockContext(context);
|
||||
// AT then UP
|
||||
values[0] = (ALint)context->Listener->Forward[0];
|
||||
values[1] = (ALint)context->Listener->Forward[1];
|
||||
@ -430,7 +436,6 @@ AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values)
|
||||
values[3] = (ALint)context->Listener->Up[0];
|
||||
values[4] = (ALint)context->Listener->Up[1];
|
||||
values[5] = (ALint)context->Listener->Up[2];
|
||||
UnlockContext(context);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -438,5 +443,64 @@ AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values)
|
||||
}
|
||||
|
||||
done:
|
||||
ReadUnlock(&context->PropLock);
|
||||
ALCcontext_DecRef(context);
|
||||
}
|
||||
|
||||
|
||||
void UpdateListenerProps(ALCcontext *context)
|
||||
{
|
||||
ALlistener *listener = context->Listener;
|
||||
struct ALlistenerProps *props;
|
||||
|
||||
/* Get an unused proprty container, or allocate a new one as needed. */
|
||||
props = ATOMIC_LOAD(&listener->FreeList, almemory_order_acquire);
|
||||
if(!props)
|
||||
props = al_calloc(16, sizeof(*props));
|
||||
else
|
||||
{
|
||||
struct ALlistenerProps *next;
|
||||
do {
|
||||
next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
|
||||
} while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALlistenerProps*,
|
||||
&listener->FreeList, &props, next, almemory_order_seq_cst,
|
||||
almemory_order_consume) == 0);
|
||||
}
|
||||
|
||||
/* Copy in current property values. */
|
||||
ATOMIC_STORE(&props->Position[0], listener->Position[0], almemory_order_relaxed);
|
||||
ATOMIC_STORE(&props->Position[1], listener->Position[1], almemory_order_relaxed);
|
||||
ATOMIC_STORE(&props->Position[2], listener->Position[2], almemory_order_relaxed);
|
||||
|
||||
ATOMIC_STORE(&props->Velocity[0], listener->Velocity[0], almemory_order_relaxed);
|
||||
ATOMIC_STORE(&props->Velocity[1], listener->Velocity[1], almemory_order_relaxed);
|
||||
ATOMIC_STORE(&props->Velocity[2], listener->Velocity[2], almemory_order_relaxed);
|
||||
|
||||
ATOMIC_STORE(&props->Forward[0], listener->Forward[0], almemory_order_relaxed);
|
||||
ATOMIC_STORE(&props->Forward[1], listener->Forward[1], almemory_order_relaxed);
|
||||
ATOMIC_STORE(&props->Forward[2], listener->Forward[2], almemory_order_relaxed);
|
||||
ATOMIC_STORE(&props->Up[0], listener->Up[0], almemory_order_relaxed);
|
||||
ATOMIC_STORE(&props->Up[1], listener->Up[1], almemory_order_relaxed);
|
||||
ATOMIC_STORE(&props->Up[2], listener->Up[2], almemory_order_relaxed);
|
||||
|
||||
ATOMIC_STORE(&props->Gain, listener->Gain, almemory_order_relaxed);
|
||||
ATOMIC_STORE(&props->MetersPerUnit, listener->MetersPerUnit, almemory_order_relaxed);
|
||||
|
||||
ATOMIC_STORE(&props->DopplerFactor, context->DopplerFactor, almemory_order_relaxed);
|
||||
ATOMIC_STORE(&props->DopplerVelocity, context->DopplerVelocity, almemory_order_relaxed);
|
||||
ATOMIC_STORE(&props->SpeedOfSound, context->SpeedOfSound, almemory_order_relaxed);
|
||||
|
||||
/* Set the new container for updating internal parameters. */
|
||||
props = ATOMIC_EXCHANGE(struct ALlistenerProps*, &listener->Update, props, almemory_order_acq_rel);
|
||||
if(props)
|
||||
{
|
||||
/* If there was an unused update container, put it back in the
|
||||
* freelist.
|
||||
*/
|
||||
struct ALlistenerProps *first = ATOMIC_LOAD(&listener->FreeList);
|
||||
do {
|
||||
ATOMIC_STORE(&props->next, first, almemory_order_relaxed);
|
||||
} while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALlistenerProps*,
|
||||
&listener->FreeList, &first, props) == 0);
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "AL/al.h"
|
||||
#include "AL/alext.h"
|
||||
#include "alError.h"
|
||||
#include "alListener.h"
|
||||
#include "alSource.h"
|
||||
#include "alAuxEffectSlot.h"
|
||||
|
||||
@ -55,12 +56,15 @@ AL_API ALvoid AL_APIENTRY alEnable(ALenum capability)
|
||||
{
|
||||
case AL_SOURCE_DISTANCE_MODEL:
|
||||
context->SourceDistanceModel = AL_TRUE;
|
||||
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
|
||||
}
|
||||
/* HACK: Force sources to update by doing a listener update */
|
||||
ReadLock(&context->PropLock);
|
||||
UpdateListenerProps(context);
|
||||
ReadUnlock(&context->PropLock);
|
||||
|
||||
done:
|
||||
ALCcontext_DecRef(context);
|
||||
@ -77,12 +81,15 @@ AL_API ALvoid AL_APIENTRY alDisable(ALenum capability)
|
||||
{
|
||||
case AL_SOURCE_DISTANCE_MODEL:
|
||||
context->SourceDistanceModel = AL_FALSE;
|
||||
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
|
||||
}
|
||||
/* HACK: Force sources to update by doing a listener update */
|
||||
ReadLock(&context->PropLock);
|
||||
UpdateListenerProps(context);
|
||||
ReadUnlock(&context->PropLock);
|
||||
|
||||
done:
|
||||
ALCcontext_DecRef(context);
|
||||
@ -547,8 +554,10 @@ AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value)
|
||||
if(!(value >= 0.0f && isfinite(value)))
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
||||
|
||||
WriteLock(&context->PropLock);
|
||||
context->DopplerFactor = value;
|
||||
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
|
||||
UpdateListenerProps(context);
|
||||
WriteUnlock(&context->PropLock);
|
||||
|
||||
done:
|
||||
ALCcontext_DecRef(context);
|
||||
@ -564,8 +573,10 @@ AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value)
|
||||
if(!(value >= 0.0f && isfinite(value)))
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
||||
|
||||
WriteLock(&context->PropLock);
|
||||
context->DopplerVelocity = value;
|
||||
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
|
||||
UpdateListenerProps(context);
|
||||
WriteUnlock(&context->PropLock);
|
||||
|
||||
done:
|
||||
ALCcontext_DecRef(context);
|
||||
@ -581,8 +592,10 @@ AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat value)
|
||||
if(!(value > 0.0f && isfinite(value)))
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
||||
|
||||
WriteLock(&context->PropLock);
|
||||
context->SpeedOfSound = value;
|
||||
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
|
||||
UpdateListenerProps(context);
|
||||
WriteUnlock(&context->PropLock);
|
||||
|
||||
done:
|
||||
ALCcontext_DecRef(context);
|
||||
@ -601,9 +614,11 @@ AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value)
|
||||
value == AL_NONE))
|
||||
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
||||
|
||||
WriteLock(&context->PropLock);
|
||||
context->DistanceModel = value;
|
||||
if(!context->SourceDistanceModel)
|
||||
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
|
||||
UpdateListenerProps(context);
|
||||
WriteUnlock(&context->PropLock);
|
||||
|
||||
done:
|
||||
ALCcontext_DecRef(context);
|
||||
|
Loading…
x
Reference in New Issue
Block a user