diff options
author | Chris Robinson <[email protected]> | 2019-06-09 18:13:54 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2019-06-09 18:13:54 -0700 |
commit | bc8f206ee1361ec4b6e740a458bb7985bb7d1429 (patch) | |
tree | 5705d45dbedf6af324b3430654decf8388d0bd21 | |
parent | 90d25e5187ca50a6e978603fabb6395035ad0db5 (diff) |
Use a FlexArray for the context's voices
-rw-r--r-- | Alc/alc.cpp | 145 | ||||
-rw-r--r-- | Alc/alcontext.h | 5 | ||||
-rw-r--r-- | Alc/alu.cpp | 42 | ||||
-rw-r--r-- | OpenAL32/Include/alMain.h | 2 | ||||
-rw-r--r-- | OpenAL32/Include/alu.h | 42 | ||||
-rw-r--r-- | OpenAL32/alSource.cpp | 59 | ||||
-rw-r--r-- | common/almalloc.h | 2 |
7 files changed, 143 insertions, 154 deletions
diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 0724f0ce..10c093d5 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2141,18 +2141,37 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) vprops = next; } - AllocateVoices(context, context->MaxVoices, old_sends); - auto voices_end = context->Voices + context->VoiceCount.load(std::memory_order_relaxed); - std::for_each(context->Voices, voices_end, - [device](ALvoice *voice) -> void + auto voices = context->Voices.get(); + auto voices_end = voices->begin() + context->VoiceCount.load(std::memory_order_relaxed); + if(device->NumAuxSends < old_sends) + { + const ALsizei num_sends{device->NumAuxSends}; + /* Clear extraneous property set sends. */ + auto clear_sends = [num_sends](ALvoice &voice) -> void + { + std::fill(std::begin(voice.mProps.Send)+num_sends, std::end(voice.mProps.Send), + ALvoiceProps::SendData{}); + + std::fill(voice.mSend.begin()+num_sends, voice.mSend.end(), ALvoice::SendData{}); + auto clear_chan_sends = [num_sends](ALvoice::ChannelData &chandata) -> void + { + std::fill(chandata.mWetParams.begin()+num_sends, chandata.mWetParams.end(), + SendParams{}); + }; + std::for_each(voice.mChans.begin(), voice.mChans.end(), clear_chan_sends); + }; + std::for_each(voices->begin(), voices_end, clear_sends); + } + std::for_each(voices->begin(), voices_end, + [device](ALvoice &voice) -> void { - delete voice->mUpdate.exchange(nullptr, std::memory_order_acq_rel); + delete voice.mUpdate.exchange(nullptr, std::memory_order_acq_rel); /* Force the voice to stopped if it was stopping. */ ALvoice::State vstate{ALvoice::Stopping}; - voice->mPlayState.compare_exchange_strong(vstate, ALvoice::Stopped, + voice.mPlayState.compare_exchange_strong(vstate, ALvoice::Stopped, std::memory_order_acquire, std::memory_order_acquire); - if(voice->mSourceID.load(std::memory_order_relaxed) == 0u) + if(voice.mSourceID.load(std::memory_order_relaxed) == 0u) return; if(device->AvgSpeakerDist > 0.0f) @@ -2162,7 +2181,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) (device->AvgSpeakerDist * device->Frequency)}; auto init_nfc = [w1](ALvoice::ChannelData &chandata) -> void { chandata.mDryParams.NFCtrlFilter.init(w1); }; - std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels, + std::for_each(voice.mChans.begin(), voice.mChans.begin()+voice.mNumChannels, init_nfc); } } @@ -2430,11 +2449,8 @@ ALCcontext::~ALCcontext() } TRACE("Freed %zu voice property object%s\n", count, (count==1)?"":"s"); - std::for_each(Voices, Voices + MaxVoices, DeinitVoice); - al_free(Voices); Voices = nullptr; VoiceCount.store(0, std::memory_order_relaxed); - MaxVoices = 0; ALlistenerProps *lprops{Listener.Update.exchange(nullptr, std::memory_order_relaxed)}; if(lprops) @@ -2576,109 +2592,46 @@ ContextRef GetContextRef(void) } -void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) +void AllocateVoices(ALCcontext *context, size_t num_voices) { ALCdevice *device{context->Device}; const ALsizei num_sends{device->NumAuxSends}; - if(num_voices == context->MaxVoices && num_sends == old_sends) + if(context->Voices && num_voices == context->Voices->size()) return; - /* Allocate the voice pointers, voices, and the voices' stored source - * property set (including the dynamically-sized Send[] array) in one - * chunk. - */ - const size_t sizeof_voice{RoundUp(sizeof(ALvoice), 16)}; - const size_t size{sizeof(ALvoice*) + sizeof_voice}; - - auto voices = static_cast<ALvoice**>(al_calloc(16, RoundUp(size*num_voices, 16))); - auto voice = reinterpret_cast<ALvoice*>(reinterpret_cast<char*>(voices) + RoundUp(num_voices*sizeof(ALvoice*), 16)); + std::unique_ptr<al::FlexArray<ALvoice>> voices; + { + void *ptr{al_calloc(16, al::FlexArray<ALvoice>::Sizeof(num_voices))}; + voices.reset(new (ptr) al::FlexArray<ALvoice>{num_voices}); + } - auto viter = voices; + const ALsizei v_count{mini(context->VoiceCount.load(std::memory_order_relaxed), num_voices)}; if(context->Voices) { - const ALsizei v_count = mini(context->VoiceCount.load(std::memory_order_relaxed), - num_voices); - const ALsizei s_count = mini(old_sends, num_sends); - /* Copy the old voice data to the new storage. */ - auto copy_voice = [&voice,s_count](ALvoice *old_voice) -> ALvoice* - { - voice = new (voice) ALvoice{}; - - /* Make sure the old voice's Update (if any) is cleared so it - * doesn't get deleted on deinit. - */ - voice->mUpdate.store(old_voice->mUpdate.exchange(nullptr, std::memory_order_relaxed), - std::memory_order_relaxed); + auto viter = std::move(context->Voices->begin(), context->Voices->begin()+v_count, + voices->begin()); - voice->mSourceID.store(old_voice->mSourceID.load(std::memory_order_relaxed), - std::memory_order_relaxed); - voice->mPlayState.store(old_voice->mPlayState.load(std::memory_order_relaxed), - std::memory_order_relaxed); - - voice->mProps = old_voice->mProps; - /* Clear extraneous property set sends. */ - std::fill(std::begin(voice->mProps.Send)+s_count, std::end(voice->mProps.Send), + /* Clear extraneous property set sends. */ + auto clear_sends = [num_sends](ALvoice &voice) -> void + { + std::fill(std::begin(voice.mProps.Send)+num_sends, std::end(voice.mProps.Send), ALvoiceProps::SendData{}); - voice->mPosition.store(old_voice->mPosition.load(std::memory_order_relaxed), - std::memory_order_relaxed); - voice->mPositionFrac.store(old_voice->mPositionFrac.load(std::memory_order_relaxed), - std::memory_order_relaxed); - - voice->mCurrentBuffer.store(old_voice->mCurrentBuffer.load(std::memory_order_relaxed), - std::memory_order_relaxed); - voice->mLoopBuffer.store(old_voice->mLoopBuffer.load(std::memory_order_relaxed), - std::memory_order_relaxed); - - voice->mFrequency = old_voice->mFrequency; - voice->mFmtChannels = old_voice->mFmtChannels; - voice->mNumChannels = old_voice->mNumChannels; - voice->mSampleSize = old_voice->mSampleSize; - - voice->mStep = old_voice->mStep; - voice->mResampler = old_voice->mResampler; - - voice->mResampleState = old_voice->mResampleState; - - voice->mFlags = old_voice->mFlags; - - voice->mDirect = old_voice->mDirect; - voice->mSend = old_voice->mSend; - voice->mChans = old_voice->mChans; - - /* Clear old send data/params. */ - std::fill(voice->mSend.begin()+s_count, voice->mSend.end(), ALvoice::SendData{}); - auto clear_chan_sends = [s_count](ALvoice::ChannelData &chandata) -> void + std::fill(voice.mSend.begin()+num_sends, voice.mSend.end(), ALvoice::SendData{}); + auto clear_chan_sends = [num_sends](ALvoice::ChannelData &chandata) -> void { - std::fill(chandata.mWetParams.begin()+s_count, chandata.mWetParams.end(), + std::fill(chandata.mWetParams.begin()+num_sends, chandata.mWetParams.end(), SendParams{}); }; - std::for_each(voice->mChans.begin(), voice->mChans.end(), clear_chan_sends); - - /* Set this voice's reference. */ - ALvoice *ret{voice++}; - return ret; + std::for_each(voice.mChans.begin(), voice.mChans.end(), clear_chan_sends); }; - viter = std::transform(context->Voices, context->Voices+v_count, viter, copy_voice); - - /* Deinit old voices. */ - auto voices_end = context->Voices + context->MaxVoices; - std::for_each(context->Voices, voices_end, DeinitVoice); + std::for_each(voices->begin(), viter, clear_sends); } - /* Finish setting the voices and references. */ - auto init_voice = [&voice]() -> ALvoice* - { - ALvoice *ret{new (voice++) ALvoice{}}; - return ret; - }; - std::generate(viter, voices+num_voices, init_voice); - al_free(context->Voices); - context->Voices = voices; - context->MaxVoices = num_voices; - context->VoiceCount = mini(context->VoiceCount.load(std::memory_order_relaxed), num_voices); + context->Voices = std::move(voices); + context->VoiceCount.store(v_count, std::memory_order_relaxed); } @@ -3439,7 +3392,7 @@ START_API_FUNC return nullptr; } - AllocateVoices(context.get(), 256, dev->NumAuxSends); + AllocateVoices(context.get(), 256); if(DefaultEffect.type != AL_EFFECT_NULL && dev->Type == Playback) { diff --git a/Alc/alcontext.h b/Alc/alcontext.h index 769847f8..63983ca3 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -18,6 +18,7 @@ #include "alnumeric.h" #include "alListener.h" +#include "alu.h" struct ALsource; @@ -26,7 +27,6 @@ struct ALcontextProps; struct ALlistenerProps; struct ALvoiceProps; struct ALeffectslotProps; -struct ALvoice; struct RingBuffer; enum class DistanceModel { @@ -116,9 +116,8 @@ struct ALCcontext { std::atomic<ALvoiceProps*> FreeVoiceProps{nullptr}; std::atomic<ALeffectslotProps*> FreeEffectslotProps{nullptr}; - ALvoice **Voices{nullptr}; + std::unique_ptr<al::FlexArray<ALvoice>> Voices{nullptr}; std::atomic<ALsizei> VoiceCount{0}; - ALsizei MaxVoices{0}; using ALeffectslotArray = al::FlexArray<ALeffectslot*>; std::atomic<ALeffectslotArray*> ActiveAuxSlots{nullptr}; diff --git a/Alc/alu.cpp b/Alc/alu.cpp index e570c2ad..05a6970c 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -177,13 +177,6 @@ void aluInit(void) } -void DeinitVoice(ALvoice *voice) noexcept -{ - delete voice->mUpdate.exchange(nullptr, std::memory_order_acq_rel); - al::destroy_at(voice); -} - - void aluSelectPostProcess(ALCdevice *device) { if(device->mHrtf) @@ -1359,11 +1352,12 @@ void ProcessParamUpdates(ALCcontext *ctx, const ALeffectslotArray *slots) { return CalcEffectSlotParams(slot, ctx, cforce) | force; } ); - std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount.load(std::memory_order_acquire), - [ctx,force](ALvoice *voice) -> void + std::for_each(ctx->Voices->begin(), + ctx->Voices->begin() + ctx->VoiceCount.load(std::memory_order_acquire), + [ctx,force](ALvoice &voice) -> void { - ALuint sid{voice->mSourceID.load(std::memory_order_acquire)}; - if(sid) CalcSourceParams(voice, ctx, force); + ALuint sid{voice.mSourceID.load(std::memory_order_acquire)}; + if(sid) CalcSourceParams(&voice, ctx, force); } ); } @@ -1389,15 +1383,16 @@ void ProcessContext(ALCcontext *ctx, const ALsizei SamplesToDo) ); /* Process voices that have a playing source. */ - std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount.load(std::memory_order_acquire), - [SamplesToDo,ctx](ALvoice *voice) -> void + std::for_each(ctx->Voices->begin(), + ctx->Voices->begin() + ctx->VoiceCount.load(std::memory_order_acquire), + [SamplesToDo,ctx](ALvoice &voice) -> void { - const ALvoice::State vstate{voice->mPlayState.load(std::memory_order_acquire)}; + const ALvoice::State vstate{voice.mPlayState.load(std::memory_order_acquire)}; if(vstate == ALvoice::Stopped) return; - const ALuint sid{voice->mSourceID.load(std::memory_order_relaxed)}; - if(voice->mStep < 1) return; + const ALuint sid{voice.mSourceID.load(std::memory_order_relaxed)}; + if(voice.mStep < 1) return; - MixVoice(voice, vstate, sid, ctx, SamplesToDo); + MixVoice(&voice, vstate, sid, ctx, SamplesToDo); } ); @@ -1788,14 +1783,15 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) } } - auto stop_voice = [](ALvoice *voice) -> void + auto stop_voice = [](ALvoice &voice) -> void { - voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed); - voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed); - voice->mSourceID.store(0u, std::memory_order_relaxed); - voice->mPlayState.store(ALvoice::Stopped, std::memory_order_release); + voice.mCurrentBuffer.store(nullptr, std::memory_order_relaxed); + voice.mLoopBuffer.store(nullptr, std::memory_order_relaxed); + voice.mSourceID.store(0u, std::memory_order_relaxed); + voice.mPlayState.store(ALvoice::Stopped, std::memory_order_release); }; - std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount.load(std::memory_order_acquire), + std::for_each(ctx->Voices->begin(), + ctx->Voices->begin() + ctx->VoiceCount.load(std::memory_order_acquire), stop_voice); ctx = ctx->next.load(std::memory_order_relaxed); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 9a5b3814..80167417 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -532,7 +532,7 @@ struct AsyncEvent { }; -void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends); +void AllocateVoices(ALCcontext *context, size_t num_voices); extern ALint RTPrioLevel; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 3e18f857..3135f8fd 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -278,10 +278,48 @@ struct ALvoice { ALvoice() = default; ALvoice(const ALvoice&) = delete; + ~ALvoice() { delete mUpdate.exchange(nullptr, std::memory_order_acq_rel); } ALvoice& operator=(const ALvoice&) = delete; -}; + ALvoice& operator=(ALvoice&& rhs) noexcept + { + ALvoiceProps *old_update{mUpdate.load(std::memory_order_relaxed)}; + mUpdate.store(rhs.mUpdate.exchange(old_update, std::memory_order_relaxed), + std::memory_order_relaxed); + + mSourceID.store(rhs.mSourceID.load(std::memory_order_relaxed), std::memory_order_relaxed); + mPlayState.store(rhs.mPlayState.load(std::memory_order_relaxed), + std::memory_order_relaxed); + + mProps = rhs.mProps; + + mPosition.store(rhs.mPosition.load(std::memory_order_relaxed), std::memory_order_relaxed); + mPositionFrac.store(rhs.mPositionFrac.load(std::memory_order_relaxed), + std::memory_order_relaxed); + + mCurrentBuffer.store(rhs.mCurrentBuffer.load(std::memory_order_relaxed), + std::memory_order_relaxed); + mLoopBuffer.store(rhs.mLoopBuffer.load(std::memory_order_relaxed), + std::memory_order_relaxed); + + mFmtChannels = rhs.mFmtChannels; + mFrequency = rhs.mFrequency; + mNumChannels = rhs.mNumChannels; + mSampleSize = rhs.mSampleSize; -void DeinitVoice(ALvoice *voice) noexcept; + mStep = rhs.mStep; + mResampler = rhs.mResampler; + + mResampleState = rhs.mResampleState; + + mFlags = rhs.mFlags; + + mDirect = rhs.mDirect; + mSend = rhs.mSend; + mChans = rhs.mChans; + + return *this; + } +}; using MixerFunc = void(*)(const ALfloat *data, const al::span<FloatBufferLine> OutBuffer, diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index b2878b8e..9fba7e4f 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -61,9 +61,9 @@ inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context) if(idx >= 0 && idx < context->VoiceCount.load(std::memory_order_relaxed)) { ALuint sid{source->id}; - ALvoice *voice{context->Voices[idx]}; - if(voice->mSourceID.load(std::memory_order_acquire) == sid) - return voice; + ALvoice &voice = (*context->Voices)[idx]; + if(voice.mSourceID.load(std::memory_order_acquire) == sid) + return &voice; } source->VoiceIdx = -1; return nullptr; @@ -2777,12 +2777,13 @@ START_API_FUNC } /* Count the number of reusable voices. */ - auto voices_end = context->Voices + context->VoiceCount.load(std::memory_order_relaxed); - auto free_voices = std::accumulate(context->Voices, voices_end, ALsizei{0}, - [](const ALsizei count, const ALvoice *voice) noexcept -> ALsizei + auto voices_end = context->Voices->begin() + + context->VoiceCount.load(std::memory_order_relaxed); + auto free_voices = std::accumulate(context->Voices->begin(), voices_end, ALsizei{0}, + [](const ALsizei count, const ALvoice &voice) noexcept -> ALsizei { - if(voice->mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped && - voice->mSourceID.load(std::memory_order_relaxed) == 0u) + if(voice.mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped && + voice.mSourceID.load(std::memory_order_relaxed) == 0u) return count + 1; return count; } @@ -2790,20 +2791,21 @@ START_API_FUNC if(UNLIKELY(n > free_voices)) { /* Increment the number of voices to handle the request. */ - const ALsizei need_voices{n - free_voices}; - const ALsizei rem_voices{context->MaxVoices - + const ALuint need_voices{static_cast<ALuint>(n) - free_voices}; + const size_t rem_voices{context->Voices->size() - context->VoiceCount.load(std::memory_order_relaxed)}; if(UNLIKELY(need_voices > rem_voices)) { /* Allocate more voices to get enough. */ - const ALsizei alloc_count{need_voices - rem_voices}; - if(UNLIKELY(context->MaxVoices > std::numeric_limits<ALsizei>::max()-alloc_count)) + const size_t alloc_count{need_voices - rem_voices}; + if(UNLIKELY(context->Voices->size() > std::numeric_limits<size_t>::max()-alloc_count)) SETERR_RETURN(context.get(), AL_OUT_OF_MEMORY,, - "Overflow increasing voice count to %d + %d", context->MaxVoices, alloc_count); + "Overflow increasing voice count to %zu + %zu", context->Voices->size(), + alloc_count); - const ALsizei newcount{context->MaxVoices + alloc_count}; - AllocateVoices(context.get(), newcount, device->NumAuxSends); + const size_t newcount{context->Voices->size() + alloc_count}; + AllocateVoices(context.get(), newcount); } context->VoiceCount.fetch_add(need_voices, std::memory_order_relaxed); @@ -2862,17 +2864,17 @@ START_API_FUNC } /* Look for an unused voice to play this source with. */ - 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 + auto voices_end = context->Voices->begin() + + context->VoiceCount.load(std::memory_order_relaxed); + voice = std::find_if(context->Voices->begin(), voices_end, + [](const ALvoice &voice) noexcept -> bool { - return voice->mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped && - voice->mSourceID.load(std::memory_order_relaxed) == 0u; + return voice.mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped && + voice.mSourceID.load(std::memory_order_relaxed) == 0u; } ); - assert(voice_iter != voices_end); - auto vidx = static_cast<ALint>(std::distance(context->Voices, voice_iter)); - voice = *voice_iter; + assert(voice != voices_end); + auto vidx = static_cast<ALint>(std::distance(context->Voices->begin(), voice)); voice->mPlayState.store(ALvoice::Stopped, std::memory_order_release); source->PropsClean.test_and_set(std::memory_order_acquire); @@ -3557,14 +3559,15 @@ ALsource::~ALsource() void UpdateAllSourceProps(ALCcontext *context) { - auto voices_end = context->Voices + context->VoiceCount.load(std::memory_order_relaxed); - std::for_each(context->Voices, voices_end, - [context](ALvoice *voice) -> void + auto voices_end = context->Voices->begin() + + context->VoiceCount.load(std::memory_order_relaxed); + std::for_each(context->Voices->begin(), voices_end, + [context](ALvoice &voice) -> void { - ALuint sid{voice->mSourceID.load(std::memory_order_acquire)}; + ALuint sid{voice.mSourceID.load(std::memory_order_acquire)}; ALsource *source = sid ? LookupSource(context, sid) : nullptr; if(source && !source->PropsClean.test_and_set(std::memory_order_acq_rel)) - UpdateSourceProps(source, voice, context); + UpdateSourceProps(source, &voice, context); } ); } diff --git a/common/almalloc.h b/common/almalloc.h index d50aa1dd..4bf3a281 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -175,7 +175,7 @@ struct FlexArray { const index_type mSize; - alignas(alignment) element_type mArray[]; + alignas(alignment) element_type mArray[0]; static constexpr index_type Sizeof(index_type count, index_type base=0u) noexcept { |