Fix reverse iterators for spans
[openal-soft.git] / al / auxeffectslot.cpp
blob3c312c662e125f89533c96debc364ff20a49da06
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include "auxeffectslot.h"
25 #include <algorithm>
26 #include <cstdint>
27 #include <iterator>
28 #include <memory>
29 #include <mutex>
30 #include <numeric>
31 #include <thread>
33 #include "AL/al.h"
34 #include "AL/alc.h"
35 #include "AL/efx.h"
37 #include "alcmain.h"
38 #include "alcontext.h"
39 #include "alexcpt.h"
40 #include "almalloc.h"
41 #include "alnumeric.h"
42 #include "alspan.h"
43 #include "alu.h"
44 #include "effect.h"
45 #include "fpu_modes.h"
46 #include "inprogext.h"
47 #include "logging.h"
48 #include "opthelpers.h"
51 namespace {
53 inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) noexcept
55 const size_t lidx{(id-1) >> 6};
56 const ALuint slidx{(id-1) & 0x3f};
58 if UNLIKELY(lidx >= context->mEffectSlotList.size())
59 return nullptr;
60 EffectSlotSubList &sublist{context->mEffectSlotList[lidx]};
61 if UNLIKELY(sublist.FreeMask & (1_u64 << slidx))
62 return nullptr;
63 return sublist.EffectSlots + slidx;
66 inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) noexcept
68 const size_t lidx{(id-1) >> 6};
69 const ALuint slidx{(id-1) & 0x3f};
71 if UNLIKELY(lidx >= device->EffectList.size())
72 return nullptr;
73 EffectSubList &sublist = device->EffectList[lidx];
74 if UNLIKELY(sublist.FreeMask & (1_u64 << slidx))
75 return nullptr;
76 return sublist.Effects + slidx;
80 void AddActiveEffectSlots(const ALuint *slotids, size_t count, ALCcontext *context)
82 if(count < 1) return;
83 ALeffectslotArray *curarray{context->mActiveAuxSlots.load(std::memory_order_acquire)};
84 size_t newcount{curarray->size() + count};
86 /* Insert the new effect slots into the head of the array, followed by the
87 * existing ones.
89 ALeffectslotArray *newarray = ALeffectslot::CreatePtrArray(newcount);
90 auto slotiter = std::transform(slotids, slotids+count, newarray->begin(),
91 [context](ALuint id) noexcept -> ALeffectslot*
92 { return LookupEffectSlot(context, id); }
94 std::copy(curarray->begin(), curarray->end(), slotiter);
96 /* Remove any duplicates (first instance of each will be kept). */
97 auto last = newarray->end();
98 for(auto start=newarray->begin()+1;;)
100 last = std::remove(start, last, *(start-1));
101 if(start == last) break;
102 ++start;
104 newcount = static_cast<size_t>(std::distance(newarray->begin(), last));
106 /* Reallocate newarray if the new size ended up smaller from duplicate
107 * removal.
109 if UNLIKELY(newcount < newarray->size())
111 curarray = newarray;
112 newarray = ALeffectslot::CreatePtrArray(newcount);
113 std::copy_n(curarray->begin(), newcount, newarray->begin());
114 delete curarray;
115 curarray = nullptr;
118 curarray = context->mActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel);
119 ALCdevice *device{context->mDevice.get()};
120 while((device->MixCount.load(std::memory_order_acquire)&1))
121 std::this_thread::yield();
122 delete curarray;
125 void RemoveActiveEffectSlots(const ALuint *slotids, size_t count, ALCcontext *context)
127 if(count < 1) return;
128 ALeffectslotArray *curarray{context->mActiveAuxSlots.load(std::memory_order_acquire)};
130 /* Don't shrink the allocated array size since we don't know how many (if
131 * any) of the effect slots to remove are in the array.
133 ALeffectslotArray *newarray = ALeffectslot::CreatePtrArray(curarray->size());
135 /* Copy each element in curarray to newarray whose ID is not in slotids. */
136 const ALuint *slotids_end{slotids + count};
137 auto slotiter = std::copy_if(curarray->begin(), curarray->end(), newarray->begin(),
138 [slotids, slotids_end](const ALeffectslot *slot) -> bool
139 { return std::find(slotids, slotids_end, slot->id) == slotids_end; }
142 /* Reallocate with the new size. */
143 auto newsize = static_cast<size_t>(std::distance(newarray->begin(), slotiter));
144 if LIKELY(newsize != newarray->size())
146 curarray = newarray;
147 newarray = ALeffectslot::CreatePtrArray(newsize);
148 std::copy_n(curarray->begin(), newsize, newarray->begin());
150 delete curarray;
151 curarray = nullptr;
154 curarray = context->mActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel);
155 ALCdevice *device{context->mDevice.get()};
156 while((device->MixCount.load(std::memory_order_acquire)&1))
157 std::this_thread::yield();
158 delete curarray;
162 bool EnsureEffectSlots(ALCcontext *context, size_t needed)
164 size_t count{std::accumulate(context->mEffectSlotList.cbegin(),
165 context->mEffectSlotList.cend(), size_t{0},
166 [](size_t cur, const EffectSlotSubList &sublist) noexcept -> size_t
167 { return cur + static_cast<ALuint>(POPCNT64(sublist.FreeMask)); }
170 while(needed > count)
172 if UNLIKELY(context->mEffectSlotList.size() >= 1<<25)
173 return false;
175 context->mEffectSlotList.emplace_back();
176 auto sublist = context->mEffectSlotList.end() - 1;
177 sublist->FreeMask = ~0_u64;
178 sublist->EffectSlots = static_cast<ALeffectslot*>(
179 al_calloc(alignof(ALeffectslot), sizeof(ALeffectslot)*64));
180 if UNLIKELY(!sublist->EffectSlots)
182 context->mEffectSlotList.pop_back();
183 return false;
185 count += 64;
187 return true;
190 ALeffectslot *AllocEffectSlot(ALCcontext *context)
192 auto sublist = std::find_if(context->mEffectSlotList.begin(), context->mEffectSlotList.end(),
193 [](const EffectSlotSubList &entry) noexcept -> bool
194 { return entry.FreeMask != 0; }
196 auto lidx = static_cast<ALuint>(std::distance(context->mEffectSlotList.begin(), sublist));
197 auto slidx = static_cast<ALuint>(CTZ64(sublist->FreeMask));
199 ALeffectslot *slot{::new (sublist->EffectSlots + slidx) ALeffectslot{}};
200 if(ALenum err{InitEffectSlot(slot)})
202 al::destroy_at(slot);
203 context->setError(err, "Effect slot object initialization failed");
204 return nullptr;
206 aluInitEffectPanning(slot, context->mDevice.get());
208 /* Add 1 to avoid source ID 0. */
209 slot->id = ((lidx<<6) | slidx) + 1;
211 context->mNumEffectSlots += 1;
212 sublist->FreeMask &= ~(1_u64 << slidx);
214 return slot;
217 void FreeEffectSlot(ALCcontext *context, ALeffectslot *slot)
219 const ALuint id{slot->id - 1};
220 const size_t lidx{id >> 6};
221 const ALuint slidx{id & 0x3f};
223 al::destroy_at(slot);
225 context->mEffectSlotList[lidx].FreeMask |= 1_u64 << slidx;
226 context->mNumEffectSlots--;
230 #define DO_UPDATEPROPS() do { \
231 if(!context->mDeferUpdates.load(std::memory_order_acquire)) \
232 UpdateEffectSlotProps(slot, context.get()); \
233 else \
234 slot->PropsClean.clear(std::memory_order_release); \
235 } while(0)
237 } // namespace
239 ALeffectslotArray *ALeffectslot::CreatePtrArray(size_t count) noexcept
241 /* Allocate space for twice as many pointers, so the mixer has scratch
242 * space to store a sorted list during mixing.
244 void *ptr{al_calloc(alignof(ALeffectslotArray), ALeffectslotArray::Sizeof(count*2))};
245 return new (ptr) ALeffectslotArray{count};
249 AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
250 START_API_FUNC
252 ContextRef context{GetContextRef()};
253 if UNLIKELY(!context) return;
255 if UNLIKELY(n < 0)
256 context->setError(AL_INVALID_VALUE, "Generating %d effect slots", n);
257 if UNLIKELY(n <= 0) return;
259 std::unique_lock<std::mutex> slotlock{context->mEffectSlotLock};
260 ALCdevice *device{context->mDevice.get()};
261 if(static_cast<ALuint>(n) > device->AuxiliaryEffectSlotMax-context->mNumEffectSlots)
263 context->setError(AL_OUT_OF_MEMORY, "Exceeding %u effect slot limit (%u + %d)",
264 device->AuxiliaryEffectSlotMax, context->mNumEffectSlots, n);
265 return;
267 if(!EnsureEffectSlots(context.get(), static_cast<ALuint>(n)))
269 context->setError(AL_OUT_OF_MEMORY, "Failed to allocate %d effectslot%s", n,
270 (n==1) ? "" : "s");
271 return;
274 if(n == 1)
276 ALeffectslot *slot{AllocEffectSlot(context.get())};
277 if(!slot) return;
278 effectslots[0] = slot->id;
280 else
282 al::vector<ALuint> ids;
283 ALsizei count{n};
284 ids.reserve(static_cast<ALuint>(count));
285 do {
286 ALeffectslot *slot{AllocEffectSlot(context.get())};
287 if(!slot)
289 slotlock.unlock();
290 alDeleteAuxiliaryEffectSlots(static_cast<ALsizei>(ids.size()), ids.data());
291 return;
293 ids.emplace_back(slot->id);
294 } while(--count);
295 std::copy(ids.cbegin(), ids.cend(), effectslots);
298 AddActiveEffectSlots(effectslots, static_cast<ALuint>(n), context.get());
300 END_API_FUNC
302 AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots)
303 START_API_FUNC
305 ContextRef context{GetContextRef()};
306 if UNLIKELY(!context) return;
308 if UNLIKELY(n < 0)
309 context->setError(AL_INVALID_VALUE, "Deleting %d effect slots", n);
310 if UNLIKELY(n <= 0) return;
312 std::lock_guard<std::mutex> _{context->mEffectSlotLock};
313 auto validate_slot = [&context](const ALuint id) -> bool
315 ALeffectslot *slot{LookupEffectSlot(context.get(), id)};
316 if UNLIKELY(!slot)
318 context->setError(AL_INVALID_NAME, "Invalid effect slot ID %u", id);
319 return false;
321 if UNLIKELY(ReadRef(slot->ref) != 0)
323 context->setError(AL_INVALID_OPERATION, "Deleting in-use effect slot %u", id);
324 return false;
326 return true;
328 auto effectslots_end = effectslots + n;
329 auto bad_slot = std::find_if_not(effectslots, effectslots_end, validate_slot);
330 if UNLIKELY(bad_slot != effectslots_end) return;
332 // All effectslots are valid, remove and delete them
333 RemoveActiveEffectSlots(effectslots, static_cast<ALuint>(n), context.get());
334 auto delete_slot = [&context](const ALuint sid) -> void
336 ALeffectslot *slot{LookupEffectSlot(context.get(), sid)};
337 if(slot) FreeEffectSlot(context.get(), slot);
339 std::for_each(effectslots, effectslots_end, delete_slot);
341 END_API_FUNC
343 AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
344 START_API_FUNC
346 ContextRef context{GetContextRef()};
347 if LIKELY(context)
349 std::lock_guard<std::mutex> _{context->mEffectSlotLock};
350 if(LookupEffectSlot(context.get(), effectslot) != nullptr)
351 return AL_TRUE;
353 return AL_FALSE;
355 END_API_FUNC
358 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint value)
359 START_API_FUNC
361 ContextRef context{GetContextRef()};
362 if UNLIKELY(!context) return;
364 std::lock_guard<std::mutex> _{context->mPropLock};
365 std::lock_guard<std::mutex> __{context->mEffectSlotLock};
366 ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot);
367 if UNLIKELY(!slot)
368 SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot);
370 ALeffectslot *target{};
371 ALCdevice *device{};
372 ALenum err{};
373 switch(param)
375 case AL_EFFECTSLOT_EFFECT:
376 device = context->mDevice.get();
378 { std::lock_guard<std::mutex> ___{device->EffectLock};
379 ALeffect *effect{value ? LookupEffect(device, static_cast<ALuint>(value)) : nullptr};
380 if(!(value == 0 || effect != nullptr))
381 SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid effect ID %u", value);
382 err = InitializeEffect(context.get(), slot, effect);
384 if(err != AL_NO_ERROR)
386 context->setError(err, "Effect initialization failed");
387 return;
389 break;
391 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
392 if(!(value == AL_TRUE || value == AL_FALSE))
393 SETERR_RETURN(context, AL_INVALID_VALUE,,
394 "Effect slot auxiliary send auto out of range");
395 slot->AuxSendAuto = static_cast<ALboolean>(value);
396 break;
398 case AL_EFFECTSLOT_TARGET_SOFT:
399 target = LookupEffectSlot(context.get(), static_cast<ALuint>(value));
400 if(value && !target)
401 SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid effect slot target ID");
402 if(target)
404 ALeffectslot *checker{target};
405 while(checker && checker != slot)
406 checker = checker->Target;
407 if(checker)
408 SETERR_RETURN(context, AL_INVALID_OPERATION,,
409 "Setting target of effect slot ID %u to %u creates circular chain", slot->id,
410 target->id);
413 if(ALeffectslot *oldtarget{slot->Target})
415 /* We must force an update if there was an existing effect slot
416 * target, in case it's about to be deleted.
418 if(target) IncrementRef(target->ref);
419 DecrementRef(oldtarget->ref);
420 slot->Target = target;
421 UpdateEffectSlotProps(slot, context.get());
422 return;
425 if(target) IncrementRef(target->ref);
426 slot->Target = target;
427 break;
429 default:
430 SETERR_RETURN(context, AL_INVALID_ENUM,, "Invalid effect slot integer property 0x%04x",
431 param);
433 DO_UPDATEPROPS();
435 END_API_FUNC
437 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *values)
438 START_API_FUNC
440 switch(param)
442 case AL_EFFECTSLOT_EFFECT:
443 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
444 case AL_EFFECTSLOT_TARGET_SOFT:
445 alAuxiliaryEffectSloti(effectslot, param, values[0]);
446 return;
449 ContextRef context{GetContextRef()};
450 if UNLIKELY(!context) return;
452 std::lock_guard<std::mutex> _{context->mEffectSlotLock};
453 ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot);
454 if UNLIKELY(!slot)
455 SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot);
457 switch(param)
459 default:
460 SETERR_RETURN(context, AL_INVALID_ENUM,,
461 "Invalid effect slot integer-vector property 0x%04x", param);
464 END_API_FUNC
466 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat value)
467 START_API_FUNC
469 ContextRef context{GetContextRef()};
470 if UNLIKELY(!context) return;
472 std::lock_guard<std::mutex> _{context->mPropLock};
473 std::lock_guard<std::mutex> __{context->mEffectSlotLock};
474 ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot);
475 if UNLIKELY(!slot)
476 SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot);
478 switch(param)
480 case AL_EFFECTSLOT_GAIN:
481 if(!(value >= 0.0f && value <= 1.0f))
482 SETERR_RETURN(context, AL_INVALID_VALUE,, "Effect slot gain out of range");
483 slot->Gain = value;
484 break;
486 default:
487 SETERR_RETURN(context, AL_INVALID_ENUM,, "Invalid effect slot float property 0x%04x",
488 param);
490 DO_UPDATEPROPS();
492 END_API_FUNC
494 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *values)
495 START_API_FUNC
497 switch(param)
499 case AL_EFFECTSLOT_GAIN:
500 alAuxiliaryEffectSlotf(effectslot, param, values[0]);
501 return;
504 ContextRef context{GetContextRef()};
505 if UNLIKELY(!context) return;
507 std::lock_guard<std::mutex> _{context->mEffectSlotLock};
508 ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot);
509 if UNLIKELY(!slot)
510 SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot);
512 switch(param)
514 default:
515 SETERR_RETURN(context, AL_INVALID_ENUM,,
516 "Invalid effect slot float-vector property 0x%04x", param);
519 END_API_FUNC
522 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *value)
523 START_API_FUNC
525 ContextRef context{GetContextRef()};
526 if UNLIKELY(!context) return;
528 std::lock_guard<std::mutex> _{context->mEffectSlotLock};
529 ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot);
530 if UNLIKELY(!slot)
531 SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot);
533 switch(param)
535 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
536 *value = slot->AuxSendAuto;
537 break;
539 case AL_EFFECTSLOT_TARGET_SOFT:
540 if(auto *target = slot->Target)
541 *value = static_cast<ALint>(target->id);
542 else
543 *value = 0;
544 break;
546 default:
547 context->setError(AL_INVALID_ENUM, "Invalid effect slot integer property 0x%04x", param);
550 END_API_FUNC
552 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *values)
553 START_API_FUNC
555 switch(param)
557 case AL_EFFECTSLOT_EFFECT:
558 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
559 case AL_EFFECTSLOT_TARGET_SOFT:
560 alGetAuxiliaryEffectSloti(effectslot, param, values);
561 return;
564 ContextRef context{GetContextRef()};
565 if UNLIKELY(!context) return;
567 std::lock_guard<std::mutex> _{context->mEffectSlotLock};
568 ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot);
569 if UNLIKELY(!slot)
570 SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot);
572 switch(param)
574 default:
575 context->setError(AL_INVALID_ENUM, "Invalid effect slot integer-vector property 0x%04x",
576 param);
579 END_API_FUNC
581 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *value)
582 START_API_FUNC
584 ContextRef context{GetContextRef()};
585 if UNLIKELY(!context) return;
587 std::lock_guard<std::mutex> _{context->mEffectSlotLock};
588 ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot);
589 if UNLIKELY(!slot)
590 SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot);
592 switch(param)
594 case AL_EFFECTSLOT_GAIN:
595 *value = slot->Gain;
596 break;
598 default:
599 context->setError(AL_INVALID_ENUM, "Invalid effect slot float property 0x%04x", param);
602 END_API_FUNC
604 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *values)
605 START_API_FUNC
607 switch(param)
609 case AL_EFFECTSLOT_GAIN:
610 alGetAuxiliaryEffectSlotf(effectslot, param, values);
611 return;
614 ContextRef context{GetContextRef()};
615 if UNLIKELY(!context) return;
617 std::lock_guard<std::mutex> _{context->mEffectSlotLock};
618 ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot);
619 if UNLIKELY(!slot)
620 SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot);
622 switch(param)
624 default:
625 context->setError(AL_INVALID_ENUM, "Invalid effect slot float-vector property 0x%04x",
626 param);
629 END_API_FUNC
632 ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect)
634 ALenum newtype{effect ? effect->type : AL_EFFECT_NULL};
635 if(newtype != EffectSlot->Effect.Type)
637 EffectStateFactory *factory{getFactoryByType(newtype)};
638 if(!factory)
640 ERR("Failed to find factory for effect type 0x%04x\n", newtype);
641 return AL_INVALID_ENUM;
643 EffectState *State{factory->create()};
644 if(!State) return AL_OUT_OF_MEMORY;
646 FPUCtl mixer_mode{};
647 ALCdevice *Device{Context->mDevice.get()};
648 std::unique_lock<std::mutex> statelock{Device->StateLock};
649 State->mOutTarget = Device->Dry.Buffer;
650 if(State->deviceUpdate(Device) == AL_FALSE)
652 statelock.unlock();
653 mixer_mode.leave();
654 State->release();
655 return AL_OUT_OF_MEMORY;
657 mixer_mode.leave();
659 if(!effect)
661 EffectSlot->Effect.Type = AL_EFFECT_NULL;
662 EffectSlot->Effect.Props = EffectProps {};
664 else
666 EffectSlot->Effect.Type = effect->type;
667 EffectSlot->Effect.Props = effect->Props;
670 EffectSlot->Effect.State->release();
671 EffectSlot->Effect.State = State;
673 else if(effect)
674 EffectSlot->Effect.Props = effect->Props;
676 /* Remove state references from old effect slot property updates. */
677 ALeffectslotProps *props{Context->mFreeEffectslotProps.load()};
678 while(props)
680 if(props->State)
681 props->State->release();
682 props->State = nullptr;
683 props = props->next.load(std::memory_order_relaxed);
686 return AL_NO_ERROR;
690 ALenum InitEffectSlot(ALeffectslot *slot)
692 EffectStateFactory *factory{getFactoryByType(slot->Effect.Type)};
693 if(!factory) return AL_INVALID_VALUE;
694 slot->Effect.State = factory->create();
695 if(!slot->Effect.State) return AL_OUT_OF_MEMORY;
697 slot->Effect.State->add_ref();
698 slot->Params.mEffectState = slot->Effect.State;
699 return AL_NO_ERROR;
702 ALeffectslot::~ALeffectslot()
704 if(Target)
705 DecrementRef(Target->ref);
706 Target = nullptr;
708 ALeffectslotProps *props{Params.Update.load()};
709 if(props)
711 if(props->State) props->State->release();
712 TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n",
713 decltype(std::declval<void*>()){props});
714 delete props;
717 if(Effect.State)
718 Effect.State->release();
719 if(Params.mEffectState)
720 Params.mEffectState->release();
723 void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context)
725 /* Get an unused property container, or allocate a new one as needed. */
726 ALeffectslotProps *props{context->mFreeEffectslotProps.load(std::memory_order_relaxed)};
727 if(!props)
728 props = new ALeffectslotProps{};
729 else
731 ALeffectslotProps *next;
732 do {
733 next = props->next.load(std::memory_order_relaxed);
734 } while(context->mFreeEffectslotProps.compare_exchange_weak(props, next,
735 std::memory_order_seq_cst, std::memory_order_acquire) == 0);
738 /* Copy in current property values. */
739 props->Gain = slot->Gain;
740 props->AuxSendAuto = slot->AuxSendAuto;
741 props->Target = slot->Target;
743 props->Type = slot->Effect.Type;
744 props->Props = slot->Effect.Props;
745 /* Swap out any stale effect state object there may be in the container, to
746 * delete it.
748 EffectState *oldstate{props->State};
749 slot->Effect.State->add_ref();
750 props->State = slot->Effect.State;
752 /* Set the new container for updating internal parameters. */
753 props = slot->Params.Update.exchange(props, std::memory_order_acq_rel);
754 if(props)
756 /* If there was an unused update container, put it back in the
757 * freelist.
759 if(props->State)
760 props->State->release();
761 props->State = nullptr;
762 AtomicReplaceHead(context->mFreeEffectslotProps, props);
765 if(oldstate)
766 oldstate->release();
769 void UpdateAllEffectSlotProps(ALCcontext *context)
771 std::lock_guard<std::mutex> _{context->mEffectSlotLock};
772 ALeffectslotArray *auxslots{context->mActiveAuxSlots.load(std::memory_order_acquire)};
773 for(ALeffectslot *slot : *auxslots)
775 if(!slot->PropsClean.test_and_set(std::memory_order_acq_rel))
776 UpdateEffectSlotProps(slot, context);
780 EffectSlotSubList::~EffectSlotSubList()
782 uint64_t usemask{~FreeMask};
783 while(usemask)
785 ALsizei idx{CTZ64(usemask)};
786 al::destroy_at(EffectSlots+idx);
787 usemask &= ~(1_u64 << idx);
789 FreeMask = ~usemask;
790 al_free(EffectSlots);
791 EffectSlots = nullptr;