Enable proper full C++ exception handling on MSVC
[openal-soft.git] / core / context.h
blob1a1852e33d9a9de2a074ab0d469b39be4490ea27
1 #ifndef CORE_CONTEXT_H
2 #define CORE_CONTEXT_H
4 #include <array>
5 #include <atomic>
6 #include <bitset>
7 #include <cstddef>
8 #include <memory>
9 #include <thread>
10 #include <vector>
12 #include "almalloc.h"
13 #include "alsem.h"
14 #include "alspan.h"
15 #include "async_event.h"
16 #include "atomic.h"
17 #include "flexarray.h"
18 #include "opthelpers.h"
19 #include "vecmat.h"
21 struct DeviceBase;
22 struct EffectSlot;
23 struct EffectSlotProps;
24 struct RingBuffer;
25 struct Voice;
26 struct VoiceChange;
27 struct VoicePropsItem;
30 inline constexpr float SpeedOfSoundMetersPerSec{343.3f};
32 inline constexpr float AirAbsorbGainHF{0.99426f}; /* -0.05dB */
34 enum class DistanceModel : unsigned char {
35 Disable,
36 Inverse, InverseClamped,
37 Linear, LinearClamped,
38 Exponent, ExponentClamped,
40 Default = InverseClamped
44 struct ContextProps {
45 std::array<float,3> Position;
46 std::array<float,3> Velocity;
47 std::array<float,3> OrientAt;
48 std::array<float,3> OrientUp;
49 float Gain;
50 float MetersPerUnit;
51 float AirAbsorptionGainHF;
53 float DopplerFactor;
54 float DopplerVelocity;
55 float SpeedOfSound;
56 bool SourceDistanceModel;
57 DistanceModel mDistanceModel;
59 std::atomic<ContextProps*> next;
62 struct ContextParams {
63 /* Pointer to the most recent property values that are awaiting an update. */
64 std::atomic<ContextProps*> ContextUpdate{nullptr};
66 alu::Vector Position{};
67 alu::Matrix Matrix{alu::Matrix::Identity()};
68 alu::Vector Velocity{};
70 float Gain{1.0f};
71 float MetersPerUnit{1.0f};
72 float AirAbsorptionGainHF{AirAbsorbGainHF};
74 float DopplerFactor{1.0f};
75 float SpeedOfSound{SpeedOfSoundMetersPerSec}; /* in units per sec! */
77 bool SourceDistanceModel{false};
78 DistanceModel mDistanceModel{};
81 struct ContextBase {
82 DeviceBase *const mDevice;
84 /* Counter for the pre-mixing updates, in 31.1 fixed point (lowest bit
85 * indicates if updates are currently happening).
87 std::atomic<unsigned int> mUpdateCount{0u};
88 std::atomic<bool> mHoldUpdates{false};
89 std::atomic<bool> mStopVoicesOnDisconnect{true};
91 float mGainBoost{1.0f};
93 /* Linked lists of unused property containers, free to use for future
94 * updates.
96 std::atomic<ContextProps*> mFreeContextProps{nullptr};
97 std::atomic<VoicePropsItem*> mFreeVoiceProps{nullptr};
98 std::atomic<EffectSlotProps*> mFreeEffectSlotProps{nullptr};
100 /* The voice change tail is the beginning of the "free" elements, up to and
101 * *excluding* the current. If tail==current, there's no free elements and
102 * new ones need to be allocated. The current voice change is the element
103 * last processed, and any after are pending.
105 VoiceChange *mVoiceChangeTail{};
106 std::atomic<VoiceChange*> mCurrentVoiceChange{};
108 void allocVoiceChanges();
109 void allocVoiceProps();
110 void allocEffectSlotProps();
111 void allocContextProps();
113 ContextParams mParams;
115 using VoiceArray = al::FlexArray<Voice*>;
116 al::atomic_unique_ptr<VoiceArray> mVoices{};
117 std::atomic<size_t> mActiveVoiceCount{};
119 void allocVoices(size_t addcount);
120 [[nodiscard]] auto getVoicesSpan() const noexcept -> al::span<Voice*>
122 return {mVoices.load(std::memory_order_relaxed)->data(),
123 mActiveVoiceCount.load(std::memory_order_relaxed)};
125 [[nodiscard]] auto getVoicesSpanAcquired() const noexcept -> al::span<Voice*>
127 return {mVoices.load(std::memory_order_acquire)->data(),
128 mActiveVoiceCount.load(std::memory_order_acquire)};
132 using EffectSlotArray = al::FlexArray<EffectSlot*>;
133 /* This array is split in half. The front half is the list of activated
134 * effect slots as set by the app, and the back half is the same list but
135 * sorted to ensure later effect slots are fed by earlier ones.
137 al::atomic_unique_ptr<EffectSlotArray> mActiveAuxSlots;
139 std::thread mEventThread;
140 al::semaphore mEventSem;
141 std::unique_ptr<RingBuffer> mAsyncEvents;
142 using AsyncEventBitset = std::bitset<al::to_underlying(AsyncEnableBits::Count)>;
143 std::atomic<AsyncEventBitset> mEnabledEvts{0u};
145 /* Asynchronous voice change actions are processed as a linked list of
146 * VoiceChange objects by the mixer, which is atomically appended to.
147 * However, to avoid allocating each object individually, they're allocated
148 * in clusters that are stored in a vector for easy automatic cleanup.
150 using VoiceChangeCluster = std::unique_ptr<std::array<VoiceChange,128>>;
151 std::vector<VoiceChangeCluster> mVoiceChangeClusters;
153 using VoiceCluster = std::unique_ptr<std::array<Voice,32>>;
154 std::vector<VoiceCluster> mVoiceClusters;
156 using VoicePropsCluster = std::unique_ptr<std::array<VoicePropsItem,32>>;
157 std::vector<VoicePropsCluster> mVoicePropClusters;
160 EffectSlot *getEffectSlot();
162 using EffectSlotCluster = std::unique_ptr<std::array<EffectSlot,4>>;
163 std::vector<EffectSlotCluster> mEffectSlotClusters;
165 using EffectSlotPropsCluster = std::unique_ptr<std::array<EffectSlotProps,4>>;
166 std::vector<EffectSlotPropsCluster> mEffectSlotPropClusters;
168 /* This could be greater than 2, but there should be no way there can be
169 * more than two context property updates in use simultaneously.
171 using ContextPropsCluster = std::unique_ptr<std::array<ContextProps,2>>;
172 std::vector<ContextPropsCluster> mContextPropClusters;
175 ContextBase(DeviceBase *device);
176 ContextBase(const ContextBase&) = delete;
177 ContextBase& operator=(const ContextBase&) = delete;
178 ~ContextBase();
181 #endif /* CORE_CONTEXT_H */