aboutsummaryrefslogtreecommitdiffstats
path: root/core/context.cpp
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2023-05-03 16:17:49 +0200
committerSven Gothel <[email protected]>2023-05-03 16:17:49 +0200
commitec167fd05661a5b02dd406c87081f84a0f8dd77d (patch)
tree9c4669e471c9969bda59265381b18d2d416db060 /core/context.cpp
parent0d14d30808cfe7b9e3413353e3eef8a0f201399a (diff)
parentd3875f333fb6abe2f39d82caca329414871ae53b (diff)
Merge branch 'v1.23.1'
Resolved Conflicts: CMakeLists.txt
Diffstat (limited to 'core/context.cpp')
-rw-r--r--core/context.cpp164
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();
+}