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
23 #include "auxeffectslot.h"
38 #include "alcontext.h"
41 #include "alnumeric.h"
45 #include "fpu_modes.h"
46 #include "inprogext.h"
48 #include "opthelpers.h"
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())
60 EffectSlotSubList
&sublist
{context
->mEffectSlotList
[lidx
]};
61 if UNLIKELY(sublist
.FreeMask
& (1_u64
<< slidx
))
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())
73 EffectSubList
&sublist
= device
->EffectList
[lidx
];
74 if UNLIKELY(sublist
.FreeMask
& (1_u64
<< slidx
))
76 return sublist
.Effects
+ slidx
;
80 void AddActiveEffectSlots(const ALuint
*slotids
, size_t count
, ALCcontext
*context
)
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
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;
104 newcount
= static_cast<size_t>(std::distance(newarray
->begin(), last
));
106 /* Reallocate newarray if the new size ended up smaller from duplicate
109 if UNLIKELY(newcount
< newarray
->size())
112 newarray
= ALeffectslot::CreatePtrArray(newcount
);
113 std::copy_n(curarray
->begin(), newcount
, newarray
->begin());
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();
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())
147 newarray
= ALeffectslot::CreatePtrArray(newsize
);
148 std::copy_n(curarray
->begin(), newsize
, newarray
->begin());
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();
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)
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();
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");
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
);
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()); \
234 slot->PropsClean.clear(std::memory_order_release); \
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
)
252 ContextRef context
{GetContextRef()};
253 if UNLIKELY(!context
) return;
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
);
267 if(!EnsureEffectSlots(context
.get(), static_cast<ALuint
>(n
)))
269 context
->setError(AL_OUT_OF_MEMORY
, "Failed to allocate %d effectslot%s", n
,
276 ALeffectslot
*slot
{AllocEffectSlot(context
.get())};
278 effectslots
[0] = slot
->id
;
282 al::vector
<ALuint
> ids
;
284 ids
.reserve(static_cast<ALuint
>(count
));
286 ALeffectslot
*slot
{AllocEffectSlot(context
.get())};
290 alDeleteAuxiliaryEffectSlots(static_cast<ALsizei
>(ids
.size()), ids
.data());
293 ids
.emplace_back(slot
->id
);
295 std::copy(ids
.cbegin(), ids
.cend(), effectslots
);
298 AddActiveEffectSlots(effectslots
, static_cast<ALuint
>(n
), context
.get());
302 AL_API ALvoid AL_APIENTRY
alDeleteAuxiliaryEffectSlots(ALsizei n
, const ALuint
*effectslots
)
305 ContextRef context
{GetContextRef()};
306 if UNLIKELY(!context
) return;
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
)};
318 context
->setError(AL_INVALID_NAME
, "Invalid effect slot ID %u", id
);
321 if UNLIKELY(ReadRef(slot
->ref
) != 0)
323 context
->setError(AL_INVALID_OPERATION
, "Deleting in-use effect slot %u", id
);
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
);
343 AL_API ALboolean AL_APIENTRY
alIsAuxiliaryEffectSlot(ALuint effectslot
)
346 ContextRef context
{GetContextRef()};
349 std::lock_guard
<std::mutex
> _
{context
->mEffectSlotLock
};
350 if(LookupEffectSlot(context
.get(), effectslot
) != nullptr)
358 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSloti(ALuint effectslot
, ALenum param
, ALint value
)
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
);
368 SETERR_RETURN(context
, AL_INVALID_NAME
,, "Invalid effect slot ID %u", effectslot
);
370 ALeffectslot
*target
{};
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");
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
);
398 case AL_EFFECTSLOT_TARGET_SOFT
:
399 target
= LookupEffectSlot(context
.get(), static_cast<ALuint
>(value
));
401 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Invalid effect slot target ID");
404 ALeffectslot
*checker
{target
};
405 while(checker
&& checker
!= slot
)
406 checker
= checker
->Target
;
408 SETERR_RETURN(context
, AL_INVALID_OPERATION
,,
409 "Setting target of effect slot ID %u to %u creates circular chain", slot
->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());
425 if(target
) IncrementRef(target
->ref
);
426 slot
->Target
= target
;
430 SETERR_RETURN(context
, AL_INVALID_ENUM
,, "Invalid effect slot integer property 0x%04x",
437 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotiv(ALuint effectslot
, ALenum param
, const ALint
*values
)
442 case AL_EFFECTSLOT_EFFECT
:
443 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
444 case AL_EFFECTSLOT_TARGET_SOFT
:
445 alAuxiliaryEffectSloti(effectslot
, param
, values
[0]);
449 ContextRef context
{GetContextRef()};
450 if UNLIKELY(!context
) return;
452 std::lock_guard
<std::mutex
> _
{context
->mEffectSlotLock
};
453 ALeffectslot
*slot
= LookupEffectSlot(context
.get(), effectslot
);
455 SETERR_RETURN(context
, AL_INVALID_NAME
,, "Invalid effect slot ID %u", effectslot
);
460 SETERR_RETURN(context
, AL_INVALID_ENUM
,,
461 "Invalid effect slot integer-vector property 0x%04x", param
);
466 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotf(ALuint effectslot
, ALenum param
, ALfloat value
)
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
);
476 SETERR_RETURN(context
, AL_INVALID_NAME
,, "Invalid effect slot ID %u", effectslot
);
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");
487 SETERR_RETURN(context
, AL_INVALID_ENUM
,, "Invalid effect slot float property 0x%04x",
494 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotfv(ALuint effectslot
, ALenum param
, const ALfloat
*values
)
499 case AL_EFFECTSLOT_GAIN
:
500 alAuxiliaryEffectSlotf(effectslot
, param
, values
[0]);
504 ContextRef context
{GetContextRef()};
505 if UNLIKELY(!context
) return;
507 std::lock_guard
<std::mutex
> _
{context
->mEffectSlotLock
};
508 ALeffectslot
*slot
= LookupEffectSlot(context
.get(), effectslot
);
510 SETERR_RETURN(context
, AL_INVALID_NAME
,, "Invalid effect slot ID %u", effectslot
);
515 SETERR_RETURN(context
, AL_INVALID_ENUM
,,
516 "Invalid effect slot float-vector property 0x%04x", param
);
522 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSloti(ALuint effectslot
, ALenum param
, ALint
*value
)
525 ContextRef context
{GetContextRef()};
526 if UNLIKELY(!context
) return;
528 std::lock_guard
<std::mutex
> _
{context
->mEffectSlotLock
};
529 ALeffectslot
*slot
= LookupEffectSlot(context
.get(), effectslot
);
531 SETERR_RETURN(context
, AL_INVALID_NAME
,, "Invalid effect slot ID %u", effectslot
);
535 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
536 *value
= slot
->AuxSendAuto
;
539 case AL_EFFECTSLOT_TARGET_SOFT
:
540 if(auto *target
= slot
->Target
)
541 *value
= static_cast<ALint
>(target
->id
);
547 context
->setError(AL_INVALID_ENUM
, "Invalid effect slot integer property 0x%04x", param
);
552 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotiv(ALuint effectslot
, ALenum param
, ALint
*values
)
557 case AL_EFFECTSLOT_EFFECT
:
558 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
559 case AL_EFFECTSLOT_TARGET_SOFT
:
560 alGetAuxiliaryEffectSloti(effectslot
, param
, values
);
564 ContextRef context
{GetContextRef()};
565 if UNLIKELY(!context
) return;
567 std::lock_guard
<std::mutex
> _
{context
->mEffectSlotLock
};
568 ALeffectslot
*slot
= LookupEffectSlot(context
.get(), effectslot
);
570 SETERR_RETURN(context
, AL_INVALID_NAME
,, "Invalid effect slot ID %u", effectslot
);
575 context
->setError(AL_INVALID_ENUM
, "Invalid effect slot integer-vector property 0x%04x",
581 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotf(ALuint effectslot
, ALenum param
, ALfloat
*value
)
584 ContextRef context
{GetContextRef()};
585 if UNLIKELY(!context
) return;
587 std::lock_guard
<std::mutex
> _
{context
->mEffectSlotLock
};
588 ALeffectslot
*slot
= LookupEffectSlot(context
.get(), effectslot
);
590 SETERR_RETURN(context
, AL_INVALID_NAME
,, "Invalid effect slot ID %u", effectslot
);
594 case AL_EFFECTSLOT_GAIN
:
599 context
->setError(AL_INVALID_ENUM
, "Invalid effect slot float property 0x%04x", param
);
604 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotfv(ALuint effectslot
, ALenum param
, ALfloat
*values
)
609 case AL_EFFECTSLOT_GAIN
:
610 alGetAuxiliaryEffectSlotf(effectslot
, param
, values
);
614 ContextRef context
{GetContextRef()};
615 if UNLIKELY(!context
) return;
617 std::lock_guard
<std::mutex
> _
{context
->mEffectSlotLock
};
618 ALeffectslot
*slot
= LookupEffectSlot(context
.get(), effectslot
);
620 SETERR_RETURN(context
, AL_INVALID_NAME
,, "Invalid effect slot ID %u", effectslot
);
625 context
->setError(AL_INVALID_ENUM
, "Invalid effect slot float-vector property 0x%04x",
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
)};
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
;
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
)
655 return AL_OUT_OF_MEMORY
;
661 EffectSlot
->Effect
.Type
= AL_EFFECT_NULL
;
662 EffectSlot
->Effect
.Props
= EffectProps
{};
666 EffectSlot
->Effect
.Type
= effect
->type
;
667 EffectSlot
->Effect
.Props
= effect
->Props
;
670 EffectSlot
->Effect
.State
->release();
671 EffectSlot
->Effect
.State
= State
;
674 EffectSlot
->Effect
.Props
= effect
->Props
;
676 /* Remove state references from old effect slot property updates. */
677 ALeffectslotProps
*props
{Context
->mFreeEffectslotProps
.load()};
681 props
->State
->release();
682 props
->State
= nullptr;
683 props
= props
->next
.load(std::memory_order_relaxed
);
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
;
702 ALeffectslot::~ALeffectslot()
705 DecrementRef(Target
->ref
);
708 ALeffectslotProps
*props
{Params
.Update
.load()};
711 if(props
->State
) props
->State
->release();
712 TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n",
713 decltype(std::declval
<void*>()){props
});
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
)};
728 props
= new ALeffectslotProps
{};
731 ALeffectslotProps
*next
;
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
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
);
756 /* If there was an unused update container, put it back in the
760 props
->State
->release();
761 props
->State
= nullptr;
762 AtomicReplaceHead(context
->mFreeEffectslotProps
, props
);
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
};
785 ALsizei idx
{CTZ64(usemask
)};
786 al::destroy_at(EffectSlots
+idx
);
787 usemask
&= ~(1_u64
<< idx
);
790 al_free(EffectSlots
);
791 EffectSlots
= nullptr;