alcontext.h 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. #ifndef ALCONTEXT_H
  2. #define ALCONTEXT_H
  3. #include <array>
  4. #include <atomic>
  5. #include <cstddef>
  6. #include <cstdint>
  7. #include <memory>
  8. #include <mutex>
  9. #include <thread>
  10. #include <utility>
  11. #include "AL/al.h"
  12. #include "AL/alc.h"
  13. #include "al/listener.h"
  14. #include "almalloc.h"
  15. #include "alnumeric.h"
  16. #include "alu.h"
  17. #include "atomic.h"
  18. #include "inprogext.h"
  19. #include "intrusive_ptr.h"
  20. #include "threads.h"
  21. #include "vecmat.h"
  22. #include "vector.h"
  23. struct ALeffectslot;
  24. struct ALsource;
  25. struct EffectSlot;
  26. struct EffectSlotProps;
  27. struct RingBuffer;
  28. struct Voice;
  29. struct VoiceChange;
  30. struct VoicePropsItem;
  31. enum class DistanceModel : unsigned char {
  32. Disable,
  33. Inverse, InverseClamped,
  34. Linear, LinearClamped,
  35. Exponent, ExponentClamped,
  36. Default = InverseClamped
  37. };
  38. struct WetBuffer {
  39. bool mInUse;
  40. al::FlexArray<FloatBufferLine, 16> mBuffer;
  41. WetBuffer(size_t count) : mBuffer{count} { }
  42. DEF_FAM_NEWDEL(WetBuffer, mBuffer)
  43. };
  44. using WetBufferPtr = std::unique_ptr<WetBuffer>;
  45. struct ContextProps {
  46. float DopplerFactor;
  47. float DopplerVelocity;
  48. float SpeedOfSound;
  49. bool SourceDistanceModel;
  50. DistanceModel mDistanceModel;
  51. std::atomic<ContextProps*> next;
  52. DEF_NEWDEL(ContextProps)
  53. };
  54. struct ListenerProps {
  55. std::array<float,3> Position;
  56. std::array<float,3> Velocity;
  57. std::array<float,3> OrientAt;
  58. std::array<float,3> OrientUp;
  59. float Gain;
  60. float MetersPerUnit;
  61. std::atomic<ListenerProps*> next;
  62. DEF_NEWDEL(ListenerProps)
  63. };
  64. struct ContextParams {
  65. /* Pointer to the most recent property values that are awaiting an update. */
  66. std::atomic<ContextProps*> ContextUpdate{nullptr};
  67. std::atomic<ListenerProps*> ListenerUpdate{nullptr};
  68. alu::Matrix Matrix{alu::Matrix::Identity()};
  69. alu::Vector Velocity{};
  70. float Gain{1.0f};
  71. float MetersPerUnit{1.0f};
  72. float DopplerFactor{1.0f};
  73. float SpeedOfSound{343.3f}; /* in units per sec! */
  74. bool SourceDistanceModel{false};
  75. DistanceModel mDistanceModel{};
  76. };
  77. struct SourceSubList {
  78. uint64_t FreeMask{~0_u64};
  79. ALsource *Sources{nullptr}; /* 64 */
  80. SourceSubList() noexcept = default;
  81. SourceSubList(const SourceSubList&) = delete;
  82. SourceSubList(SourceSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Sources{rhs.Sources}
  83. { rhs.FreeMask = ~0_u64; rhs.Sources = nullptr; }
  84. ~SourceSubList();
  85. SourceSubList& operator=(const SourceSubList&) = delete;
  86. SourceSubList& operator=(SourceSubList&& rhs) noexcept
  87. { std::swap(FreeMask, rhs.FreeMask); std::swap(Sources, rhs.Sources); return *this; }
  88. };
  89. struct EffectSlotSubList {
  90. uint64_t FreeMask{~0_u64};
  91. ALeffectslot *EffectSlots{nullptr}; /* 64 */
  92. EffectSlotSubList() noexcept = default;
  93. EffectSlotSubList(const EffectSlotSubList&) = delete;
  94. EffectSlotSubList(EffectSlotSubList&& rhs) noexcept
  95. : FreeMask{rhs.FreeMask}, EffectSlots{rhs.EffectSlots}
  96. { rhs.FreeMask = ~0_u64; rhs.EffectSlots = nullptr; }
  97. ~EffectSlotSubList();
  98. EffectSlotSubList& operator=(const EffectSlotSubList&) = delete;
  99. EffectSlotSubList& operator=(EffectSlotSubList&& rhs) noexcept
  100. { std::swap(FreeMask, rhs.FreeMask); std::swap(EffectSlots, rhs.EffectSlots); return *this; }
  101. };
  102. struct ALCcontext : public al::intrusive_ref<ALCcontext> {
  103. const al::intrusive_ptr<ALCdevice> mDevice;
  104. /* Counter for the pre-mixing updates, in 31.1 fixed point (lowest bit
  105. * indicates if updates are currently happening).
  106. */
  107. RefCount mUpdateCount{0u};
  108. std::atomic<bool> mHoldUpdates{false};
  109. float mGainBoost{1.0f};
  110. /* Linked lists of unused property containers, free to use for future
  111. * updates.
  112. */
  113. std::atomic<ContextProps*> mFreeContextProps{nullptr};
  114. std::atomic<ListenerProps*> mFreeListenerProps{nullptr};
  115. std::atomic<VoicePropsItem*> mFreeVoiceProps{nullptr};
  116. std::atomic<EffectSlotProps*> mFreeEffectslotProps{nullptr};
  117. /* The voice change tail is the beginning of the "free" elements, up to and
  118. * *excluding* the current. If tail==current, there's no free elements and
  119. * new ones need to be allocated. The current voice change is the element
  120. * last processed, and any after are pending.
  121. */
  122. VoiceChange *mVoiceChangeTail{};
  123. std::atomic<VoiceChange*> mCurrentVoiceChange{};
  124. void allocVoiceChanges(size_t addcount);
  125. ContextParams mParams;
  126. using VoiceArray = al::FlexArray<Voice*>;
  127. std::atomic<VoiceArray*> mVoices{};
  128. std::atomic<size_t> mActiveVoiceCount{};
  129. void allocVoices(size_t addcount);
  130. al::span<Voice*> getVoicesSpan() const noexcept
  131. {
  132. return {mVoices.load(std::memory_order_relaxed)->data(),
  133. mActiveVoiceCount.load(std::memory_order_relaxed)};
  134. }
  135. al::span<Voice*> getVoicesSpanAcquired() const noexcept
  136. {
  137. return {mVoices.load(std::memory_order_acquire)->data(),
  138. mActiveVoiceCount.load(std::memory_order_acquire)};
  139. }
  140. using EffectSlotArray = al::FlexArray<EffectSlot*>;
  141. std::atomic<EffectSlotArray*> mActiveAuxSlots{nullptr};
  142. std::thread mEventThread;
  143. al::semaphore mEventSem;
  144. std::unique_ptr<RingBuffer> mAsyncEvents;
  145. std::atomic<uint> mEnabledEvts{0u};
  146. /* Asynchronous voice change actions are processed as a linked list of
  147. * VoiceChange objects by the mixer, which is atomically appended to.
  148. * However, to avoid allocating each object individually, they're allocated
  149. * in clusters that are stored in a vector for easy automatic cleanup.
  150. */
  151. using VoiceChangeCluster = std::unique_ptr<VoiceChange[]>;
  152. al::vector<VoiceChangeCluster> mVoiceChangeClusters;
  153. using VoiceCluster = std::unique_ptr<Voice[]>;
  154. al::vector<VoiceCluster> mVoiceClusters;
  155. /* Wet buffers used by effect slots. */
  156. al::vector<WetBufferPtr> mWetBuffers;
  157. std::atomic_flag mPropsClean;
  158. std::atomic<bool> mDeferUpdates{false};
  159. std::mutex mPropLock;
  160. std::atomic<ALenum> mLastError{AL_NO_ERROR};
  161. DistanceModel mDistanceModel{DistanceModel::Default};
  162. bool mSourceDistanceModel{false};
  163. float mDopplerFactor{1.0f};
  164. float mDopplerVelocity{1.0f};
  165. float mSpeedOfSound{SpeedOfSoundMetersPerSec};
  166. std::mutex mEventCbLock;
  167. ALEVENTPROCSOFT mEventCb{};
  168. void *mEventParam{nullptr};
  169. ALlistener mListener{};
  170. al::vector<SourceSubList> mSourceList;
  171. ALuint mNumSources{0};
  172. std::mutex mSourceLock;
  173. al::vector<EffectSlotSubList> mEffectSlotList;
  174. ALuint mNumEffectSlots{0u};
  175. std::mutex mEffectSlotLock;
  176. /* Default effect slot */
  177. std::unique_ptr<ALeffectslot> mDefaultSlot;
  178. const char *mExtensionList{nullptr};
  179. ALCcontext(al::intrusive_ptr<ALCdevice> device);
  180. ALCcontext(const ALCcontext&) = delete;
  181. ALCcontext& operator=(const ALCcontext&) = delete;
  182. ~ALCcontext();
  183. void init();
  184. /**
  185. * Removes the context from its device and removes it from being current on
  186. * the running thread or globally. Returns true if other contexts still
  187. * exist on the device.
  188. */
  189. bool deinit();
  190. /**
  191. * Defers/suspends updates for the given context's listener and sources.
  192. * This does *NOT* stop mixing, but rather prevents certain property
  193. * changes from taking effect.
  194. */
  195. void deferUpdates() noexcept { mDeferUpdates.exchange(true, std::memory_order_acq_rel); }
  196. /** Resumes update processing after being deferred. */
  197. void processUpdates();
  198. [[gnu::format(printf,3,4)]] void setError(ALenum errorCode, const char *msg, ...);
  199. DEF_NEWDEL(ALCcontext)
  200. };
  201. #define SETERR_RETURN(ctx, err, retval, ...) do { \
  202. (ctx)->setError((err), __VA_ARGS__); \
  203. return retval; \
  204. } while(0)
  205. using ContextRef = al::intrusive_ptr<ALCcontext>;
  206. ContextRef GetContextRef(void);
  207. void UpdateContextProps(ALCcontext *context);
  208. extern bool TrapALError;
  209. #endif /* ALCONTEXT_H */