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 auto evt_vec
= mAsyncEvents
->getReadVector();
37 if(evt_vec
.first
.len
> 0)
39 std::destroy_n(std::launder(reinterpret_cast<AsyncEvent
*>(evt_vec
.first
.buf
)),
41 count
+= evt_vec
.first
.len
;
43 if(evt_vec
.second
.len
> 0)
45 std::destroy_n(std::launder(reinterpret_cast<AsyncEvent
*>(evt_vec
.second
.buf
)),
47 count
+= evt_vec
.second
.len
;
50 TRACE("Destructed %zu orphaned event%s\n", count
, (count
==1)?"":"s");
51 mAsyncEvents
->readAdvance(count
);
56 void ContextBase::allocVoiceChanges()
58 static constexpr size_t clustersize
{std::tuple_size_v
<VoiceChangeCluster::element_type
>};
60 VoiceChangeCluster clusterptr
{std::make_unique
<VoiceChangeCluster::element_type
>()};
61 const auto cluster
= al::span
{*clusterptr
};
63 for(size_t i
{1};i
< clustersize
;++i
)
64 cluster
[i
-1].mNext
.store(std::addressof(cluster
[i
]), std::memory_order_relaxed
);
65 cluster
[clustersize
-1].mNext
.store(mVoiceChangeTail
, std::memory_order_relaxed
);
67 mVoiceChangeClusters
.emplace_back(std::move(clusterptr
));
68 mVoiceChangeTail
= mVoiceChangeClusters
.back()->data();
71 void ContextBase::allocVoiceProps()
73 static constexpr size_t clustersize
{std::tuple_size_v
<VoicePropsCluster::element_type
>};
75 TRACE("Increasing allocated voice properties to %zu\n",
76 (mVoicePropClusters
.size()+1) * clustersize
);
78 auto clusterptr
= std::make_unique
<VoicePropsCluster::element_type
>();
79 auto cluster
= al::span
{*clusterptr
};
80 for(size_t i
{1};i
< clustersize
;++i
)
81 cluster
[i
-1].next
.store(std::addressof(cluster
[i
]), std::memory_order_relaxed
);
82 mVoicePropClusters
.emplace_back(std::move(clusterptr
));
84 VoicePropsItem
*oldhead
{mFreeVoiceProps
.load(std::memory_order_acquire
)};
86 mVoicePropClusters
.back()->back().next
.store(oldhead
, std::memory_order_relaxed
);
87 } while(mFreeVoiceProps
.compare_exchange_weak(oldhead
, mVoicePropClusters
.back()->data(),
88 std::memory_order_acq_rel
, std::memory_order_acquire
) == false);
91 void ContextBase::allocVoices(size_t addcount
)
93 static constexpr size_t clustersize
{std::tuple_size_v
<VoiceCluster::element_type
>};
94 /* Convert element count to cluster count. */
95 addcount
= (addcount
+(clustersize
-1)) / clustersize
;
99 if(!mVoiceClusters
.empty())
104 if(addcount
>= std::numeric_limits
<int>::max()/clustersize
- mVoiceClusters
.size())
105 throw std::runtime_error
{"Allocating too many voices"};
106 const size_t totalcount
{(mVoiceClusters
.size()+addcount
) * clustersize
};
107 TRACE("Increasing allocated voices to %zu\n", totalcount
);
111 mVoiceClusters
.emplace_back(std::make_unique
<VoiceCluster::element_type
>());
115 auto newarray
= VoiceArray::Create(totalcount
);
116 auto voice_iter
= newarray
->begin();
117 for(VoiceCluster
&cluster
: mVoiceClusters
)
118 voice_iter
= std::transform(cluster
->begin(), cluster
->end(), voice_iter
,
119 [](Voice
&voice
) noexcept
-> Voice
* { return &voice
; });
121 if(auto oldvoices
= mVoices
.exchange(std::move(newarray
), std::memory_order_acq_rel
))
122 std::ignore
= mDevice
->waitForMix();
126 void ContextBase::allocEffectSlotProps()
128 static constexpr size_t clustersize
{std::tuple_size_v
<EffectSlotPropsCluster::element_type
>};
130 TRACE("Increasing allocated effect slot properties to %zu\n",
131 (mEffectSlotPropClusters
.size()+1) * clustersize
);
133 auto clusterptr
= std::make_unique
<EffectSlotPropsCluster::element_type
>();
134 auto cluster
= al::span
{*clusterptr
};
135 for(size_t i
{1};i
< clustersize
;++i
)
136 cluster
[i
-1].next
.store(std::addressof(cluster
[i
]), std::memory_order_relaxed
);
137 auto *newcluster
= mEffectSlotPropClusters
.emplace_back(std::move(clusterptr
)).get();
139 EffectSlotProps
*oldhead
{mFreeEffectSlotProps
.load(std::memory_order_acquire
)};
141 newcluster
->back().next
.store(oldhead
, std::memory_order_relaxed
);
142 } while(mFreeEffectSlotProps
.compare_exchange_weak(oldhead
, newcluster
->data(),
143 std::memory_order_acq_rel
, std::memory_order_acquire
) == false);
146 EffectSlot
*ContextBase::getEffectSlot()
148 for(auto& clusterptr
: mEffectSlotClusters
)
150 const auto cluster
= al::span
{*clusterptr
};
151 auto iter
= std::find_if_not(cluster
.begin(), cluster
.end(),
152 std::mem_fn(&EffectSlot::InUse
));
153 if(iter
!= cluster
.end()) return al::to_address(iter
);
156 auto clusterptr
= std::make_unique
<EffectSlotCluster::element_type
>();
157 if(1 >= std::numeric_limits
<int>::max()/clusterptr
->size() - mEffectSlotClusters
.size())
158 throw std::runtime_error
{"Allocating too many effect slots"};
159 const size_t totalcount
{(mEffectSlotClusters
.size()+1) * clusterptr
->size()};
160 TRACE("Increasing allocated effect slots to %zu\n", totalcount
);
162 mEffectSlotClusters
.emplace_back(std::move(clusterptr
));
163 return mEffectSlotClusters
.back()->data();
167 void ContextBase::allocContextProps()
169 static constexpr size_t clustersize
{std::tuple_size_v
<ContextPropsCluster::element_type
>};
171 TRACE("Increasing allocated context properties to %zu\n",
172 (mContextPropClusters
.size()+1) * clustersize
);
174 auto clusterptr
= std::make_unique
<ContextPropsCluster::element_type
>();
175 auto cluster
= al::span
{*clusterptr
};
176 for(size_t i
{1};i
< clustersize
;++i
)
177 cluster
[i
-1].next
.store(std::addressof(cluster
[i
]), std::memory_order_relaxed
);
178 auto *newcluster
= mContextPropClusters
.emplace_back(std::move(clusterptr
)).get();
180 ContextProps
*oldhead
{mFreeContextProps
.load(std::memory_order_acquire
)};
182 newcluster
->back().next
.store(oldhead
, std::memory_order_relaxed
);
183 } while(mFreeContextProps
.compare_exchange_weak(oldhead
, newcluster
->data(),
184 std::memory_order_acq_rel
, std::memory_order_acquire
) == false);