aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Alc/alc.cpp37
-rw-r--r--Alc/alcontext.h22
-rw-r--r--OpenAL32/Include/alAuxEffectSlot.h2
-rw-r--r--OpenAL32/alAuxEffectSlot.cpp164
-rw-r--r--OpenAL32/alSource.cpp11
5 files changed, 178 insertions, 58 deletions
diff --git a/Alc/alc.cpp b/Alc/alc.cpp
index 55104f9e..99247753 100644
--- a/Alc/alc.cpp
+++ b/Alc/alc.cpp
@@ -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
diff --git a/Alc/alcontext.h b/Alc/alcontext.h
index bdf5f2fe..2c4ad1d3 100644
--- a/Alc/alcontext.h
+++ b/Alc/alcontext.h
@@ -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};
diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h
index ccb01266..6c060fe6 100644
--- a/OpenAL32/Include/alAuxEffectSlot.h
+++ b/OpenAL32/Include/alAuxEffectSlot.h
@@ -117,7 +117,7 @@ struct ALeffectslot {
static ALeffectslotArray *CreatePtrArray(size_t count) noexcept;
- DEF_NEWDEL(ALeffectslot)
+ DEF_PLACE_NEWDEL()
};
ALenum InitEffectSlot(ALeffectslot *slot);
diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp
index c9803819..07c6e69e 100644
--- a/OpenAL32/alAuxEffectSlot.cpp
+++ b/OpenAL32/alAuxEffectSlot.cpp
@@ -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;
+ EffectSlotSubList &sublist{context->EffectSlotList[lidx]};
+ if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx)))
return nullptr;
- return context->EffectSlotList[id].get();
+ 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;
+}
diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp
index dd418a58..cf466c32 100644
--- a/OpenAL32/alSource.cpp
+++ b/OpenAL32/alSource.cpp
@@ -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;
+ EffectSlotSubList &sublist{context->EffectSlotList[lidx]};
+ if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx)))
return nullptr;
- return context->EffectSlotList[id].get();
+ return sublist.EffectSlots + slidx;
}