Make a couple more operator bools explicit
[openal-soft.git] / alc / context.h
blob0a8848357220da40666ef23331608f80cf7ae5b6
1 #ifndef ALC_CONTEXT_H
2 #define ALC_CONTEXT_H
4 #include <atomic>
5 #include <memory>
6 #include <mutex>
7 #include <stdint.h>
8 #include <utility>
10 #include "AL/al.h"
11 #include "AL/alc.h"
12 #include "AL/alext.h"
14 #include "al/listener.h"
15 #include "almalloc.h"
16 #include "alnumeric.h"
17 #include "atomic.h"
18 #include "core/context.h"
19 #include "intrusive_ptr.h"
20 #include "vector.h"
22 #ifdef ALSOFT_EAX
23 #include "al/eax_eax_call.h"
24 #include "al/eax_fx_slot_index.h"
25 #include "al/eax_fx_slots.h"
26 #include "al/eax_utils.h"
29 using EaxContextSharedDirtyFlagsValue = std::uint_least8_t;
31 struct EaxContextSharedDirtyFlags
33 using EaxIsBitFieldStruct = bool;
35 EaxContextSharedDirtyFlagsValue primary_fx_slot_id : 1;
36 }; // EaxContextSharedDirtyFlags
39 using ContextDirtyFlagsValue = std::uint_least8_t;
41 struct ContextDirtyFlags
43 using EaxIsBitFieldStruct = bool;
45 ContextDirtyFlagsValue guidPrimaryFXSlotID : 1;
46 ContextDirtyFlagsValue flDistanceFactor : 1;
47 ContextDirtyFlagsValue flAirAbsorptionHF : 1;
48 ContextDirtyFlagsValue flHFReference : 1;
49 ContextDirtyFlagsValue flMacroFXFactor : 1;
50 }; // ContextDirtyFlags
53 struct EaxAlIsExtensionPresentResult
55 ALboolean is_present;
56 bool is_return;
57 }; // EaxAlIsExtensionPresentResult
58 #endif // ALSOFT_EAX
60 struct ALeffect;
61 struct ALeffectslot;
62 struct ALsource;
64 using uint = unsigned int;
67 struct SourceSubList {
68 uint64_t FreeMask{~0_u64};
69 ALsource *Sources{nullptr}; /* 64 */
71 SourceSubList() noexcept = default;
72 SourceSubList(const SourceSubList&) = delete;
73 SourceSubList(SourceSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Sources{rhs.Sources}
74 { rhs.FreeMask = ~0_u64; rhs.Sources = nullptr; }
75 ~SourceSubList();
77 SourceSubList& operator=(const SourceSubList&) = delete;
78 SourceSubList& operator=(SourceSubList&& rhs) noexcept
79 { std::swap(FreeMask, rhs.FreeMask); std::swap(Sources, rhs.Sources); return *this; }
82 struct EffectSlotSubList {
83 uint64_t FreeMask{~0_u64};
84 ALeffectslot *EffectSlots{nullptr}; /* 64 */
86 EffectSlotSubList() noexcept = default;
87 EffectSlotSubList(const EffectSlotSubList&) = delete;
88 EffectSlotSubList(EffectSlotSubList&& rhs) noexcept
89 : FreeMask{rhs.FreeMask}, EffectSlots{rhs.EffectSlots}
90 { rhs.FreeMask = ~0_u64; rhs.EffectSlots = nullptr; }
91 ~EffectSlotSubList();
93 EffectSlotSubList& operator=(const EffectSlotSubList&) = delete;
94 EffectSlotSubList& operator=(EffectSlotSubList&& rhs) noexcept
95 { std::swap(FreeMask, rhs.FreeMask); std::swap(EffectSlots, rhs.EffectSlots); return *this; }
98 struct ALCcontext : public al::intrusive_ref<ALCcontext>, ContextBase {
99 const al::intrusive_ptr<ALCdevice> mALDevice;
101 /* Wet buffers used by effect slots. */
102 al::vector<WetBufferPtr> mWetBuffers;
105 bool mPropsDirty{true};
106 bool mDeferUpdates{false};
108 std::mutex mPropLock;
110 std::atomic<ALenum> mLastError{AL_NO_ERROR};
112 DistanceModel mDistanceModel{DistanceModel::Default};
113 bool mSourceDistanceModel{false};
115 float mDopplerFactor{1.0f};
116 float mDopplerVelocity{1.0f};
117 float mSpeedOfSound{SpeedOfSoundMetersPerSec};
118 float mAirAbsorptionGainHF{AirAbsorbGainHF};
120 std::mutex mEventCbLock;
121 ALEVENTPROCSOFT mEventCb{};
122 void *mEventParam{nullptr};
124 ALlistener mListener{};
126 al::vector<SourceSubList> mSourceList;
127 ALuint mNumSources{0};
128 std::mutex mSourceLock;
130 al::vector<EffectSlotSubList> mEffectSlotList;
131 ALuint mNumEffectSlots{0u};
132 std::mutex mEffectSlotLock;
134 /* Default effect slot */
135 std::unique_ptr<ALeffectslot> mDefaultSlot;
137 const char *mExtensionList{nullptr};
140 ALCcontext(al::intrusive_ptr<ALCdevice> device);
141 ALCcontext(const ALCcontext&) = delete;
142 ALCcontext& operator=(const ALCcontext&) = delete;
143 ~ALCcontext();
145 void init();
147 * Removes the context from its device and removes it from being current on
148 * the running thread or globally. Returns true if other contexts still
149 * exist on the device.
151 bool deinit();
154 * Defers/suspends updates for the given context's listener and sources.
155 * This does *NOT* stop mixing, but rather prevents certain property
156 * changes from taking effect. mPropLock must be held when called.
158 void deferUpdates() noexcept { mDeferUpdates = true; }
161 * Resumes update processing after being deferred. mPropLock must be held
162 * when called.
164 void processUpdates()
166 if(std::exchange(mDeferUpdates, false))
167 applyAllUpdates();
171 * Applies all pending updates for the context, listener, effect slots, and
172 * sources.
174 void applyAllUpdates();
176 #ifdef __USE_MINGW_ANSI_STDIO
177 [[gnu::format(gnu_printf, 3, 4)]]
178 #else
179 [[gnu::format(printf, 3, 4)]]
180 #endif
181 void setError(ALenum errorCode, const char *msg, ...);
183 /* Process-wide current context */
184 static std::atomic<ALCcontext*> sGlobalContext;
186 private:
187 /* Thread-local current context. */
188 static thread_local ALCcontext *sLocalContext;
190 /* Thread-local context handling. This handles attempting to release the
191 * context which may have been left current when the thread is destroyed.
193 class ThreadCtx {
194 public:
195 ~ThreadCtx();
196 void set(ALCcontext *ctx) const noexcept { sLocalContext = ctx; }
198 static thread_local ThreadCtx sThreadContext;
200 public:
201 /* HACK: MinGW generates bad code when accessing an extern thread_local
202 * object. Add a wrapper function for it that only accesses it where it's
203 * defined.
205 #ifdef __MINGW32__
206 static ALCcontext *getThreadContext() noexcept;
207 static void setThreadContext(ALCcontext *context) noexcept;
208 #else
209 static ALCcontext *getThreadContext() noexcept { return sLocalContext; }
210 static void setThreadContext(ALCcontext *context) noexcept { sThreadContext.set(context); }
211 #endif
213 /* Default effect that applies to sources that don't have an effect on send 0. */
214 static ALeffect sDefaultEffect;
216 DEF_NEWDEL(ALCcontext)
218 #ifdef ALSOFT_EAX
219 public:
220 bool has_eax() const noexcept { return eax_is_initialized_; }
222 bool eax_is_capable() const noexcept;
225 void eax_uninitialize() noexcept;
228 ALenum eax_eax_set(
229 const GUID* property_set_id,
230 ALuint property_id,
231 ALuint property_source_id,
232 ALvoid* property_value,
233 ALuint property_value_size);
235 ALenum eax_eax_get(
236 const GUID* property_set_id,
237 ALuint property_id,
238 ALuint property_source_id,
239 ALvoid* property_value,
240 ALuint property_value_size);
243 void eax_update_filters();
245 void eax_commit_and_update_sources();
248 void eax_set_last_error() noexcept;
251 EaxFxSlotIndex eax_get_previous_primary_fx_slot_index() const noexcept
252 { return eax_previous_primary_fx_slot_index_; }
253 EaxFxSlotIndex eax_get_primary_fx_slot_index() const noexcept
254 { return eax_primary_fx_slot_index_; }
256 const ALeffectslot& eax_get_fx_slot(EaxFxSlotIndexValue fx_slot_index) const
257 { return eax_fx_slots_.get(fx_slot_index); }
258 ALeffectslot& eax_get_fx_slot(EaxFxSlotIndexValue fx_slot_index)
259 { return eax_fx_slots_.get(fx_slot_index); }
262 private:
263 using SourceList = al::vector<SourceSubList>;
266 struct SourceListIteratorBeginTag{};
267 struct SourceListIteratorEndTag{};
269 class SourceListIterator
271 public:
272 SourceListIterator(
273 SourceList& sources,
274 SourceListIteratorBeginTag) noexcept;
276 SourceListIterator(
277 SourceList& sources,
278 SourceListIteratorEndTag) noexcept;
280 SourceListIterator(
281 const SourceListIterator& rhs);
283 SourceListIterator& operator=(
284 const SourceListIterator& rhs) = delete;
286 SourceListIterator& operator++();
288 ALsource& operator*() noexcept;
290 bool operator==(
291 const SourceListIterator& rhs) const noexcept;
293 bool operator!=(
294 const SourceListIterator& rhs) const noexcept;
297 private:
298 SourceList::iterator sub_list_iterator_;
299 SourceList::iterator sub_list_end_iterator_;
300 std::uint64_t sub_list_item_index_;
301 }; // SourceListIterator
303 class SourceListEnumerator
305 public:
306 explicit SourceListEnumerator(
307 SourceList& sources) noexcept;
309 SourceListEnumerator(
310 const SourceListEnumerator& rhs) = delete;
312 SourceListEnumerator& operator=(
313 const SourceListEnumerator& rhs) = delete;
315 SourceListIterator begin() noexcept;
317 SourceListIterator end() noexcept;
320 private:
321 SourceList& sources_;
322 }; // SourceListEnumerator
325 struct Eax
327 EAX50CONTEXTPROPERTIES context{};
328 }; // Eax
331 bool eax_is_initialized_{};
332 bool eax_is_tried_{};
333 bool eax_are_legacy_fx_slots_unlocked_{};
335 long eax_last_error_{};
336 unsigned long eax_speaker_config_{};
338 EaxFxSlotIndex eax_previous_primary_fx_slot_index_{};
339 EaxFxSlotIndex eax_primary_fx_slot_index_{};
340 EaxFxSlots eax_fx_slots_{};
342 EaxContextSharedDirtyFlags eax_context_shared_dirty_flags_{};
344 Eax eax_{};
345 Eax eax_d_{};
346 EAXSESSIONPROPERTIES eax_session_{};
348 ContextDirtyFlags eax_context_dirty_flags_{};
350 std::string eax_extension_list_{};
353 [[noreturn]]
354 static void eax_fail(
355 const char* message);
358 void eax_initialize_extensions();
360 void eax_initialize();
363 bool eax_has_no_default_effect_slot() const noexcept;
365 void eax_ensure_no_default_effect_slot() const;
367 bool eax_has_enough_aux_sends() const noexcept;
369 void eax_ensure_enough_aux_sends() const;
371 void eax_ensure_compatibility();
374 unsigned long eax_detect_speaker_configuration() const;
375 void eax_update_speaker_configuration();
378 void eax_set_last_error_defaults() noexcept;
380 void eax_set_session_defaults() noexcept;
382 void eax_set_context_defaults() noexcept;
384 void eax_set_defaults() noexcept;
386 void eax_initialize_sources();
389 void eax_unlock_legacy_fx_slots(const EaxEaxCall& eax_call) noexcept;
392 void eax_dispatch_fx_slot(
393 const EaxEaxCall& eax_call);
395 void eax_dispatch_source(
396 const EaxEaxCall& eax_call);
399 void eax_get_primary_fx_slot_id(
400 const EaxEaxCall& eax_call);
402 void eax_get_distance_factor(
403 const EaxEaxCall& eax_call);
405 void eax_get_air_absorption_hf(
406 const EaxEaxCall& eax_call);
408 void eax_get_hf_reference(
409 const EaxEaxCall& eax_call);
411 void eax_get_last_error(
412 const EaxEaxCall& eax_call);
414 void eax_get_speaker_config(
415 const EaxEaxCall& eax_call);
417 void eax_get_session(
418 const EaxEaxCall& eax_call);
420 void eax_get_macro_fx_factor(
421 const EaxEaxCall& eax_call);
423 void eax_get_context_all(
424 const EaxEaxCall& eax_call);
426 void eax_get(
427 const EaxEaxCall& eax_call);
430 void eax_set_primary_fx_slot_id();
432 void eax_set_distance_factor();
434 void eax_set_air_absorbtion_hf();
436 void eax_set_hf_reference();
438 void eax_set_macro_fx_factor();
440 void eax_set_context();
442 void eax_initialize_fx_slots();
445 void eax_update_sources();
448 void eax_validate_primary_fx_slot_id(
449 const GUID& primary_fx_slot_id);
451 void eax_validate_distance_factor(
452 float distance_factor);
454 void eax_validate_air_absorption_hf(
455 float air_absorption_hf);
457 void eax_validate_hf_reference(
458 float hf_reference);
460 void eax_validate_speaker_config(
461 unsigned long speaker_config);
463 void eax_validate_session_eax_version(
464 unsigned long eax_version);
466 void eax_validate_session_max_active_sends(
467 unsigned long max_active_sends);
469 void eax_validate_session(
470 const EAXSESSIONPROPERTIES& eax_session);
472 void eax_validate_macro_fx_factor(
473 float macro_fx_factor);
475 void eax_validate_context_all(
476 const EAX40CONTEXTPROPERTIES& context_all);
478 void eax_validate_context_all(
479 const EAX50CONTEXTPROPERTIES& context_all);
482 void eax_defer_primary_fx_slot_id(
483 const GUID& primary_fx_slot_id);
485 void eax_defer_distance_factor(
486 float distance_factor);
488 void eax_defer_air_absorption_hf(
489 float air_absorption_hf);
491 void eax_defer_hf_reference(
492 float hf_reference);
494 void eax_defer_macro_fx_factor(
495 float macro_fx_factor);
497 void eax_defer_context_all(
498 const EAX40CONTEXTPROPERTIES& context_all);
500 void eax_defer_context_all(
501 const EAX50CONTEXTPROPERTIES& context_all);
504 void eax_defer_context_all(
505 const EaxEaxCall& eax_call);
507 void eax_defer_primary_fx_slot_id(
508 const EaxEaxCall& eax_call);
510 void eax_defer_distance_factor(
511 const EaxEaxCall& eax_call);
513 void eax_defer_air_absorption_hf(
514 const EaxEaxCall& eax_call);
516 void eax_defer_hf_reference(
517 const EaxEaxCall& eax_call);
519 void eax_set_session(
520 const EaxEaxCall& eax_call);
522 void eax_defer_macro_fx_factor(
523 const EaxEaxCall& eax_call);
525 void eax_set(
526 const EaxEaxCall& eax_call);
528 void eax_apply_deferred();
529 #endif // ALSOFT_EAX
532 #define SETERR_RETURN(ctx, err, retval, ...) do { \
533 (ctx)->setError((err), __VA_ARGS__); \
534 return retval; \
535 } while(0)
538 using ContextRef = al::intrusive_ptr<ALCcontext>;
540 ContextRef GetContextRef(void);
542 void UpdateContextProps(ALCcontext *context);
545 extern bool TrapALError;
548 #ifdef ALSOFT_EAX
549 ALenum AL_APIENTRY EAXSet(
550 const GUID* property_set_id,
551 ALuint property_id,
552 ALuint property_source_id,
553 ALvoid* property_value,
554 ALuint property_value_size) noexcept;
556 ALenum AL_APIENTRY EAXGet(
557 const GUID* property_set_id,
558 ALuint property_id,
559 ALuint property_source_id,
560 ALvoid* property_value,
561 ALuint property_value_size) noexcept;
562 #endif // ALSOFT_EAX
564 #endif /* ALC_CONTEXT_H */