]> git.tdb.fi Git - ext/openal.git/blob - core/context.h
Import OpenAL Soft 1.23.1 sources
[ext/openal.git] / core / context.h
1 #ifndef CORE_CONTEXT_H
2 #define CORE_CONTEXT_H
3
4 #include <array>
5 #include <atomic>
6 #include <bitset>
7 #include <cstddef>
8 #include <memory>
9 #include <thread>
10
11 #include "almalloc.h"
12 #include "alspan.h"
13 #include "async_event.h"
14 #include "atomic.h"
15 #include "bufferline.h"
16 #include "threads.h"
17 #include "vecmat.h"
18 #include "vector.h"
19
20 struct DeviceBase;
21 struct EffectSlot;
22 struct EffectSlotProps;
23 struct RingBuffer;
24 struct Voice;
25 struct VoiceChange;
26 struct VoicePropsItem;
27
28 using uint = unsigned int;
29
30
31 constexpr float SpeedOfSoundMetersPerSec{343.3f};
32
33 constexpr float AirAbsorbGainHF{0.99426f}; /* -0.05dB */
34
35 enum class DistanceModel : unsigned char {
36     Disable,
37     Inverse, InverseClamped,
38     Linear, LinearClamped,
39     Exponent, ExponentClamped,
40
41     Default = InverseClamped
42 };
43
44
45 struct ContextProps {
46     std::array<float,3> Position;
47     std::array<float,3> Velocity;
48     std::array<float,3> OrientAt;
49     std::array<float,3> OrientUp;
50     float Gain;
51     float MetersPerUnit;
52     float AirAbsorptionGainHF;
53
54     float DopplerFactor;
55     float DopplerVelocity;
56     float SpeedOfSound;
57     bool SourceDistanceModel;
58     DistanceModel mDistanceModel;
59
60     std::atomic<ContextProps*> next;
61
62     DEF_NEWDEL(ContextProps)
63 };
64
65 struct ContextParams {
66     /* Pointer to the most recent property values that are awaiting an update. */
67     std::atomic<ContextProps*> ContextUpdate{nullptr};
68
69     alu::Vector Position{};
70     alu::Matrix Matrix{alu::Matrix::Identity()};
71     alu::Vector Velocity{};
72
73     float Gain{1.0f};
74     float MetersPerUnit{1.0f};
75     float AirAbsorptionGainHF{AirAbsorbGainHF};
76
77     float DopplerFactor{1.0f};
78     float SpeedOfSound{SpeedOfSoundMetersPerSec}; /* in units per sec! */
79
80     bool SourceDistanceModel{false};
81     DistanceModel mDistanceModel{};
82 };
83
84 struct ContextBase {
85     DeviceBase *const mDevice;
86
87     /* Counter for the pre-mixing updates, in 31.1 fixed point (lowest bit
88      * indicates if updates are currently happening).
89      */
90     RefCount mUpdateCount{0u};
91     std::atomic<bool> mHoldUpdates{false};
92     std::atomic<bool> mStopVoicesOnDisconnect{true};
93
94     float mGainBoost{1.0f};
95
96     /* Linked lists of unused property containers, free to use for future
97      * updates.
98      */
99     std::atomic<ContextProps*> mFreeContextProps{nullptr};
100     std::atomic<VoicePropsItem*> mFreeVoiceProps{nullptr};
101     std::atomic<EffectSlotProps*> mFreeEffectslotProps{nullptr};
102
103     /* The voice change tail is the beginning of the "free" elements, up to and
104      * *excluding* the current. If tail==current, there's no free elements and
105      * new ones need to be allocated. The current voice change is the element
106      * last processed, and any after are pending.
107      */
108     VoiceChange *mVoiceChangeTail{};
109     std::atomic<VoiceChange*> mCurrentVoiceChange{};
110
111     void allocVoiceChanges();
112     void allocVoiceProps();
113
114
115     ContextParams mParams;
116
117     using VoiceArray = al::FlexArray<Voice*>;
118     std::atomic<VoiceArray*> mVoices{};
119     std::atomic<size_t> mActiveVoiceCount{};
120
121     void allocVoices(size_t addcount);
122     al::span<Voice*> getVoicesSpan() const noexcept
123     {
124         return {mVoices.load(std::memory_order_relaxed)->data(),
125             mActiveVoiceCount.load(std::memory_order_relaxed)};
126     }
127     al::span<Voice*> getVoicesSpanAcquired() const noexcept
128     {
129         return {mVoices.load(std::memory_order_acquire)->data(),
130             mActiveVoiceCount.load(std::memory_order_acquire)};
131     }
132
133
134     using EffectSlotArray = al::FlexArray<EffectSlot*>;
135     std::atomic<EffectSlotArray*> mActiveAuxSlots{nullptr};
136
137     std::thread mEventThread;
138     al::semaphore mEventSem;
139     std::unique_ptr<RingBuffer> mAsyncEvents;
140     using AsyncEventBitset = std::bitset<AsyncEvent::UserEventCount>;
141     std::atomic<AsyncEventBitset> mEnabledEvts{0u};
142
143     /* Asynchronous voice change actions are processed as a linked list of
144      * VoiceChange objects by the mixer, which is atomically appended to.
145      * However, to avoid allocating each object individually, they're allocated
146      * in clusters that are stored in a vector for easy automatic cleanup.
147      */
148     using VoiceChangeCluster = std::unique_ptr<VoiceChange[]>;
149     al::vector<VoiceChangeCluster> mVoiceChangeClusters;
150
151     using VoiceCluster = std::unique_ptr<Voice[]>;
152     al::vector<VoiceCluster> mVoiceClusters;
153
154     using VoicePropsCluster = std::unique_ptr<VoicePropsItem[]>;
155     al::vector<VoicePropsCluster> mVoicePropClusters;
156
157
158     static constexpr size_t EffectSlotClusterSize{4};
159     EffectSlot *getEffectSlot();
160
161     using EffectSlotCluster = std::unique_ptr<EffectSlot[]>;
162     al::vector<EffectSlotCluster> mEffectSlotClusters;
163
164
165     ContextBase(DeviceBase *device);
166     ContextBase(const ContextBase&) = delete;
167     ContextBase& operator=(const ContextBase&) = delete;
168     ~ContextBase();
169 };
170
171 #endif /* CORE_CONTEXT_H */