11 #include "async_event.h"
14 #include "effectslot.h"
16 #include "ringbuffer.h"
18 #include "voice_change.h"
21 #ifdef __cpp_lib_atomic_is_always_lock_free
22 static_assert(std::atomic
<ContextBase::AsyncEventBitset
>::is_always_lock_free
, "atomic<bitset> isn't lock-free");
25 ContextBase::ContextBase(DeviceBase
*device
) : mDevice
{device
}
26 { assert(mEnabledEvts
.is_lock_free()); }
28 ContextBase::~ContextBase()
30 mActiveAuxSlots
.store(nullptr, std::memory_order_relaxed
);
31 mVoices
.store(nullptr, std::memory_order_relaxed
);
36 for(auto &evt
: mAsyncEvents
->getReadVector())
40 std::destroy_n(std::launder(reinterpret_cast<AsyncEvent
*>(evt
.buf
)), evt
.len
);
45 TRACE("Destructed %zu orphaned event%s\n", count
, (count
==1)?"":"s");
46 mAsyncEvents
->readAdvance(count
);
51 void ContextBase::allocVoiceChanges()
53 static constexpr size_t clustersize
{std::tuple_size_v
<VoiceChangeCluster::element_type
>};
55 VoiceChangeCluster clusterptr
{std::make_unique
<VoiceChangeCluster::element_type
>()};
56 const auto cluster
= al::span
{*clusterptr
};
58 for(size_t i
{1};i
< clustersize
;++i
)
59 cluster
[i
-1].mNext
.store(std::addressof(cluster
[i
]), std::memory_order_relaxed
);
60 cluster
[clustersize
-1].mNext
.store(mVoiceChangeTail
, std::memory_order_relaxed
);
62 mVoiceChangeClusters
.emplace_back(std::move(clusterptr
));
63 mVoiceChangeTail
= mVoiceChangeClusters
.back()->data();
66 void ContextBase::allocVoiceProps()
68 static constexpr size_t clustersize
{std::tuple_size_v
<VoicePropsCluster::element_type
>};
70 TRACE("Increasing allocated voice properties to %zu\n",
71 (mVoicePropClusters
.size()+1) * clustersize
);
73 auto clusterptr
= std::make_unique
<VoicePropsCluster::element_type
>();
74 auto cluster
= al::span
{*clusterptr
};
75 for(size_t i
{1};i
< clustersize
;++i
)
76 cluster
[i
-1].next
.store(std::addressof(cluster
[i
]), std::memory_order_relaxed
);
77 mVoicePropClusters
.emplace_back(std::move(clusterptr
));
79 VoicePropsItem
*oldhead
{mFreeVoiceProps
.load(std::memory_order_acquire
)};
81 mVoicePropClusters
.back()->back().next
.store(oldhead
, std::memory_order_relaxed
);
82 } while(mFreeVoiceProps
.compare_exchange_weak(oldhead
, mVoicePropClusters
.back()->data(),
83 std::memory_order_acq_rel
, std::memory_order_acquire
) == false);
86 void ContextBase::allocVoices(size_t addcount
)
88 static constexpr size_t clustersize
{std::tuple_size_v
<VoiceCluster::element_type
>};
89 /* Convert element count to cluster count. */
90 addcount
= (addcount
+(clustersize
-1)) / clustersize
;
94 if(!mVoiceClusters
.empty())
99 if(addcount
>= std::numeric_limits
<int>::max()/clustersize
- mVoiceClusters
.size())
100 throw std::runtime_error
{"Allocating too many voices"};
101 const size_t totalcount
{(mVoiceClusters
.size()+addcount
) * clustersize
};
102 TRACE("Increasing allocated voices to %zu\n", totalcount
);
106 mVoiceClusters
.emplace_back(std::make_unique
<VoiceCluster::element_type
>());
110 auto newarray
= VoiceArray::Create(totalcount
);
111 auto voice_iter
= newarray
->begin();
112 for(VoiceCluster
&cluster
: mVoiceClusters
)
113 voice_iter
= std::transform(cluster
->begin(), cluster
->end(), voice_iter
,
114 [](Voice
&voice
) noexcept
-> Voice
* { return &voice
; });
116 if(auto oldvoices
= mVoices
.exchange(std::move(newarray
), std::memory_order_acq_rel
))
117 std::ignore
= mDevice
->waitForMix();
121 void ContextBase::allocEffectSlotProps()
123 static constexpr size_t clustersize
{std::tuple_size_v
<EffectSlotPropsCluster::element_type
>};
125 TRACE("Increasing allocated effect slot properties to %zu\n",
126 (mEffectSlotPropClusters
.size()+1) * clustersize
);
128 auto clusterptr
= std::make_unique
<EffectSlotPropsCluster::element_type
>();
129 auto cluster
= al::span
{*clusterptr
};
130 for(size_t i
{1};i
< clustersize
;++i
)
131 cluster
[i
-1].next
.store(std::addressof(cluster
[i
]), std::memory_order_relaxed
);
132 auto *newcluster
= mEffectSlotPropClusters
.emplace_back(std::move(clusterptr
)).get();
134 EffectSlotProps
*oldhead
{mFreeEffectSlotProps
.load(std::memory_order_acquire
)};
136 newcluster
->back().next
.store(oldhead
, std::memory_order_relaxed
);
137 } while(mFreeEffectSlotProps
.compare_exchange_weak(oldhead
, newcluster
->data(),
138 std::memory_order_acq_rel
, std::memory_order_acquire
) == false);
141 EffectSlot
*ContextBase::getEffectSlot()
143 for(auto& clusterptr
: mEffectSlotClusters
)
145 const auto cluster
= al::span
{*clusterptr
};
146 auto iter
= std::find_if_not(cluster
.begin(), cluster
.end(),
147 std::mem_fn(&EffectSlot::InUse
));
148 if(iter
!= cluster
.end()) return al::to_address(iter
);
151 auto clusterptr
= std::make_unique
<EffectSlotCluster::element_type
>();
152 if(1 >= std::numeric_limits
<int>::max()/clusterptr
->size() - mEffectSlotClusters
.size())
153 throw std::runtime_error
{"Allocating too many effect slots"};
154 const size_t totalcount
{(mEffectSlotClusters
.size()+1) * clusterptr
->size()};
155 TRACE("Increasing allocated effect slots to %zu\n", totalcount
);
157 mEffectSlotClusters
.emplace_back(std::move(clusterptr
));
158 return mEffectSlotClusters
.back()->data();
162 void ContextBase::allocContextProps()
164 static constexpr size_t clustersize
{std::tuple_size_v
<ContextPropsCluster::element_type
>};
166 TRACE("Increasing allocated context properties to %zu\n",
167 (mContextPropClusters
.size()+1) * clustersize
);
169 auto clusterptr
= std::make_unique
<ContextPropsCluster::element_type
>();
170 auto cluster
= al::span
{*clusterptr
};
171 for(size_t i
{1};i
< clustersize
;++i
)
172 cluster
[i
-1].next
.store(std::addressof(cluster
[i
]), std::memory_order_relaxed
);
173 auto *newcluster
= mContextPropClusters
.emplace_back(std::move(clusterptr
)).get();
175 ContextProps
*oldhead
{mFreeContextProps
.load(std::memory_order_acquire
)};
177 newcluster
->back().next
.store(oldhead
, std::memory_order_relaxed
);
178 } while(mFreeContextProps
.compare_exchange_weak(oldhead
, newcluster
->data(),
179 std::memory_order_acq_rel
, std::memory_order_acquire
) == false);