Provide asynchronous property updates for sources

This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.

The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.

There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
This commit is contained in:
Chris Robinson
2016-05-14 23:43:40 -07:00
parent 0f7e499323
commit b3338d25f6
10 changed files with 628 additions and 357 deletions
+17 -48
View File
@@ -1558,22 +1558,7 @@ extern inline ALint GetChannelIndex(const enum Channel names[MAX_OUTPUT_CHANNELS
*/
void ALCcontext_DeferUpdates(ALCcontext *context)
{
ALCdevice *device = context->Device;
FPUCtl oldMode;
SetMixerFPUMode(&oldMode);
V0(device->Backend,lock)();
if(!context->DeferUpdates)
{
context->DeferUpdates = AL_TRUE;
/* Make sure all pending updates are performed */
UpdateContextSources(context);
}
V0(device->Backend,unlock)();
RestoreFPUMode(&oldMode);
ATOMIC_STORE(&context->DeferUpdates, AL_TRUE);
}
/* ALCcontext_ProcessUpdates
@@ -1584,14 +1569,15 @@ void ALCcontext_ProcessUpdates(ALCcontext *context)
{
ALCdevice *device = context->Device;
V0(device->Backend,lock)();
if(context->DeferUpdates)
ReadLock(&context->PropLock);
if(ATOMIC_EXCHANGE(ALenum, &context->DeferUpdates, AL_FALSE))
{
ALsizei pos;
context->DeferUpdates = AL_FALSE;
UpdateListenerProps(context);
LockUIntMapRead(&context->SourceMap);
V0(device->Backend,lock)();
for(pos = 0;pos < context->SourceMap.size;pos++)
{
ALsource *Source = context->SourceMap.array[pos].value;
@@ -1610,9 +1596,11 @@ void ALCcontext_ProcessUpdates(ALCcontext *context)
if(new_state)
SetSourceState(Source, context, new_state);
}
V0(device->Backend,unlock)();
UnlockUIntMapRead(&context->SourceMap);
UpdateAllSourceProps(context);
}
V0(device->Backend,unlock)();
ReadUnlock(&context->PropLock);
}
@@ -2052,7 +2040,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
}
SetMixerFPUMode(&oldMode);
V0(device->Backend,lock)();
if(device->DefaultSlot)
{
ALeffectslot *slot = device->DefaultSlot;
@@ -2062,7 +2049,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
state->OutChannels = device->Dry.NumChannels;
if(V(state,deviceUpdate)(device) == AL_FALSE)
{
V0(device->Backend,unlock)();
RestoreFPUMode(&oldMode);
return ALC_INVALID_DEVICE;
}
@@ -2074,6 +2060,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
{
ALsizei pos;
ReadLock(&context->PropLock);
LockUIntMapRead(&context->EffectSlotMap);
for(pos = 0;pos < context->EffectSlotMap.size;pos++)
{
@@ -2085,10 +2072,11 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
if(V(state,deviceUpdate)(device) == AL_FALSE)
{
UnlockUIntMapRead(&context->EffectSlotMap);
V0(device->Backend,unlock)();
ReadUnlock(&context->PropLock);
RestoreFPUMode(&oldMode);
return ALC_INVALID_DEVICE;
}
UpdateEffectSlotProps(slot, AL_FALSE);
}
UnlockUIntMapRead(&context->EffectSlotMap);
@@ -2105,38 +2093,19 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
source->Send[s].Slot = NULL;
source->Send[s].Gain = 1.0f;
source->Send[s].GainHF = 1.0f;
source->Send[s].HFReference = LOWPASSFREQREF;
source->Send[s].GainLF = 1.0f;
source->Send[s].LFReference = HIGHPASSFREQREF;
s++;
}
ATOMIC_STORE(&source->NeedsUpdate, AL_TRUE);
}
UnlockUIntMapRead(&context->SourceMap);
for(pos = 0;pos < context->VoiceCount;pos++)
{
ALvoice *voice = &context->Voices[pos];
ALsource *source = voice->Source;
ALbufferlistitem *BufferListItem;
if(!source)
continue;
BufferListItem = ATOMIC_LOAD(&source->queue);
while(BufferListItem != NULL)
{
ALbuffer *buffer;
if((buffer=BufferListItem->buffer) != NULL)
{
ATOMIC_STORE(&source->NeedsUpdate, AL_FALSE);
voice->Update(voice, source, buffer, context);
break;
}
BufferListItem = BufferListItem->next;
}
}
UpdateAllSourceProps(context);
ReadUnlock(&context->PropLock);
context = context->next;
}
V0(device->Backend,unlock)();
RestoreFPUMode(&oldMode);
if(!(device->Flags&DEVICE_PAUSED))
@@ -2308,7 +2277,7 @@ static ALvoid InitContext(ALCcontext *Context)
Context->DopplerFactor = 1.0f;
Context->DopplerVelocity = 1.0f;
Context->SpeedOfSound = SPEEDOFSOUNDMETRESPERSEC;
Context->DeferUpdates = AL_FALSE;
ATOMIC_INIT(&Context->DeferUpdates, AL_FALSE);
Context->ExtensionList = alExtList;
}
+136 -133
View File
@@ -266,7 +266,7 @@ static ALboolean BsincPrepare(const ALuint increment, BsincState *state)
}
static ALboolean CalcListenerParams(ALCcontext *Context)
static void CalcListenerParams(ALCcontext *Context)
{
ALlistener *Listener = Context->Listener;
ALdouble N[3], V[3], U[3], P[3];
@@ -275,7 +275,7 @@ static ALboolean CalcListenerParams(ALCcontext *Context)
aluVector vel;
props = ATOMIC_EXCHANGE(struct ALlistenerProps*, &Listener->Update, NULL, almemory_order_acq_rel);
if(!props) return AL_FALSE;
if(!props) return;
/* AT then UP */
N[0] = ATOMIC_LOAD(&props->Forward[0], almemory_order_relaxed);
@@ -330,17 +330,15 @@ static ALboolean CalcListenerParams(ALCcontext *Context)
ATOMIC_STORE(&props->next, first, almemory_order_relaxed);
} while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALlistenerProps*,
&Listener->FreeList, &first, props) == 0);
return AL_TRUE;
}
static ALboolean CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device)
static void CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device)
{
struct ALeffectslotProps *first;
struct ALeffectslotProps *props;
props = ATOMIC_EXCHANGE(struct ALeffectslotProps*, &slot->Update, NULL, almemory_order_acq_rel);
if(!props) return AL_FALSE;
if(!props) return;
slot->Params.Gain = ATOMIC_LOAD(&props->Gain, almemory_order_relaxed);
slot->Params.AuxSendAuto = ATOMIC_LOAD(&props->AuxSendAuto, almemory_order_relaxed);
@@ -377,11 +375,43 @@ static ALboolean CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device)
ATOMIC_STORE(&props->next, first, almemory_order_relaxed);
} while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps*,
&slot->FreeList, &first, props) == 0);
return AL_TRUE;
}
ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer *ALBuffer, const ALCcontext *ALContext)
static void CalcSourceParams(ALvoice *voice, ALCcontext *context)
{
ALsource *source = voice->Source;
ALbufferlistitem *BufferListItem;
struct ALsourceProps *first;
struct ALsourceProps *props;
props = ATOMIC_EXCHANGE(struct ALsourceProps*, &source->Update, NULL, almemory_order_acq_rel);
if(!props) return;
BufferListItem = ATOMIC_LOAD(&source->queue, almemory_order_relaxed);
while(BufferListItem != NULL)
{
ALbuffer *buffer;
if((buffer=BufferListItem->buffer) != NULL)
{
voice->Update(voice, props, buffer, context);
break;
}
BufferListItem = BufferListItem->next;
}
/* 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(&source->FreeList);
do {
ATOMIC_STORE(&props->next, first, almemory_order_relaxed);
} while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*,
&source->FreeList, &first, props) == 0);
}
ALvoid CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext)
{
static const struct ChanMap MonoMap[1] = {
{ FrontCenter, 0.0f, 0.0f }
@@ -448,22 +478,22 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A
ListenerGain = Listener->Params.Gain;
/* Get source properties */
SourceVolume = ALSource->Gain;
MinVolume = ALSource->MinGain;
MaxVolume = ALSource->MaxGain;
Pitch = ALSource->Pitch;
Relative = ALSource->HeadRelative;
DirectChannels = ALSource->DirectChannels;
SourceVolume = ATOMIC_LOAD(&props->Gain, almemory_order_relaxed);
MinVolume = ATOMIC_LOAD(&props->MinGain, almemory_order_relaxed);
MaxVolume = ATOMIC_LOAD(&props->MaxGain, almemory_order_relaxed);
Pitch = ATOMIC_LOAD(&props->Pitch, almemory_order_relaxed);
Relative = ATOMIC_LOAD(&props->HeadRelative, almemory_order_relaxed);
DirectChannels = ATOMIC_LOAD(&props->DirectChannels, almemory_order_relaxed);
/* Convert counter-clockwise to clockwise. */
StereoMap[0].angle = -ALSource->StereoPan[0];
StereoMap[1].angle = -ALSource->StereoPan[1];
StereoMap[0].angle = -ATOMIC_LOAD(&props->StereoPan[0], almemory_order_relaxed);
StereoMap[1].angle = -ATOMIC_LOAD(&props->StereoPan[1], almemory_order_relaxed);
voice->Direct.OutBuffer = Device->Dry.Buffer;
voice->Direct.OutChannels = Device->Dry.NumChannels;
for(i = 0;i < NumSends;i++)
{
SendSlots[i] = ALSource->Send[i].Slot;
SendSlots[i] = ATOMIC_LOAD(&props->Send[i].Slot, almemory_order_relaxed);
if(!SendSlots[i] && i == 0)
SendSlots[i] = Device->DefaultSlot;
if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL)
@@ -489,15 +519,15 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A
/* Calculate gains */
DryGain = clampf(SourceVolume, MinVolume, MaxVolume);
DryGain *= ALSource->Direct.Gain * ListenerGain;
DryGainHF = ALSource->Direct.GainHF;
DryGainLF = ALSource->Direct.GainLF;
DryGain *= ATOMIC_LOAD(&props->Direct.Gain, almemory_order_relaxed) * ListenerGain;
DryGainHF = ATOMIC_LOAD(&props->Direct.GainHF, almemory_order_relaxed);
DryGainLF = ATOMIC_LOAD(&props->Direct.GainLF, almemory_order_relaxed);
for(i = 0;i < NumSends;i++)
{
WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume);
WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
WetGainHF[i] = ALSource->Send[i].GainHF;
WetGainLF[i] = ALSource->Send[i].GainLF;
WetGain[i] *= ATOMIC_LOAD(&props->Send[i].Gain, almemory_order_relaxed) * ListenerGain;
WetGainHF[i] = ATOMIC_LOAD(&props->Send[i].GainHF, almemory_order_relaxed);
WetGainLF[i] = ATOMIC_LOAD(&props->Send[i].GainLF, almemory_order_relaxed);
}
switch(ALBuffer->FmtChannels)
@@ -557,13 +587,13 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A
ALfloat scale;
/* AT then UP */
N[0] = ALSource->Orientation[0][0];
N[1] = ALSource->Orientation[0][1];
N[2] = ALSource->Orientation[0][2];
N[0] = ATOMIC_LOAD(&props->Orientation[0][0], almemory_order_relaxed);
N[1] = ATOMIC_LOAD(&props->Orientation[0][1], almemory_order_relaxed);
N[2] = ATOMIC_LOAD(&props->Orientation[0][2], almemory_order_relaxed);
aluNormalize(N);
V[0] = ALSource->Orientation[1][0];
V[1] = ALSource->Orientation[1][1];
V[2] = ALSource->Orientation[1][2];
V[0] = ATOMIC_LOAD(&props->Orientation[1][0], almemory_order_relaxed);
V[1] = ATOMIC_LOAD(&props->Orientation[1][1], almemory_order_relaxed);
V[2] = ATOMIC_LOAD(&props->Orientation[1][2], almemory_order_relaxed);
aluNormalize(V);
if(!Relative)
{
@@ -779,8 +809,10 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A
}
{
ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
ALfloat hfscale = ATOMIC_LOAD(&props->Direct.HFReference, almemory_order_relaxed) /
Frequency;
ALfloat lfscale = ATOMIC_LOAD(&props->Direct.LFReference, almemory_order_relaxed) /
Frequency;
DryGainHF = maxf(DryGainHF, 0.0001f);
DryGainLF = maxf(DryGainLF, 0.0001f);
for(c = 0;c < num_channels;c++)
@@ -800,8 +832,10 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A
}
for(i = 0;i < NumSends;i++)
{
ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
ALfloat hfscale = ATOMIC_LOAD(&props->Send[i].HFReference, almemory_order_relaxed) /
Frequency;
ALfloat lfscale = ATOMIC_LOAD(&props->Send[i].LFReference, almemory_order_relaxed) /
Frequency;
WetGainHF[i] = maxf(WetGainHF[i], 0.0001f);
WetGainLF[i] = maxf(WetGainLF[i], 0.0001f);
for(c = 0;c < num_channels;c++)
@@ -821,7 +855,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A
}
}
ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer *ALBuffer, const ALCcontext *ALContext)
ALvoid CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext)
{
const ALCdevice *Device = ALContext->Device;
const ALlistener *Listener = ALContext->Listener;
@@ -862,7 +896,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer
}
/* Get context/device properties */
DopplerFactor = Listener->Params.DopplerFactor * ALSource->DopplerFactor;
DopplerFactor = Listener->Params.DopplerFactor;
SpeedOfSound = Listener->Params.SpeedOfSound;
NumSends = Device->NumAuxSends;
Frequency = Device->Frequency;
@@ -872,29 +906,39 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer
MetersPerUnit = Listener->Params.MetersPerUnit;
/* Get source properties */
SourceVolume = ALSource->Gain;
MinVolume = ALSource->MinGain;
MaxVolume = ALSource->MaxGain;
Pitch = ALSource->Pitch;
Position = ALSource->Position;
Direction = ALSource->Direction;
Velocity = ALSource->Velocity;
MinDist = ALSource->RefDistance;
MaxDist = ALSource->MaxDistance;
Rolloff = ALSource->RollOffFactor;
InnerAngle = ALSource->InnerAngle;
OuterAngle = ALSource->OuterAngle;
AirAbsorptionFactor = ALSource->AirAbsorptionFactor;
DryGainHFAuto = ALSource->DryGainHFAuto;
WetGainAuto = ALSource->WetGainAuto;
WetGainHFAuto = ALSource->WetGainHFAuto;
RoomRolloffBase = ALSource->RoomRolloffFactor;
SourceVolume = ATOMIC_LOAD(&props->Gain, almemory_order_relaxed);
MinVolume = ATOMIC_LOAD(&props->MinGain, almemory_order_relaxed);
MaxVolume = ATOMIC_LOAD(&props->MaxGain, almemory_order_relaxed);
Pitch = ATOMIC_LOAD(&props->Pitch, almemory_order_relaxed);
aluVectorSet(&Position, ATOMIC_LOAD(&props->Position[0], almemory_order_relaxed),
ATOMIC_LOAD(&props->Position[1], almemory_order_relaxed),
ATOMIC_LOAD(&props->Position[2], almemory_order_relaxed),
1.0f);
aluVectorSet(&Direction, ATOMIC_LOAD(&props->Direction[0], almemory_order_relaxed),
ATOMIC_LOAD(&props->Direction[1], almemory_order_relaxed),
ATOMIC_LOAD(&props->Direction[2], almemory_order_relaxed),
0.0f);
aluVectorSet(&Velocity, 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);
MinDist = ATOMIC_LOAD(&props->RefDistance, almemory_order_relaxed);
MaxDist = ATOMIC_LOAD(&props->MaxDistance, almemory_order_relaxed);
Rolloff = ATOMIC_LOAD(&props->RollOffFactor, almemory_order_relaxed);
DopplerFactor *= ATOMIC_LOAD(&props->DopplerFactor, almemory_order_relaxed);
InnerAngle = ATOMIC_LOAD(&props->InnerAngle, almemory_order_relaxed);
OuterAngle = ATOMIC_LOAD(&props->OuterAngle, almemory_order_relaxed);
AirAbsorptionFactor = ATOMIC_LOAD(&props->AirAbsorptionFactor, almemory_order_relaxed);
DryGainHFAuto = ATOMIC_LOAD(&props->DryGainHFAuto, almemory_order_relaxed);
WetGainAuto = ATOMIC_LOAD(&props->WetGainAuto, almemory_order_relaxed);
WetGainHFAuto = ATOMIC_LOAD(&props->WetGainHFAuto, almemory_order_relaxed);
RoomRolloffBase = ATOMIC_LOAD(&props->RoomRolloffFactor, almemory_order_relaxed);
voice->Direct.OutBuffer = Device->Dry.Buffer;
voice->Direct.OutChannels = Device->Dry.NumChannels;
for(i = 0;i < NumSends;i++)
{
SendSlots[i] = ALSource->Send[i].Slot;
SendSlots[i] = ATOMIC_LOAD(&props->Send[i].Slot, almemory_order_relaxed);
if(!SendSlots[i] && i == 0)
SendSlots[i] = Device->DefaultSlot;
@@ -905,7 +949,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer
DecayDistance[i] = 0.0f;
RoomAirAbsorption[i] = 1.0f;
}
else if(SendSlots[i]->AuxSendAuto)
else if(SendSlots[i]->Params.AuxSendAuto)
{
RoomRolloff[i] = SendSlots[i]->Params.RoomRolloff + RoomRolloffBase;
DecayDistance[i] = SendSlots[i]->Params.DecayTime *
@@ -934,7 +978,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer
}
/* Transform source to listener space (convert to head relative) */
if(ALSource->HeadRelative == AL_FALSE)
if(ATOMIC_LOAD(&props->HeadRelative, almemory_order_relaxed) == AL_FALSE)
{
const aluMatrixd *Matrix = &Listener->Params.Matrix;
/* Transform source vectors */
@@ -964,8 +1008,9 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer
Attenuation = 1.0f;
for(i = 0;i < NumSends;i++)
RoomAttenuation[i] = 1.0f;
switch(Listener->Params.SourceDistanceModel ? ALSource->DistanceModel :
Listener->Params.DistanceModel)
switch(Listener->Params.SourceDistanceModel ?
ATOMIC_LOAD(&props->DistanceModel, almemory_order_relaxed) :
Listener->Params.DistanceModel)
{
case InverseDistanceClamped:
ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
@@ -1059,13 +1104,15 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer
if(Angle > InnerAngle && Angle <= OuterAngle)
{
ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
ConeVolume = lerp(1.0f, ALSource->OuterGain, scale);
ConeHF = lerp(1.0f, ALSource->OuterGainHF, scale);
ConeVolume = lerp(1.0f, ATOMIC_LOAD(&props->OuterGain, almemory_order_relaxed),
scale);
ConeHF = lerp(1.0f, ATOMIC_LOAD(&props->OuterGainHF, almemory_order_relaxed),
scale);
}
else if(Angle > OuterAngle)
{
ConeVolume = ALSource->OuterGain;
ConeHF = ALSource->OuterGainHF;
ConeVolume = ATOMIC_LOAD(&props->OuterGain, almemory_order_relaxed);
ConeHF = ATOMIC_LOAD(&props->OuterGainHF, almemory_order_relaxed);
}
else
{
@@ -1093,14 +1140,14 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer
WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume);
/* Apply gain and frequency filters */
DryGain *= ALSource->Direct.Gain * ListenerGain;
DryGainHF *= ALSource->Direct.GainHF;
DryGainLF *= ALSource->Direct.GainLF;
DryGain *= ATOMIC_LOAD(&props->Direct.Gain, almemory_order_relaxed) * ListenerGain;
DryGainHF *= ATOMIC_LOAD(&props->Direct.GainHF, almemory_order_relaxed);
DryGainLF *= ATOMIC_LOAD(&props->Direct.GainLF, almemory_order_relaxed);
for(i = 0;i < NumSends;i++)
{
WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
WetGainHF[i] *= ALSource->Send[i].GainHF;
WetGainLF[i] *= ALSource->Send[i].GainLF;
WetGain[i] *= ATOMIC_LOAD(&props->Send[i].Gain, almemory_order_relaxed) * ListenerGain;
WetGainHF[i] *= ATOMIC_LOAD(&props->Send[i].GainHF, almemory_order_relaxed);
WetGainLF[i] *= ATOMIC_LOAD(&props->Send[i].GainLF, almemory_order_relaxed);
}
/* Calculate velocity-based doppler effect */
@@ -1139,7 +1186,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer
*/
ALfloat dir[3] = { 0.0f, 0.0f, -1.0f };
ALfloat ev = 0.0f, az = 0.0f;
ALfloat radius = ALSource->Radius;
ALfloat radius = ATOMIC_LOAD(&props->Radius, almemory_order_relaxed);
ALfloat coeffs[MAX_AMBI_COEFFS];
ALfloat spread = 0.0f;
@@ -1193,7 +1240,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer
{
/* Non-HRTF rendering. */
ALfloat dir[3] = { 0.0f, 0.0f, -1.0f };
ALfloat radius = ALSource->Radius;
ALfloat radius = ATOMIC_LOAD(&props->Radius, almemory_order_relaxed);
ALfloat coeffs[MAX_AMBI_COEFFS];
ALfloat spread = 0.0f;
@@ -1247,8 +1294,10 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer
}
{
ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
ALfloat hfscale = ATOMIC_LOAD(&props->Direct.HFReference, almemory_order_relaxed) /
Frequency;
ALfloat lfscale = ATOMIC_LOAD(&props->Direct.LFReference, almemory_order_relaxed) /
Frequency;
DryGainHF = maxf(DryGainHF, 0.0001f);
DryGainLF = maxf(DryGainLF, 0.0001f);
voice->Direct.Filters[0].ActiveType = AF_None;
@@ -1265,8 +1314,10 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer
}
for(i = 0;i < NumSends;i++)
{
ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
ALfloat hfscale = ATOMIC_LOAD(&props->Send[i].HFReference, almemory_order_relaxed) /
Frequency;
ALfloat lfscale = ATOMIC_LOAD(&props->Send[i].LFReference, almemory_order_relaxed) /
Frequency;
WetGainHF[i] = maxf(WetGainHF[i], 0.0001f);
WetGainLF[i] = maxf(WetGainLF[i], 0.0001f);
voice->Send[i].Filters[0].ActiveType = AF_None;
@@ -1287,69 +1338,22 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer
void UpdateContextSources(ALCcontext *ctx)
{
ALvoice *voice, *voice_end;
ALboolean fullupdate;
ALsource *source;
fullupdate = CalcListenerParams(ctx);
#define UPDATE_SLOT(iter) do { \
if(CalcEffectSlotParams(*iter, ctx->Device)) \
fullupdate = AL_TRUE; \
} while(0)
CalcListenerParams(ctx);
#define UPDATE_SLOT(iter) CalcEffectSlotParams(*iter, ctx->Device)
VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, UPDATE_SLOT);
#undef UPDATE_SLOT
if(fullupdate)
voice = ctx->Voices;
voice_end = voice + ctx->VoiceCount;
for(;voice != voice_end;++voice)
{
voice = ctx->Voices;
voice_end = voice + ctx->VoiceCount;
for(;voice != voice_end;++voice)
{
if(!(source=voice->Source)) continue;
if(source->state != AL_PLAYING && source->state != AL_PAUSED)
voice->Source = NULL;
else
{
ALbufferlistitem *BufferListItem;
BufferListItem = ATOMIC_LOAD(&source->queue);
while(BufferListItem != NULL)
{
ALbuffer *buffer;
if((buffer=BufferListItem->buffer) != NULL)
{
ATOMIC_STORE(&source->NeedsUpdate, AL_FALSE);
voice->Update(voice, source, buffer, ctx);
break;
}
BufferListItem = BufferListItem->next;
}
}
}
}
else
{
voice = ctx->Voices;
voice_end = voice + ctx->VoiceCount;
for(;voice != voice_end;++voice)
{
if(!(source=voice->Source)) continue;
if(source->state != AL_PLAYING && source->state != AL_PAUSED)
voice->Source = NULL;
else if(ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE))
{
ALbufferlistitem *BufferListItem;
BufferListItem = ATOMIC_LOAD(&source->queue);
while(BufferListItem != NULL)
{
ALbuffer *buffer;
if((buffer=BufferListItem->buffer) != NULL)
{
voice->Update(voice, source, buffer, ctx);
break;
}
BufferListItem = BufferListItem->next;
}
}
}
if(!(source=voice->Source)) continue;
if(source->state != AL_PLAYING && source->state != AL_PAUSED)
voice->Source = NULL;
else
CalcSourceParams(voice, ctx);
}
}
@@ -1447,8 +1451,7 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
ctx = ATOMIC_LOAD(&device->ContextList);
while(ctx)
{
if(!ctx->DeferUpdates)
UpdateContextSources(ctx);
UpdateContextSources(ctx);
#define CLEAR_WET_BUFFER(iter) do { \
for(i = 0;i < (*iter)->NumChannels;i++) \
memset((*iter)->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); \
+1 -1
View File
@@ -388,9 +388,9 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam
BufferListItem = ATOMIC_LOAD(&Source->current_buffer);
DataPosInt = Source->position;
DataPosFrac = Source->position_fraction;
Looping = Source->Looping;
NumChannels = Source->NumChannels;
SampleSize = Source->SampleSize;
Looping = voice->Looping;
increment = voice->Step;
IrSize = (Device->Hrtf ? GetHrtfIrSize(Device->Hrtf) : 0);
+1 -1
View File
@@ -695,7 +695,7 @@ struct ALCcontext_struct {
volatile ALfloat DopplerFactor;
volatile ALfloat DopplerVelocity;
volatile ALfloat SpeedOfSound;
volatile ALenum DeferUpdates;
ATOMIC(ALenum) DeferUpdates;
RWLock PropLock;
+81 -23
View File
@@ -13,6 +13,7 @@ extern "C" {
struct ALbuffer;
struct ALsource;
struct ALsourceProps;
typedef struct ALbufferlistitem {
@@ -25,11 +26,13 @@ typedef struct ALvoice {
struct ALsource *volatile Source;
/** Method to update mixing parameters. */
ALvoid (*Update)(struct ALvoice *self, const struct ALsource *source, const struct ALbuffer *ALBuffer, const ALCcontext *context);
ALvoid (*Update)(struct ALvoice *self, const struct ALsourceProps *props, const struct ALbuffer *ALBuffer, const ALCcontext *context);
/** Current target parameters used for mixing. */
ALint Step;
ALboolean Looping;
/* If not 'moving', gain/coefficients are set directly without fading. */
ALboolean Moving;
@@ -46,6 +49,59 @@ typedef struct ALvoice {
} ALvoice;
struct ALsourceProps {
ATOMIC(ALfloat) Pitch;
ATOMIC(ALfloat) Gain;
ATOMIC(ALfloat) OuterGain;
ATOMIC(ALfloat) MinGain;
ATOMIC(ALfloat) MaxGain;
ATOMIC(ALfloat) InnerAngle;
ATOMIC(ALfloat) OuterAngle;
ATOMIC(ALfloat) RefDistance;
ATOMIC(ALfloat) MaxDistance;
ATOMIC(ALfloat) RollOffFactor;
ATOMIC(ALfloat) Position[3];
ATOMIC(ALfloat) Velocity[3];
ATOMIC(ALfloat) Direction[3];
ATOMIC(ALfloat) Orientation[2][3];
ATOMIC(ALboolean) HeadRelative;
ATOMIC(ALboolean) Looping;
ATOMIC(enum DistanceModel) DistanceModel;
ATOMIC(ALboolean) DirectChannels;
ATOMIC(ALboolean) DryGainHFAuto;
ATOMIC(ALboolean) WetGainAuto;
ATOMIC(ALboolean) WetGainHFAuto;
ATOMIC(ALfloat) OuterGainHF;
ATOMIC(ALfloat) AirAbsorptionFactor;
ATOMIC(ALfloat) RoomRolloffFactor;
ATOMIC(ALfloat) DopplerFactor;
ATOMIC(ALfloat) StereoPan[2];
ATOMIC(ALfloat) Radius;
/** Direct filter and auxiliary send info. */
struct {
ATOMIC(ALfloat) Gain;
ATOMIC(ALfloat) GainHF;
ATOMIC(ALfloat) HFReference;
ATOMIC(ALfloat) GainLF;
ATOMIC(ALfloat) LFReference;
} Direct;
struct {
ATOMIC(struct ALeffectslot*) Slot;
ATOMIC(ALfloat) Gain;
ATOMIC(ALfloat) GainHF;
ATOMIC(ALfloat) HFReference;
ATOMIC(ALfloat) GainLF;
ATOMIC(ALfloat) LFReference;
} Send[MAX_SENDS];
ATOMIC(struct ALsourceProps*) next;
};
typedef struct ALsource {
/** Source properties. */
volatile ALfloat Pitch;
@@ -58,9 +114,9 @@ typedef struct ALsource {
volatile ALfloat RefDistance;
volatile ALfloat MaxDistance;
volatile ALfloat RollOffFactor;
aluVector Position;
aluVector Velocity;
aluVector Direction;
volatile ALfloat Position[3];
volatile ALfloat Velocity[3];
volatile ALfloat Direction[3];
volatile ALfloat Orientation[2][3];
volatile ALboolean HeadRelative;
volatile ALboolean Looping;
@@ -83,6 +139,23 @@ typedef struct ALsource {
volatile ALfloat Radius;
/** Direct filter and auxiliary send info. */
struct {
ALfloat Gain;
ALfloat GainHF;
ALfloat HFReference;
ALfloat GainLF;
ALfloat LFReference;
} Direct;
struct {
struct ALeffectslot *Slot;
ALfloat Gain;
ALfloat GainHF;
ALfloat HFReference;
ALfloat GainLF;
ALfloat LFReference;
} Send[MAX_SENDS];
/**
* Last user-specified offset, and the offset type (bytes, samples, or
* seconds).
@@ -114,25 +187,8 @@ typedef struct ALsource {
ALuint NumChannels;
ALuint SampleSize;
/** Direct filter and auxiliary send info. */
struct {
ALfloat Gain;
ALfloat GainHF;
ALfloat HFReference;
ALfloat GainLF;
ALfloat LFReference;
} Direct;
struct {
struct ALeffectslot *Slot;
ALfloat Gain;
ALfloat GainHF;
ALfloat HFReference;
ALfloat GainLF;
ALfloat LFReference;
} Send[MAX_SENDS];
/** Source needs to update its mixing parameters. */
ATOMIC(ALenum) NeedsUpdate;
ATOMIC(struct ALsourceProps*) Update;
ATOMIC(struct ALsourceProps*) FreeList;
/** Self ID */
ALuint id;
@@ -152,6 +208,8 @@ inline struct ALsource *LookupSource(ALCcontext *context, ALuint id)
inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id)
{ return (struct ALsource*)RemoveUIntMapKeyNoLock(&context->SourceMap, id); }
void UpdateSourceProps(ALsource *source, ALuint num_sends);
void UpdateAllSourceProps(ALCcontext *context);
ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state);
ALboolean ApplyOffset(ALsource *Source);
+3 -2
View File
@@ -34,6 +34,7 @@ extern "C" {
#endif
struct ALsource;
struct ALsourceProps;
struct ALvoice;
struct ALeffectslot;
struct ALbuffer;
@@ -375,8 +376,8 @@ void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALuint numchans, c
ALvoid UpdateContextSources(ALCcontext *context);
ALvoid CalcSourceParams(struct ALvoice *voice, const struct ALsource *source, const struct ALbuffer *buffer, const ALCcontext *ALContext);
ALvoid CalcNonAttnSourceParams(struct ALvoice *voice, const struct ALsource *source, const struct ALbuffer *buffer, const ALCcontext *ALContext);
ALvoid CalcAttnSourceParams(struct ALvoice *voice, const struct ALsourceProps *props, const struct ALbuffer *buffer, const ALCcontext *ALContext);
ALvoid CalcNonAttnSourceParams(struct ALvoice *voice, const struct ALsourceProps *props, const struct ALbuffer *buffer, const ALCcontext *ALContext);
ALvoid MixSource(struct ALvoice *voice, struct ALsource *source, ALCdevice *Device, ALuint SamplesToDo);
+2
View File
@@ -202,6 +202,8 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
slot->AuxSendAuto = value;
UpdateEffectSlotProps(slot, AL_FALSE);
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateAllSourceProps(context);
break;
default:
+30 -6
View File
@@ -51,7 +51,11 @@ AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value)
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
UpdateListenerProps(context);
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
{
UpdateListenerProps(context);
UpdateAllSourceProps(context);
}
done:
WriteUnlock(&context->PropLock);
@@ -88,7 +92,11 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
UpdateListenerProps(context);
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
{
UpdateListenerProps(context);
UpdateAllSourceProps(context);
}
done:
WriteUnlock(&context->PropLock);
@@ -140,7 +148,11 @@ AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values)
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
UpdateListenerProps(context);
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
{
UpdateListenerProps(context);
UpdateAllSourceProps(context);
}
done:
WriteUnlock(&context->PropLock);
@@ -161,7 +173,11 @@ AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint UNUSED(value))
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
UpdateListenerProps(context);
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
{
UpdateListenerProps(context);
UpdateAllSourceProps(context);
}
done:
WriteUnlock(&context->PropLock);
@@ -190,7 +206,11 @@ AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, A
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
UpdateListenerProps(context);
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
{
UpdateListenerProps(context);
UpdateAllSourceProps(context);
}
done:
WriteUnlock(&context->PropLock);
@@ -235,7 +255,11 @@ AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values)
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
UpdateListenerProps(context);
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
{
UpdateListenerProps(context);
UpdateAllSourceProps(context);
}
done:
WriteUnlock(&context->PropLock);
+320 -132
View File
File diff suppressed because it is too large Load Diff
+37 -11
View File
@@ -62,7 +62,11 @@ AL_API ALvoid AL_APIENTRY alEnable(ALenum capability)
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
UpdateListenerProps(context);
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
{
UpdateListenerProps(context);
UpdateAllSourceProps(context);
}
done:
WriteUnlock(&context->PropLock);
@@ -86,7 +90,11 @@ AL_API ALvoid AL_APIENTRY alDisable(ALenum capability)
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
UpdateListenerProps(context);
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
{
UpdateListenerProps(context);
UpdateAllSourceProps(context);
}
done:
WriteUnlock(&context->PropLock);
@@ -148,7 +156,7 @@ AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname)
break;
case AL_DEFERRED_UPDATES_SOFT:
value = context->DeferUpdates;
value = ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire);
break;
default:
@@ -188,7 +196,7 @@ AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname)
break;
case AL_DEFERRED_UPDATES_SOFT:
value = (ALdouble)context->DeferUpdates;
value = (ALdouble)ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire);
break;
default:
@@ -228,7 +236,7 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname)
break;
case AL_DEFERRED_UPDATES_SOFT:
value = (ALfloat)context->DeferUpdates;
value = (ALfloat)ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire);
break;
default:
@@ -268,7 +276,7 @@ AL_API ALint AL_APIENTRY alGetInteger(ALenum pname)
break;
case AL_DEFERRED_UPDATES_SOFT:
value = (ALint)context->DeferUpdates;
value = (ALint)ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire);
break;
default:
@@ -308,7 +316,7 @@ AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname)
break;
case AL_DEFERRED_UPDATES_SOFT:
value = (ALint64SOFT)context->DeferUpdates;
value = (ALint64SOFT)ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire);
break;
default:
@@ -554,7 +562,11 @@ AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value)
WriteLock(&context->PropLock);
context->DopplerFactor = value;
UpdateListenerProps(context);
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
{
UpdateListenerProps(context);
UpdateAllSourceProps(context);
}
WriteUnlock(&context->PropLock);
done:
@@ -573,7 +585,11 @@ AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value)
WriteLock(&context->PropLock);
context->DopplerVelocity = value;
UpdateListenerProps(context);
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
{
UpdateListenerProps(context);
UpdateAllSourceProps(context);
}
WriteUnlock(&context->PropLock);
done:
@@ -592,7 +608,11 @@ AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat value)
WriteLock(&context->PropLock);
context->SpeedOfSound = value;
UpdateListenerProps(context);
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
{
UpdateListenerProps(context);
UpdateAllSourceProps(context);
}
WriteUnlock(&context->PropLock);
done:
@@ -615,7 +635,13 @@ AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value)
WriteLock(&context->PropLock);
context->DistanceModel = value;
if(!context->SourceDistanceModel)
UpdateListenerProps(context);
{
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
{
UpdateListenerProps(context);
UpdateAllSourceProps(context);
}
}
WriteUnlock(&context->PropLock);
done: