Store effect slots in groups of 64
Now that their wet buffers are allocated dynamically, the ALeffectslot object itself is rather small.
This commit is contained in:
+24
-13
@@ -2081,18 +2081,26 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
|
||||
|
||||
std::unique_lock<std::mutex> proplock{context->PropLock};
|
||||
std::unique_lock<std::mutex> slotlock{context->EffectSlotLock};
|
||||
for(auto &slot : context->EffectSlotList)
|
||||
for(auto &sublist : context->EffectSlotList)
|
||||
{
|
||||
if(!slot) continue;
|
||||
aluInitEffectPanning(slot.get());
|
||||
uint64_t usemask = ~sublist.FreeMask;
|
||||
while(usemask)
|
||||
{
|
||||
ALsizei idx = CTZ64(usemask);
|
||||
ALeffectslot *slot = sublist.EffectSlots + idx;
|
||||
|
||||
EffectState *state{slot->Effect.State};
|
||||
state->mOutBuffer = device->Dry.Buffer;
|
||||
state->mOutChannels = device->Dry.NumChannels;
|
||||
if(state->deviceUpdate(device) == AL_FALSE)
|
||||
update_failed = AL_TRUE;
|
||||
else
|
||||
UpdateEffectSlotProps(slot.get(), context);
|
||||
usemask &= ~(1_u64 << idx);
|
||||
|
||||
aluInitEffectPanning(slot);
|
||||
|
||||
EffectState *state{slot->Effect.State};
|
||||
state->mOutBuffer = device->Dry.Buffer;
|
||||
state->mOutChannels = device->Dry.NumChannels;
|
||||
if(state->deviceUpdate(device) == AL_FALSE)
|
||||
update_failed = AL_TRUE;
|
||||
else
|
||||
UpdateEffectSlotProps(slot, context);
|
||||
}
|
||||
}
|
||||
slotlock.unlock();
|
||||
|
||||
@@ -2415,12 +2423,14 @@ ALCcontext::~ALCcontext()
|
||||
delete ActiveAuxSlots.exchange(nullptr, std::memory_order_relaxed);
|
||||
DefaultSlot = nullptr;
|
||||
|
||||
count = std::count_if(EffectSlotList.cbegin(), EffectSlotList.cend(),
|
||||
[](const ALeffectslotPtr &slot) noexcept -> bool { return slot != nullptr; }
|
||||
count = std::accumulate(EffectSlotList.cbegin(), EffectSlotList.cend(), size_t{0u},
|
||||
[](size_t cur, const EffectSlotSubList &sublist) noexcept -> size_t
|
||||
{ return cur + POPCNT64(~sublist.FreeMask); }
|
||||
);
|
||||
if(count > 0)
|
||||
WARN(SZFMT " AuxiliaryEffectSlot%s not deleted\n", count, (count==1)?"":"s");
|
||||
EffectSlotList.clear();
|
||||
NumEffectSlots = 0;
|
||||
|
||||
count = 0;
|
||||
ALvoiceProps *vprops{FreeVoiceProps.exchange(nullptr, std::memory_order_acquire)};
|
||||
@@ -3440,7 +3450,8 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin
|
||||
|
||||
if(DefaultEffect.type != AL_EFFECT_NULL && dev->Type == Playback)
|
||||
{
|
||||
ALContext->DefaultSlot = al::make_unique<ALeffectslot>();
|
||||
void *ptr{al_calloc(16, sizeof(ALeffectslot))};
|
||||
ALContext->DefaultSlot = std::unique_ptr<ALeffectslot>{new (ptr) ALeffectslot{}};
|
||||
if(InitEffectSlot(ALContext->DefaultSlot.get()) == AL_NO_ERROR)
|
||||
aluInitEffectPanning(ALContext->DefaultSlot.get());
|
||||
else
|
||||
|
||||
+17
-5
@@ -56,10 +56,21 @@ struct SourceSubList {
|
||||
{ std::swap(FreeMask, rhs.FreeMask); std::swap(Sources, rhs.Sources); return *this; }
|
||||
};
|
||||
|
||||
/* Effect slots are rather large, and apps aren't likely to have more than one
|
||||
* or two (let alone 64), so hold them individually.
|
||||
*/
|
||||
using ALeffectslotPtr = std::unique_ptr<ALeffectslot>;
|
||||
struct EffectSlotSubList {
|
||||
uint64_t FreeMask{~0_u64};
|
||||
ALeffectslot *EffectSlots{nullptr}; /* 64 */
|
||||
|
||||
EffectSlotSubList() noexcept = default;
|
||||
EffectSlotSubList(const EffectSlotSubList&) = delete;
|
||||
EffectSlotSubList(EffectSlotSubList&& rhs) noexcept
|
||||
: FreeMask{rhs.FreeMask}, EffectSlots{rhs.EffectSlots}
|
||||
{ rhs.FreeMask = ~0_u64; rhs.EffectSlots = nullptr; }
|
||||
~EffectSlotSubList();
|
||||
|
||||
EffectSlotSubList& operator=(const EffectSlotSubList&) = delete;
|
||||
EffectSlotSubList& operator=(EffectSlotSubList&& rhs) noexcept
|
||||
{ std::swap(FreeMask, rhs.FreeMask); std::swap(EffectSlots, rhs.EffectSlots); return *this; }
|
||||
};
|
||||
|
||||
struct ALCcontext {
|
||||
RefCount ref{1u};
|
||||
@@ -68,7 +79,8 @@ struct ALCcontext {
|
||||
ALuint NumSources{0};
|
||||
std::mutex SourceLock;
|
||||
|
||||
al::vector<ALeffectslotPtr> EffectSlotList;
|
||||
al::vector<EffectSlotSubList> EffectSlotList;
|
||||
ALuint NumEffectSlots{0u};
|
||||
std::mutex EffectSlotLock;
|
||||
|
||||
std::atomic<ALenum> LastError{AL_NO_ERROR};
|
||||
|
||||
@@ -117,7 +117,7 @@ struct ALeffectslot {
|
||||
|
||||
static ALeffectslotArray *CreatePtrArray(size_t count) noexcept;
|
||||
|
||||
DEF_NEWDEL(ALeffectslot)
|
||||
DEF_PLACE_NEWDEL()
|
||||
};
|
||||
|
||||
ALenum InitEffectSlot(ALeffectslot *slot);
|
||||
|
||||
+128
-36
@@ -44,10 +44,15 @@ namespace {
|
||||
|
||||
inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) noexcept
|
||||
{
|
||||
--id;
|
||||
if(UNLIKELY(id >= context->EffectSlotList.size()))
|
||||
ALuint lidx = (id-1) >> 6;
|
||||
ALsizei slidx = (id-1) & 0x3f;
|
||||
|
||||
if(UNLIKELY(lidx >= context->EffectSlotList.size()))
|
||||
return nullptr;
|
||||
return context->EffectSlotList[id].get();
|
||||
EffectSlotSubList &sublist{context->EffectSlotList[lidx]};
|
||||
if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx)))
|
||||
return nullptr;
|
||||
return sublist.EffectSlots + slidx;
|
||||
}
|
||||
|
||||
inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) noexcept
|
||||
@@ -176,6 +181,86 @@ inline EffectStateFactory *getFactoryByType(ALenum type)
|
||||
}
|
||||
|
||||
|
||||
ALeffectslot *AllocEffectSlot(ALCcontext *context)
|
||||
{
|
||||
ALCdevice *device{context->Device};
|
||||
std::lock_guard<std::mutex> _{context->EffectSlotLock};
|
||||
if(context->NumEffectSlots >= device->AuxiliaryEffectSlotMax)
|
||||
{
|
||||
alSetError(context, AL_OUT_OF_MEMORY, "Exceeding %u effect slot limit",
|
||||
device->AuxiliaryEffectSlotMax);
|
||||
return nullptr;
|
||||
}
|
||||
auto sublist = std::find_if(context->EffectSlotList.begin(), context->EffectSlotList.end(),
|
||||
[](const EffectSlotSubList &entry) noexcept -> bool
|
||||
{ return entry.FreeMask != 0; }
|
||||
);
|
||||
auto lidx = static_cast<ALsizei>(std::distance(context->EffectSlotList.begin(), sublist));
|
||||
ALeffectslot *slot;
|
||||
ALsizei slidx;
|
||||
if(LIKELY(sublist != context->EffectSlotList.end()))
|
||||
{
|
||||
slidx = CTZ64(sublist->FreeMask);
|
||||
slot = sublist->EffectSlots + slidx;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Don't allocate so many list entries that the 32-bit ID could
|
||||
* overflow...
|
||||
*/
|
||||
if(UNLIKELY(context->EffectSlotList.size() >= 1<<25))
|
||||
{
|
||||
alSetError(context, AL_OUT_OF_MEMORY, "Too many effect slots allocated");
|
||||
return nullptr;
|
||||
}
|
||||
context->EffectSlotList.emplace_back();
|
||||
sublist = context->EffectSlotList.end() - 1;
|
||||
|
||||
sublist->FreeMask = ~0_u64;
|
||||
sublist->EffectSlots = static_cast<ALeffectslot*>(al_calloc(16, sizeof(ALeffectslot)*64));
|
||||
if(UNLIKELY(!sublist->EffectSlots))
|
||||
{
|
||||
context->EffectSlotList.pop_back();
|
||||
alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate effect slot batch");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
slidx = 0;
|
||||
slot = sublist->EffectSlots + slidx;
|
||||
}
|
||||
|
||||
slot = new (slot) ALeffectslot{};
|
||||
ALenum err{InitEffectSlot(slot)};
|
||||
if(err != AL_NO_ERROR)
|
||||
{
|
||||
slot->~ALeffectslot();
|
||||
alSetError(context, err, "Effect slot object initialization failed");
|
||||
return nullptr;
|
||||
}
|
||||
aluInitEffectPanning(slot);
|
||||
|
||||
/* Add 1 to avoid source ID 0. */
|
||||
slot->id = ((lidx<<6) | slidx) + 1;
|
||||
|
||||
context->NumEffectSlots += 1;
|
||||
sublist->FreeMask &= ~(1_u64 << slidx);
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
void FreeEffectSlot(ALCcontext *context, ALeffectslot *slot)
|
||||
{
|
||||
ALuint id = slot->id - 1;
|
||||
ALsizei lidx = id >> 6;
|
||||
ALsizei slidx = id & 0x3f;
|
||||
|
||||
slot->~ALeffectslot();
|
||||
|
||||
context->EffectSlotList[lidx].FreeMask |= 1_u64 << slidx;
|
||||
context->NumEffectSlots--;
|
||||
}
|
||||
|
||||
|
||||
#define DO_UPDATEPROPS() do { \
|
||||
if(!context->DeferUpdates.load(std::memory_order_acquire)) \
|
||||
UpdateEffectSlotProps(slot, context.get()); \
|
||||
@@ -204,45 +289,35 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo
|
||||
SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Generating %d effect slots", n);
|
||||
if(n == 0) return;
|
||||
|
||||
std::unique_lock<std::mutex> slotlock{context->EffectSlotLock};
|
||||
ALCdevice *device{context->Device};
|
||||
for(ALsizei cur{0};cur < n;cur++)
|
||||
if(n == 1)
|
||||
{
|
||||
auto iter = std::find_if(context->EffectSlotList.begin(), context->EffectSlotList.end(),
|
||||
[](const ALeffectslotPtr &entry) noexcept -> bool
|
||||
{ return !entry; }
|
||||
);
|
||||
if(iter == context->EffectSlotList.end())
|
||||
{
|
||||
if(UNLIKELY(device->AuxiliaryEffectSlotMax == context->EffectSlotList.size()))
|
||||
ALeffectslot *slot{AllocEffectSlot(context.get())};
|
||||
if(!slot) return;
|
||||
effectslots[0] = slot->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto tempids = al::vector<ALuint>(n);
|
||||
auto alloc_end = std::find_if_not(tempids.begin(), tempids.end(),
|
||||
[&context](ALuint &id) -> bool
|
||||
{
|
||||
slotlock.unlock();
|
||||
alDeleteAuxiliaryEffectSlots(cur, effectslots);
|
||||
alSetError(context.get(), AL_OUT_OF_MEMORY,
|
||||
"Exceeding %u auxiliary effect slot limit", device->AuxiliaryEffectSlotMax);
|
||||
return;
|
||||
ALeffectslot *slot{AllocEffectSlot(context.get())};
|
||||
if(!slot) return false;
|
||||
id = slot->id;
|
||||
return true;
|
||||
}
|
||||
context->EffectSlotList.emplace_back(nullptr);
|
||||
iter = context->EffectSlotList.end() - 1;
|
||||
}
|
||||
|
||||
*iter = al::make_unique<ALeffectslot>();
|
||||
ALenum err{InitEffectSlot(iter->get())};
|
||||
if(err != AL_NO_ERROR)
|
||||
);
|
||||
if(alloc_end != tempids.end())
|
||||
{
|
||||
*iter = nullptr;
|
||||
slotlock.unlock();
|
||||
|
||||
alDeleteAuxiliaryEffectSlots(cur, effectslots);
|
||||
alSetError(context.get(), err, "Effect slot object allocation failed");
|
||||
auto count = static_cast<ALsizei>(std::distance(tempids.begin(), alloc_end));
|
||||
alDeleteAuxiliaryEffectSlots(count, tempids.data());
|
||||
return;
|
||||
}
|
||||
aluInitEffectPanning(iter->get());
|
||||
|
||||
auto id = static_cast<ALuint>(std::distance(context->EffectSlotList.begin(), iter) + 1);
|
||||
(*iter)->id = id;
|
||||
effectslots[cur] = id;
|
||||
std::copy(tempids.cbegin(), tempids.cend(), effectslots);
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> slotlock{context->EffectSlotLock};
|
||||
AddActiveEffectSlots(effectslots, n, context.get());
|
||||
}
|
||||
|
||||
@@ -280,8 +355,11 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *
|
||||
// All effectslots are valid, remove and delete them
|
||||
RemoveActiveEffectSlots(effectslots, n, context.get());
|
||||
std::for_each(effectslots, effectslots_end,
|
||||
[&context](ALuint id) noexcept -> void
|
||||
{ context->EffectSlotList[id-1] = nullptr; }
|
||||
[&context](ALuint sid) -> void
|
||||
{
|
||||
ALeffectslot *slot{LookupEffectSlot(context.get(), sid)};
|
||||
if(slot) FreeEffectSlot(context.get(), slot);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -714,3 +792,17 @@ void UpdateAllEffectSlotProps(ALCcontext *context)
|
||||
UpdateEffectSlotProps(slot, context);
|
||||
}
|
||||
}
|
||||
|
||||
EffectSlotSubList::~EffectSlotSubList()
|
||||
{
|
||||
uint64_t usemask{~FreeMask};
|
||||
while(usemask)
|
||||
{
|
||||
ALsizei idx{CTZ64(usemask)};
|
||||
EffectSlots[idx].~ALeffectslot();
|
||||
usemask &= ~(1_u64 << idx);
|
||||
}
|
||||
FreeMask = ~usemask;
|
||||
al_free(EffectSlots);
|
||||
EffectSlots = nullptr;
|
||||
}
|
||||
|
||||
@@ -582,10 +582,15 @@ inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) noexcept
|
||||
|
||||
inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) noexcept
|
||||
{
|
||||
--id;
|
||||
if(UNLIKELY(id >= context->EffectSlotList.size()))
|
||||
ALuint lidx = (id-1) >> 6;
|
||||
ALsizei slidx = (id-1) & 0x3f;
|
||||
|
||||
if(UNLIKELY(lidx >= context->EffectSlotList.size()))
|
||||
return nullptr;
|
||||
return context->EffectSlotList[id].get();
|
||||
EffectSlotSubList &sublist{context->EffectSlotList[lidx]};
|
||||
if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx)))
|
||||
return nullptr;
|
||||
return sublist.EffectSlots + slidx;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user