First Commit
This commit is contained in:
164
externals/openal-soft/core/context.cpp
vendored
Normal file
164
externals/openal-soft/core/context.cpp
vendored
Normal file
@@ -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();
|
||||
}
|
||||
Reference in New Issue
Block a user