7 #include "async_event.h"
10 #include "effectslot.h"
12 #include "ringbuffer.h"
14 #include "voice_change.h"
17 #ifdef __cpp_lib_atomic_is_always_lock_free
18 static_assert(std::atomic<ContextBase::AsyncEventBitset>::is_always_lock_free, "atomic<bitset> isn't lock-free");
21 ContextBase::ContextBase(DeviceBase *device) : mDevice{device}
22 { assert(mEnabledEvts.is_lock_free()); }
24 ContextBase::~ContextBase()
27 ContextProps *cprops{mParams.ContextUpdate.exchange(nullptr, std::memory_order_relaxed)};
33 cprops = mFreeContextProps.exchange(nullptr, std::memory_order_acquire);
36 std::unique_ptr<ContextProps> old{cprops};
37 cprops = old->next.load(std::memory_order_relaxed);
40 TRACE("Freed %zu context property object%s\n", count, (count==1)?"":"s");
43 EffectSlotProps *eprops{mFreeEffectslotProps.exchange(nullptr, std::memory_order_acquire)};
46 std::unique_ptr<EffectSlotProps> old{eprops};
47 eprops = old->next.load(std::memory_order_relaxed);
50 TRACE("Freed %zu AuxiliaryEffectSlot property object%s\n", count, (count==1)?"":"s");
52 if(EffectSlotArray *curarray{mActiveAuxSlots.exchange(nullptr, std::memory_order_relaxed)})
54 al::destroy_n(curarray->end(), curarray->size());
58 delete mVoices.exchange(nullptr, std::memory_order_relaxed);
63 auto evt_vec = mAsyncEvents->getReadVector();
64 if(evt_vec.first.len > 0)
66 al::destroy_n(reinterpret_cast<AsyncEvent*>(evt_vec.first.buf), evt_vec.first.len);
67 count += evt_vec.first.len;
69 if(evt_vec.second.len > 0)
71 al::destroy_n(reinterpret_cast<AsyncEvent*>(evt_vec.second.buf), evt_vec.second.len);
72 count += evt_vec.second.len;
75 TRACE("Destructed %zu orphaned event%s\n", count, (count==1)?"":"s");
76 mAsyncEvents->readAdvance(count);
81 void ContextBase::allocVoiceChanges()
83 constexpr size_t clustersize{128};
85 VoiceChangeCluster cluster{std::make_unique<VoiceChange[]>(clustersize)};
86 for(size_t i{1};i < clustersize;++i)
87 cluster[i-1].mNext.store(std::addressof(cluster[i]), std::memory_order_relaxed);
88 cluster[clustersize-1].mNext.store(mVoiceChangeTail, std::memory_order_relaxed);
90 mVoiceChangeClusters.emplace_back(std::move(cluster));
91 mVoiceChangeTail = mVoiceChangeClusters.back().get();
94 void ContextBase::allocVoiceProps()
96 constexpr size_t clustersize{32};
98 TRACE("Increasing allocated voice properties to %zu\n",
99 (mVoicePropClusters.size()+1) * clustersize);
101 VoicePropsCluster cluster{std::make_unique<VoicePropsItem[]>(clustersize)};
102 for(size_t i{1};i < clustersize;++i)
103 cluster[i-1].next.store(std::addressof(cluster[i]), std::memory_order_relaxed);
104 mVoicePropClusters.emplace_back(std::move(cluster));
106 VoicePropsItem *oldhead{mFreeVoiceProps.load(std::memory_order_acquire)};
108 mVoicePropClusters.back()[clustersize-1].next.store(oldhead, std::memory_order_relaxed);
109 } while(mFreeVoiceProps.compare_exchange_weak(oldhead, mVoicePropClusters.back().get(),
110 std::memory_order_acq_rel, std::memory_order_acquire) == false);
113 void ContextBase::allocVoices(size_t addcount)
115 constexpr size_t clustersize{32};
116 /* Convert element count to cluster count. */
117 addcount = (addcount+(clustersize-1)) / clustersize;
119 if(addcount >= std::numeric_limits<int>::max()/clustersize - mVoiceClusters.size())
120 throw std::runtime_error{"Allocating too many voices"};
121 const size_t totalcount{(mVoiceClusters.size()+addcount) * clustersize};
122 TRACE("Increasing allocated voices to %zu\n", totalcount);
124 auto newarray = VoiceArray::Create(totalcount);
127 mVoiceClusters.emplace_back(std::make_unique<Voice[]>(clustersize));
131 auto voice_iter = newarray->begin();
132 for(VoiceCluster &cluster : mVoiceClusters)
134 for(size_t i{0};i < clustersize;++i)
135 *(voice_iter++) = &cluster[i];
138 if(auto *oldvoices = mVoices.exchange(newarray.release(), std::memory_order_acq_rel))
140 mDevice->waitForMix();
146 EffectSlot *ContextBase::getEffectSlot()
148 for(auto& cluster : mEffectSlotClusters)
150 for(size_t i{0};i < EffectSlotClusterSize;++i)
152 if(!cluster[i].InUse)
157 if(1 >= std::numeric_limits<int>::max()/EffectSlotClusterSize - mEffectSlotClusters.size())
158 throw std::runtime_error{"Allocating too many effect slots"};
159 const size_t totalcount{(mEffectSlotClusters.size()+1) * EffectSlotClusterSize};
160 TRACE("Increasing allocated effect slots to %zu\n", totalcount);
162 mEffectSlotClusters.emplace_back(std::make_unique<EffectSlot[]>(EffectSlotClusterSize));
163 return getEffectSlot();