From c9537abfb1a9d1c94d6bf9aa0e6cfa2cda1ae94b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 17 Dec 2021 04:07:00 -0800 Subject: [PATCH] Allocate voice properties in clusters --- al/source.cpp | 14 +++++++------- alc/alc.cpp | 21 ++++++++------------- alc/context.cpp | 29 +++++++++++++++++++---------- core/context.h | 4 ++++ core/voice.h | 2 +- 5 files changed, 39 insertions(+), 31 deletions(-) diff --git a/al/source.cpp b/al/source.cpp index 4a2aaf35..cf95f7a4 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -100,15 +100,15 @@ void UpdateSourceProps(const ALsource *source, Voice *voice, ALCcontext *context /* Get an unused property container, or allocate a new one as needed. */ VoicePropsItem *props{context->mFreeVoiceProps.load(std::memory_order_acquire)}; if(!props) - props = new VoicePropsItem{}; - else { - VoicePropsItem *next; - do { - next = props->next.load(std::memory_order_relaxed); - } while(context->mFreeVoiceProps.compare_exchange_weak(props, next, - std::memory_order_acq_rel, std::memory_order_acquire) == 0); + context->allocVoiceProps(); + props = context->mFreeVoiceProps.load(std::memory_order_acquire); } + VoicePropsItem *next; + do { + next = props->next.load(std::memory_order_relaxed); + } while(unlikely(context->mFreeVoiceProps.compare_exchange_weak(props, next, + std::memory_order_acq_rel, std::memory_order_acquire) == false)); props->Pitch = source->Pitch; props->Gain = source->Gain; diff --git a/alc/alc.cpp b/alc/alc.cpp index 54162d14..89c836d0 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -2082,18 +2082,6 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList) } } - /* Clear any pre-existing voice property structs, in case the number of - * auxiliary sends is changing. Active sources will have updates - * respecified in UpdateAllSourceProps. - */ - VoicePropsItem *vprops{context->mFreeVoiceProps.exchange(nullptr, std::memory_order_acq_rel)}; - while(vprops) - { - VoicePropsItem *next = vprops->next.load(std::memory_order_relaxed); - delete vprops; - vprops = next; - } - auto voicelist = context->getVoicesSpan(); for(Voice *voice : voicelist) { @@ -2108,7 +2096,8 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList) SendParams{}); } - delete voice->mUpdate.exchange(nullptr, std::memory_order_acq_rel); + if(VoicePropsItem *props{voice->mUpdate.exchange(nullptr, std::memory_order_relaxed)}) + AtomicReplaceHead(context->mFreeVoiceProps, props); /* Force the voice to stopped if it was stopping. */ Voice::State vstate{Voice::Stopping}; @@ -2119,6 +2108,9 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList) voice->prepare(device); } + /* Clear all voice props to let them get allocated again. */ + context->mVoicePropClusters.clear(); + context->mFreeVoiceProps.store(nullptr, std::memory_order_relaxed); srclock.unlock(); context->mPropsDirty.test_and_clear(std::memory_order_release); @@ -2173,6 +2165,9 @@ bool ResetDeviceParams(ALCdevice *device, const int *attrList) vchg = next; ctx->mCurrentVoiceChange.store(vchg, std::memory_order_release); + ctx->mVoicePropClusters.clear(); + ctx->mFreeVoiceProps.store(nullptr, std::memory_order_relaxed); + ctx->mVoiceClusters.clear(); ctx->allocVoices(std::max(256, ctx->mActiveVoiceCount.load(std::memory_order_relaxed))); diff --git a/alc/context.cpp b/alc/context.cpp index a97c2a68..297d24a6 100644 --- a/alc/context.cpp +++ b/alc/context.cpp @@ -133,16 +133,6 @@ ContextBase::~ContextBase() delete curarray; } - count = 0; - VoicePropsItem *vprops{mFreeVoiceProps.exchange(nullptr, std::memory_order_acquire)}; - while(vprops) - { - std::unique_ptr old{vprops}; - vprops = old->next.load(std::memory_order_relaxed); - ++count; - } - TRACE("Freed %zu voice property object%s\n", count, (count==1)?"":"s"); - delete mVoices.exchange(nullptr, std::memory_order_relaxed); count = 0; @@ -198,6 +188,25 @@ void ContextBase::allocVoiceChanges(size_t addcount) } } +void ContextBase::allocVoiceProps() +{ + constexpr size_t clustersize{32}; + + TRACE("Increasing allocated voice properties to %zu\n", + (mVoicePropClusters.size()+1) * clustersize); + + VoicePropsCluster cluster{std::make_unique(clustersize)}; + for(size_t i{1};i < clustersize;++i) + cluster[i-1].next.store(std::addressof(cluster[i]), std::memory_order_relaxed); + mVoicePropClusters.emplace_back(std::move(cluster)); + + VoicePropsItem *oldhead{mFreeVoiceProps.load(std::memory_order_acquire)}; + do { + mVoicePropClusters.back()[clustersize-1].next.store(oldhead, std::memory_order_relaxed); + } while(mFreeVoiceProps.compare_exchange_weak(oldhead, mVoicePropClusters.back().get(), + std::memory_order_acq_rel, std::memory_order_acquire) == false); +} + void ContextBase::allocVoices(size_t addcount) { constexpr size_t clustersize{32}; diff --git a/core/context.h b/core/context.h index 155ee167..0e531db0 100644 --- a/core/context.h +++ b/core/context.h @@ -122,6 +122,7 @@ struct ContextBase { std::atomic mCurrentVoiceChange{}; void allocVoiceChanges(size_t addcount); + void allocVoiceProps(); ContextParams mParams; @@ -162,6 +163,9 @@ struct ContextBase { using VoiceCluster = std::unique_ptr; al::vector mVoiceClusters; + using VoicePropsCluster = std::unique_ptr; + al::vector mVoicePropClusters; + ContextBase(DeviceBase *device); ContextBase(const ContextBase&) = delete; diff --git a/core/voice.h b/core/voice.h index 8b5ae37f..d7168fb9 100644 --- a/core/voice.h +++ b/core/voice.h @@ -252,7 +252,7 @@ struct Voice { al::vector mChans{2}; Voice() = default; - ~Voice() { delete mUpdate.exchange(nullptr, std::memory_order_acq_rel); } + ~Voice() = default; Voice(const Voice&) = delete; Voice& operator=(const Voice&) = delete;