Files
openal-soft/core/context.cpp

186 lines
6.7 KiB
C++
Raw Permalink Normal View History

#include "config.h"
#include <cassert>
#include <functional>
2023-05-12 16:01:06 -07:00
#include <limits>
#include <memory>
2023-05-12 16:01:06 -07:00
#include <stdexcept>
#include <utility>
#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()
{
mActiveAuxSlots.store(nullptr, std::memory_order_relaxed);
mVoices.store(nullptr, std::memory_order_relaxed);
if(mAsyncEvents)
{
size_t count{0};
auto evt_vec = mAsyncEvents->getReadVector();
if(evt_vec.first.len > 0)
{
2023-05-24 11:56:56 -07:00
std::destroy_n(std::launder(reinterpret_cast<AsyncEvent*>(evt_vec.first.buf)),
evt_vec.first.len);
count += evt_vec.first.len;
}
if(evt_vec.second.len > 0)
{
2023-05-24 11:56:56 -07:00
std::destroy_n(std::launder(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()
{
2023-12-08 12:23:54 -08:00
static constexpr size_t clustersize{std::tuple_size_v<VoiceChangeCluster::element_type>};
VoiceChangeCluster clusterptr{std::make_unique<VoiceChangeCluster::element_type>()};
const auto cluster = al::span{*clusterptr};
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(clusterptr));
mVoiceChangeTail = mVoiceChangeClusters.back()->data();
}
void ContextBase::allocVoiceProps()
{
2023-12-08 12:23:54 -08:00
static constexpr size_t clustersize{std::tuple_size_v<VoicePropsCluster::element_type>};
TRACE("Increasing allocated voice properties to %zu\n",
(mVoicePropClusters.size()+1) * clustersize);
2023-12-08 12:23:54 -08:00
auto clusterptr = std::make_unique<VoicePropsCluster::element_type>();
auto cluster = al::span{*clusterptr};
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(clusterptr));
VoicePropsItem *oldhead{mFreeVoiceProps.load(std::memory_order_acquire)};
do {
mVoicePropClusters.back()->back().next.store(oldhead, std::memory_order_relaxed);
} while(mFreeVoiceProps.compare_exchange_weak(oldhead, mVoicePropClusters.back()->data(),
std::memory_order_acq_rel, std::memory_order_acquire) == false);
}
void ContextBase::allocVoices(size_t addcount)
{
2023-12-08 12:23:54 -08:00
static constexpr size_t clustersize{std::tuple_size_v<VoiceCluster::element_type>};
/* Convert element count to cluster count. */
addcount = (addcount+(clustersize-1)) / clustersize;
if(!addcount)
{
if(!mVoiceClusters.empty())
return;
++addcount;
}
2023-12-08 12:23:54 -08:00
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);
while(addcount)
{
2023-12-08 12:23:54 -08:00
mVoiceClusters.emplace_back(std::make_unique<VoiceCluster::element_type>());
--addcount;
}
auto newarray = VoiceArray::Create(totalcount);
auto voice_iter = newarray->begin();
for(VoiceCluster &cluster : mVoiceClusters)
voice_iter = std::transform(cluster->begin(), cluster->end(), voice_iter,
[](Voice &voice) noexcept -> Voice* { return &voice; });
if(auto oldvoices = mVoices.exchange(std::move(newarray), std::memory_order_acq_rel))
2023-12-08 10:11:08 -08:00
std::ignore = mDevice->waitForMix();
}
2022-07-15 06:14:25 -07:00
void ContextBase::allocEffectSlotProps()
{
static constexpr size_t clustersize{std::tuple_size_v<EffectSlotPropsCluster::element_type>};
TRACE("Increasing allocated effect slot properties to %zu\n",
(mEffectSlotPropClusters.size()+1) * clustersize);
auto clusterptr = std::make_unique<EffectSlotPropsCluster::element_type>();
auto cluster = al::span{*clusterptr};
for(size_t i{1};i < clustersize;++i)
cluster[i-1].next.store(std::addressof(cluster[i]), std::memory_order_relaxed);
auto *newcluster = mEffectSlotPropClusters.emplace_back(std::move(clusterptr)).get();
EffectSlotProps *oldhead{mFreeEffectSlotProps.load(std::memory_order_acquire)};
do {
newcluster->back().next.store(oldhead, std::memory_order_relaxed);
} while(mFreeEffectSlotProps.compare_exchange_weak(oldhead, newcluster->data(),
std::memory_order_acq_rel, std::memory_order_acquire) == false);
}
2022-07-15 06:14:25 -07:00
EffectSlot *ContextBase::getEffectSlot()
{
for(auto& clusterptr : mEffectSlotClusters)
2022-07-15 06:14:25 -07:00
{
const auto cluster = al::span{*clusterptr};
auto iter = std::find_if_not(cluster.begin(), cluster.end(),
std::mem_fn(&EffectSlot::InUse));
if(iter != cluster.end()) return al::to_address(iter);
2022-07-15 06:14:25 -07:00
}
auto clusterptr = std::make_unique<EffectSlotCluster::element_type>();
if(1 >= std::numeric_limits<int>::max()/clusterptr->size() - mEffectSlotClusters.size())
2022-07-15 06:14:25 -07:00
throw std::runtime_error{"Allocating too many effect slots"};
const size_t totalcount{(mEffectSlotClusters.size()+1) * clusterptr->size()};
2022-07-15 06:14:25 -07:00
TRACE("Increasing allocated effect slots to %zu\n", totalcount);
mEffectSlotClusters.emplace_back(std::move(clusterptr));
return mEffectSlotClusters.back()->data();
2022-07-15 06:14:25 -07:00
}
void ContextBase::allocContextProps()
{
static constexpr size_t clustersize{std::tuple_size_v<ContextPropsCluster::element_type>};
TRACE("Increasing allocated context properties to %zu\n",
(mContextPropClusters.size()+1) * clustersize);
auto clusterptr = std::make_unique<ContextPropsCluster::element_type>();
auto cluster = al::span{*clusterptr};
for(size_t i{1};i < clustersize;++i)
cluster[i-1].next.store(std::addressof(cluster[i]), std::memory_order_relaxed);
auto *newcluster = mContextPropClusters.emplace_back(std::move(clusterptr)).get();
ContextProps *oldhead{mFreeContextProps.load(std::memory_order_acquire)};
do {
newcluster->back().next.store(oldhead, std::memory_order_relaxed);
} while(mFreeContextProps.compare_exchange_weak(oldhead, newcluster->data(),
std::memory_order_acq_rel, std::memory_order_acquire) == false);
}