Make the context VoiceCount atomic

This commit is contained in:
Chris Robinson 2018-11-23 16:16:31 -08:00
parent 73528c9f55
commit df057d4118
4 changed files with 80 additions and 87 deletions

View File

@ -1711,7 +1711,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
ALCsizei hrtf_id = -1;
ALCcontext *context;
ALCuint oldFreq;
ALCsizei i;
int val;
// Check for attributes
@ -2248,9 +2247,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
context = device->ContextList.load();
while(context)
{
struct ALvoiceProps *vprops;
ALsizei pos;
if(context->DefaultSlot)
{
ALeffectslot *slot = context->DefaultSlot.get();
@ -2320,7 +2316,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
* auxiliary sends is changing. Active sources will have updates
* respecified in UpdateAllSourceProps.
*/
vprops = context->FreeVoiceProps.exchange(nullptr, std::memory_order_acq_rel);
ALvoiceProps *vprops{context->FreeVoiceProps.exchange(nullptr, std::memory_order_acq_rel)};
while(vprops)
{
struct ALvoiceProps *next = vprops->next.load(std::memory_order_relaxed);
@ -2329,24 +2325,27 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
}
AllocateVoices(context, context->MaxVoices, old_sends);
for(pos = 0;pos < context->VoiceCount;pos++)
{
ALvoice *voice = context->Voices[pos];
al_free(voice->Update.exchange(nullptr, std::memory_order_acq_rel));
if(voice->Source.load(std::memory_order_acquire) == nullptr)
continue;
if(device->AvgSpeakerDist > 0.0f)
auto voices_end = context->Voices + context->VoiceCount.load(std::memory_order_relaxed);
std::for_each(context->Voices, voices_end,
[device](ALvoice *voice) -> void
{
/* Reinitialize the NFC filters for new parameters. */
ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC /
(device->AvgSpeakerDist * device->Frequency);
for(i = 0;i < voice->NumChannels;i++)
NfcFilterCreate(&voice->Direct.Params[i].NFCtrlFilter, 0.0f, w1);
al_free(voice->Update.exchange(nullptr, std::memory_order_acq_rel));
if(voice->Source.load(std::memory_order_acquire) == nullptr)
return;
if(device->AvgSpeakerDist > 0.0f)
{
/* Reinitialize the NFC filters for new parameters. */
ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC /
(device->AvgSpeakerDist * device->Frequency);
std::for_each(voice->Direct.Params, voice->Direct.Params+voice->NumChannels,
[w1](DirectParams &params) -> void
{ NfcFilterCreate(&params.NFCtrlFilter, 0.0f, w1); }
);
}
}
}
);
srclock.unlock();
context->PropsClean.test_and_set(std::memory_order_release);
@ -2592,11 +2591,12 @@ ALCcontext_struct::~ALCcontext_struct()
}
TRACE("Freed " SZFMT " voice property object%s\n", count, (count==1)?"":"s");
for(ALsizei i{0};i < VoiceCount;i++)
DeinitVoice(Voices[i]);
std::for_each(Voices, Voices + VoiceCount.load(std::memory_order_relaxed),
[](ALvoice *voice) -> void { DeinitVoice(voice); }
);
al_free(Voices);
Voices = nullptr;
VoiceCount = 0;
VoiceCount.store(0, std::memory_order_relaxed);
MaxVoices = 0;
struct ALlistenerProps *lprops{Listener.Update.load(std::memory_order_relaxed)};
@ -2747,15 +2747,8 @@ ALCcontext *GetContextRef(void)
void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends)
{
ALCdevice *device = context->Device;
ALsizei num_sends = device->NumAuxSends;
struct ALvoiceProps *props;
size_t sizeof_props;
size_t sizeof_voice;
ALvoice **voices;
ALvoice *voice;
ALsizei v = 0;
size_t size;
ALCdevice *device{context->Device};
ALsizei num_sends{device->NumAuxSends};
if(num_voices == context->MaxVoices && num_sends == old_sends)
return;
@ -2764,53 +2757,54 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends)
* property set (including the dynamically-sized Send[] array) in one
* chunk.
*/
sizeof_voice = RoundUp(FAM_SIZE(ALvoice, Send, num_sends), 16);
sizeof_props = RoundUp(FAM_SIZE(struct ALvoiceProps, Send, num_sends), 16);
size = sizeof(ALvoice*) + sizeof_voice + sizeof_props;
size_t sizeof_voice{RoundUp(FAM_SIZE(ALvoice, Send, num_sends), 16)};
size_t sizeof_props{RoundUp(FAM_SIZE(struct ALvoiceProps, Send, num_sends), 16)};
size_t size{sizeof(ALvoice*) + sizeof_voice + sizeof_props};
voices = static_cast<ALvoice**>(al_calloc(16, RoundUp(size*num_voices, 16)));
auto voices = static_cast<ALvoice**>(al_calloc(16, RoundUp(size*num_voices, 16)));
/* The voice and property objects are stored interleaved since they're
* paired together.
*/
voice = (ALvoice*)((char*)voices + RoundUp(num_voices*sizeof(ALvoice*), 16));
props = (struct ALvoiceProps*)((char*)voice + sizeof_voice);
auto voice = reinterpret_cast<ALvoice*>((char*)voices + RoundUp(num_voices*sizeof(ALvoice*), 16));
auto props = reinterpret_cast<ALvoiceProps*>((char*)voice + sizeof_voice);
ALsizei v{0};
if(context->Voices)
{
const ALsizei v_count = mini(context->VoiceCount, num_voices);
const ALsizei v_count = mini(context->VoiceCount.load(std::memory_order_relaxed),
num_voices);
const ALsizei s_count = mini(old_sends, num_sends);
for(;v < v_count;v++)
{
ALvoice *old_voice = context->Voices[v];
ALsizei i;
ALvoice *old_voice{context->Voices[v]};
/* Copy the old voice data and source property set to the new
* storage.
*/
memcpy(voice, old_voice, sizeof(*voice));
for(i = 0;i < s_count;i++)
voice->Send[i] = old_voice->Send[i];
std::copy_n(old_voice->Send, s_count, voice->Send);
memcpy(props, old_voice->Props, sizeof(*props));
for(i = 0;i < s_count;i++)
props->Send[i] = old_voice->Props->Send[i];
std::copy_n(old_voice->Props->Send, s_count, props->Send);
/* Set this voice's property set pointer and voice reference. */
voice->Props = props;
voices[v] = voice;
/* Increment pointers to the next storage space. */
voice = (ALvoice*)((char*)props + sizeof_props);
props = (struct ALvoiceProps*)((char*)voice + sizeof_voice);
voice = reinterpret_cast<ALvoice*>((char*)props + sizeof_props);
props = reinterpret_cast<ALvoiceProps*>((char*)voice + sizeof_voice);
}
/* Deinit any left over voices that weren't copied over to the new
* array. NOTE: If this does anything, v equals num_voices and
* num_voices is less than VoiceCount, so the following loop won't do
* anything.
*/
for(;v < context->VoiceCount;v++)
DeinitVoice(context->Voices[v]);
auto voices_end = context->Voices + context->VoiceCount.load(std::memory_order_relaxed);
std::for_each(context->Voices + v, voices_end,
[](ALvoice *voice) -> void { DeinitVoice(voice); }
);
}
/* Finish setting the voices' property set pointers and references. */
for(;v < num_voices;v++)
@ -2820,14 +2814,14 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends)
voice->Props = props;
voices[v] = voice;
voice = (ALvoice*)((char*)props + sizeof_props);
props = (struct ALvoiceProps*)((char*)voice + sizeof_voice);
voice = reinterpret_cast<ALvoice*>((char*)props + sizeof_props);
props = reinterpret_cast<ALvoiceProps*>((char*)voice + sizeof_voice);
}
al_free(context->Voices);
context->Voices = voices;
context->MaxVoices = num_voices;
context->VoiceCount = mini(context->VoiceCount, num_voices);
context->VoiceCount = mini(context->VoiceCount.load(std::memory_order_relaxed), num_voices);
}

View File

@ -95,7 +95,7 @@ struct ALCcontext_struct {
ATOMIC(ALeffectslotProps*) FreeEffectslotProps{nullptr};
ALvoice **Voices{nullptr};
ALsizei VoiceCount{0};
std::atomic<ALsizei> VoiceCount{0};
ALsizei MaxVoices{0};
ATOMIC(ALeffectslotArray*) ActiveAuxSlots{nullptr};

View File

@ -1503,7 +1503,7 @@ void ProcessParamUpdates(ALCcontext *ctx, const ALeffectslotArray *slots)
{ force |= CalcEffectSlotParams(slot, ctx, cforce); }
);
std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount,
std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount.load(std::memory_order_acquire),
[ctx,force](ALvoice *voice) -> void
{
ALsource *source{voice->Source.load(std::memory_order_acquire)};
@ -1533,7 +1533,7 @@ void ProcessContext(ALCcontext *ctx, ALsizei SamplesToDo)
);
/* Process voices that have a playing source. */
std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount,
std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount.load(std::memory_order_acquire),
[SamplesToDo,ctx](ALvoice *voice) -> void
{
ALsource *source{voice->Source.load(std::memory_order_acquire)};
@ -1859,7 +1859,7 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...)
ll_ringbuffer_write(ctx->AsyncEvents, &evt, 1) == 1)
alsem_post(&ctx->EventSem);
std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount,
std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount.load(std::memory_order_acquire),
[ctx](ALvoice *voice) -> void
{
ALsource *source{voice->Source.exchange(nullptr, std::memory_order_relaxed)};

View File

@ -51,7 +51,7 @@ namespace {
inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context)
{
ALint idx{source->VoiceIdx};
if(idx >= 0 && idx < context->VoiceCount)
if(idx >= 0 && idx < context->VoiceCount.load(std::memory_order_relaxed))
{
ALvoice *voice{context->Voices[idx]};
if(voice->Source.load(std::memory_order_acquire) == source)
@ -2725,7 +2725,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
return;
}
while(n > context->MaxVoices-context->VoiceCount)
while(n > context->MaxVoices-context->VoiceCount.load(std::memory_order_relaxed))
{
ALsizei newcount = context->MaxVoices << 1;
if(context->MaxVoices >= newcount)
@ -2790,19 +2790,15 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
/* Look for an unused voice to play this source with. */
assert(voice == nullptr);
ALint vidx{-1};
for(ALsizei j{0};j < context->VoiceCount;j++)
{
if(context->Voices[j]->Source.load(std::memory_order_acquire) == nullptr)
{
vidx = j;
break;
}
}
if(vidx == -1)
vidx = context->VoiceCount++;
voice = context->Voices[vidx];
auto voices_end = context->Voices + context->VoiceCount.load(std::memory_order_relaxed);
auto voice_iter = std::find_if(context->Voices, voices_end,
[](const ALvoice *voice) noexcept -> bool
{ return voice->Source.load(std::memory_order_relaxed) == nullptr; }
);
auto vidx = static_cast<ALint>(std::distance(context->Voices, voice_iter));
voice = *voice_iter;
voice->Playing.store(false, std::memory_order_release);
if(voice_iter == voices_end) context->VoiceCount.fetch_add(1, std::memory_order_acq_rel);
source->PropsClean.test_and_set(std::memory_order_acquire);
UpdateSourceProps(source, voice, context.get());
@ -2823,19 +2819,20 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
voice->position_fraction.load(std::memory_order_relaxed) != 0 ||
voice->current_buffer.load(std::memory_order_relaxed) != BufferList;
for(ALsizei j{0};j < BufferList->num_buffers;j++)
auto buffers_end = BufferList->buffers + BufferList->num_buffers;
auto buffer = std::find_if(BufferList->buffers, buffers_end,
[](const ALbuffer *buffer) noexcept -> bool
{ return buffer != nullptr; }
);
if(buffer != buffers_end)
{
ALbuffer *buffer = BufferList->buffers[j];
if(buffer)
{
voice->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
voice->SampleSize = BytesFromFmt(buffer->FmtType);
break;
}
voice->NumChannels = ChannelsFromFmt((*buffer)->FmtChannels);
voice->SampleSize = BytesFromFmt((*buffer)->FmtType);
}
/* Clear previous samples. */
memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
for(auto &samples : voice->PrevSamples)
std::fill(std::begin(samples), std::end(samples), 0.0f);
/* Clear the stepping value so the mixer knows not to mix this until
* the update gets applied.
@ -3399,13 +3396,15 @@ ALsource::~ALsource()
void UpdateAllSourceProps(ALCcontext *context)
{
for(ALsizei i{0};i < context->VoiceCount;++i)
{
ALvoice *voice{context->Voices[i]};
ALsource *source{voice->Source.load(std::memory_order_acquire)};
if(source && !source->PropsClean.test_and_set(std::memory_order_acq_rel))
UpdateSourceProps(source, voice, context);
}
auto voices_end = context->Voices + context->VoiceCount.load(std::memory_order_relaxed);
std::for_each(context->Voices, voices_end,
[context](ALvoice *voice) -> void
{
ALsource *source{voice->Source.load(std::memory_order_acquire)};
if(source && !source->PropsClean.test_and_set(std::memory_order_acq_rel))
UpdateSourceProps(source, voice, context);
}
);
}
/* ReleaseALSources