diff options
author | Sven Gothel <[email protected]> | 2023-05-03 16:17:49 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2023-05-03 16:17:49 +0200 |
commit | ec167fd05661a5b02dd406c87081f84a0f8dd77d (patch) | |
tree | 9c4669e471c9969bda59265381b18d2d416db060 /core/context.cpp | |
parent | 0d14d30808cfe7b9e3413353e3eef8a0f201399a (diff) | |
parent | d3875f333fb6abe2f39d82caca329414871ae53b (diff) |
Merge branch 'v1.23.1'
Resolved Conflicts:
CMakeLists.txt
Diffstat (limited to 'core/context.cpp')
-rw-r--r-- | core/context.cpp | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/core/context.cpp b/core/context.cpp new file mode 100644 index 00000000..d68d8327 --- /dev/null +++ b/core/context.cpp @@ -0,0 +1,164 @@ + +#include "config.h" + +#include <cassert> +#include <memory> + +#include "async_event.h" +#include "context.h" +#include "device.h" +#include "effectslot.h" +#include "logging.h" +#include "ringbuffer.h" +#include "voice.h" +#include "voice_change.h" + + +#ifdef __cpp_lib_atomic_is_always_lock_free +static_assert(std::atomic<ContextBase::AsyncEventBitset>::is_always_lock_free, "atomic<bitset> isn't lock-free"); +#endif + +ContextBase::ContextBase(DeviceBase *device) : mDevice{device} +{ assert(mEnabledEvts.is_lock_free()); } + +ContextBase::~ContextBase() +{ + size_t count{0}; + ContextProps *cprops{mParams.ContextUpdate.exchange(nullptr, std::memory_order_relaxed)}; + if(cprops) + { + ++count; + delete cprops; + } + cprops = mFreeContextProps.exchange(nullptr, std::memory_order_acquire); + while(cprops) + { + std::unique_ptr<ContextProps> old{cprops}; + cprops = old->next.load(std::memory_order_relaxed); + ++count; + } + TRACE("Freed %zu context property object%s\n", count, (count==1)?"":"s"); + + count = 0; + EffectSlotProps *eprops{mFreeEffectslotProps.exchange(nullptr, std::memory_order_acquire)}; + while(eprops) + { + std::unique_ptr<EffectSlotProps> old{eprops}; + eprops = old->next.load(std::memory_order_relaxed); + ++count; + } + TRACE("Freed %zu AuxiliaryEffectSlot property object%s\n", count, (count==1)?"":"s"); + + if(EffectSlotArray *curarray{mActiveAuxSlots.exchange(nullptr, std::memory_order_relaxed)}) + { + al::destroy_n(curarray->end(), curarray->size()); + delete curarray; + } + + delete mVoices.exchange(nullptr, std::memory_order_relaxed); + + if(mAsyncEvents) + { + count = 0; + auto evt_vec = mAsyncEvents->getReadVector(); + if(evt_vec.first.len > 0) + { + al::destroy_n(reinterpret_cast<AsyncEvent*>(evt_vec.first.buf), evt_vec.first.len); + count += evt_vec.first.len; + } + if(evt_vec.second.len > 0) + { + al::destroy_n(reinterpret_cast<AsyncEvent*>(evt_vec.second.buf), evt_vec.second.len); + count += evt_vec.second.len; + } + if(count > 0) + TRACE("Destructed %zu orphaned event%s\n", count, (count==1)?"":"s"); + mAsyncEvents->readAdvance(count); + } +} + + +void ContextBase::allocVoiceChanges() +{ + constexpr size_t clustersize{128}; + + VoiceChangeCluster cluster{std::make_unique<VoiceChange[]>(clustersize)}; + for(size_t i{1};i < clustersize;++i) + cluster[i-1].mNext.store(std::addressof(cluster[i]), std::memory_order_relaxed); + cluster[clustersize-1].mNext.store(mVoiceChangeTail, std::memory_order_relaxed); + + mVoiceChangeClusters.emplace_back(std::move(cluster)); + mVoiceChangeTail = mVoiceChangeClusters.back().get(); +} + +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<VoicePropsItem[]>(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}; + /* Convert element count to cluster count. */ + addcount = (addcount+(clustersize-1)) / clustersize; + + if(addcount >= std::numeric_limits<int>::max()/clustersize - mVoiceClusters.size()) + throw std::runtime_error{"Allocating too many voices"}; + const size_t totalcount{(mVoiceClusters.size()+addcount) * clustersize}; + TRACE("Increasing allocated voices to %zu\n", totalcount); + + auto newarray = VoiceArray::Create(totalcount); + while(addcount) + { + mVoiceClusters.emplace_back(std::make_unique<Voice[]>(clustersize)); + --addcount; + } + + auto voice_iter = newarray->begin(); + for(VoiceCluster &cluster : mVoiceClusters) + { + for(size_t i{0};i < clustersize;++i) + *(voice_iter++) = &cluster[i]; + } + + if(auto *oldvoices = mVoices.exchange(newarray.release(), std::memory_order_acq_rel)) + { + mDevice->waitForMix(); + delete oldvoices; + } +} + + +EffectSlot *ContextBase::getEffectSlot() +{ + for(auto& cluster : mEffectSlotClusters) + { + for(size_t i{0};i < EffectSlotClusterSize;++i) + { + if(!cluster[i].InUse) + return &cluster[i]; + } + } + + if(1 >= std::numeric_limits<int>::max()/EffectSlotClusterSize - mEffectSlotClusters.size()) + throw std::runtime_error{"Allocating too many effect slots"}; + const size_t totalcount{(mEffectSlotClusters.size()+1) * EffectSlotClusterSize}; + TRACE("Increasing allocated effect slots to %zu\n", totalcount); + + mEffectSlotClusters.emplace_back(std::make_unique<EffectSlot[]>(EffectSlotClusterSize)); + return getEffectSlot(); +} |