2018-11-17 23:02:27 -08:00
|
|
|
#ifndef ALCONTEXT_H
|
|
|
|
#define ALCONTEXT_H
|
|
|
|
|
2018-11-20 10:55:57 -08:00
|
|
|
#include <atomic>
|
2019-08-01 09:21:56 -07:00
|
|
|
#include <cstddef>
|
|
|
|
#include <cstdint>
|
2018-11-20 05:01:08 -08:00
|
|
|
#include <memory>
|
2019-08-01 09:21:56 -07:00
|
|
|
#include <mutex>
|
2018-11-18 18:04:27 -08:00
|
|
|
#include <thread>
|
2019-08-01 09:21:56 -07:00
|
|
|
#include <utility>
|
2018-11-18 18:04:27 -08:00
|
|
|
|
2018-11-17 23:02:27 -08:00
|
|
|
#include "AL/al.h"
|
|
|
|
#include "AL/alc.h"
|
|
|
|
|
2019-07-30 21:32:05 -07:00
|
|
|
#include "al/listener.h"
|
2018-11-18 00:38:31 -08:00
|
|
|
#include "almalloc.h"
|
2019-02-11 11:07:06 -08:00
|
|
|
#include "alnumeric.h"
|
2019-06-09 18:13:54 -07:00
|
|
|
#include "alu.h"
|
2019-07-30 21:32:05 -07:00
|
|
|
#include "atomic.h"
|
|
|
|
#include "inprogext.h"
|
2019-08-01 13:28:53 -07:00
|
|
|
#include "intrusive_ptr.h"
|
2019-07-30 21:32:05 -07:00
|
|
|
#include "logging.h"
|
|
|
|
#include "threads.h"
|
|
|
|
#include "vector.h"
|
2019-10-02 16:53:23 -07:00
|
|
|
#include "voice.h"
|
2018-11-17 23:41:11 -08:00
|
|
|
|
2018-11-17 23:02:27 -08:00
|
|
|
struct ALeffectslot;
|
|
|
|
struct ALeffectslotProps;
|
2019-08-01 09:21:56 -07:00
|
|
|
struct ALsource;
|
2018-12-26 21:22:17 -08:00
|
|
|
struct RingBuffer;
|
2018-11-17 23:02:27 -08:00
|
|
|
|
2019-08-01 09:21:56 -07:00
|
|
|
|
2018-11-17 23:02:27 -08:00
|
|
|
enum class DistanceModel {
|
|
|
|
InverseClamped = AL_INVERSE_DISTANCE_CLAMPED,
|
|
|
|
LinearClamped = AL_LINEAR_DISTANCE_CLAMPED,
|
|
|
|
ExponentClamped = AL_EXPONENT_DISTANCE_CLAMPED,
|
|
|
|
Inverse = AL_INVERSE_DISTANCE,
|
|
|
|
Linear = AL_LINEAR_DISTANCE,
|
|
|
|
Exponent = AL_EXPONENT_DISTANCE,
|
|
|
|
Disable = AL_NONE,
|
|
|
|
|
|
|
|
Default = InverseClamped
|
|
|
|
};
|
|
|
|
|
2019-08-01 09:21:56 -07:00
|
|
|
|
|
|
|
struct ALcontextProps {
|
|
|
|
ALfloat DopplerFactor;
|
|
|
|
ALfloat DopplerVelocity;
|
|
|
|
ALfloat SpeedOfSound;
|
|
|
|
ALboolean SourceDistanceModel;
|
|
|
|
DistanceModel mDistanceModel;
|
|
|
|
|
|
|
|
std::atomic<ALcontextProps*> next;
|
2019-08-13 22:25:59 -07:00
|
|
|
|
|
|
|
DEF_NEWDEL(ALcontextProps)
|
2019-08-01 09:21:56 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2020-02-20 22:50:37 -08:00
|
|
|
struct VoiceChange {
|
|
|
|
ALvoice *mVoice{nullptr};
|
|
|
|
ALuint mSourceID{0};
|
|
|
|
ALenum mState{0};
|
|
|
|
|
|
|
|
std::atomic<VoiceChange*> mNext{nullptr};
|
|
|
|
|
|
|
|
DEF_NEWDEL(VoiceChange)
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2018-11-17 23:02:27 -08:00
|
|
|
struct SourceSubList {
|
2019-02-11 11:07:06 -08:00
|
|
|
uint64_t FreeMask{~0_u64};
|
2018-11-18 02:15:31 -08:00
|
|
|
ALsource *Sources{nullptr}; /* 64 */
|
2018-11-25 08:42:43 -08:00
|
|
|
|
|
|
|
SourceSubList() noexcept = default;
|
|
|
|
SourceSubList(const SourceSubList&) = delete;
|
|
|
|
SourceSubList(SourceSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Sources{rhs.Sources}
|
2019-02-11 11:07:06 -08:00
|
|
|
{ rhs.FreeMask = ~0_u64; rhs.Sources = nullptr; }
|
2018-11-25 08:42:43 -08:00
|
|
|
~SourceSubList();
|
|
|
|
|
|
|
|
SourceSubList& operator=(const SourceSubList&) = delete;
|
|
|
|
SourceSubList& operator=(SourceSubList&& rhs) noexcept
|
|
|
|
{ std::swap(FreeMask, rhs.FreeMask); std::swap(Sources, rhs.Sources); return *this; }
|
2018-11-17 23:02:27 -08:00
|
|
|
};
|
|
|
|
|
2019-02-20 22:00:26 -08:00
|
|
|
struct EffectSlotSubList {
|
|
|
|
uint64_t FreeMask{~0_u64};
|
|
|
|
ALeffectslot *EffectSlots{nullptr}; /* 64 */
|
|
|
|
|
|
|
|
EffectSlotSubList() noexcept = default;
|
|
|
|
EffectSlotSubList(const EffectSlotSubList&) = delete;
|
|
|
|
EffectSlotSubList(EffectSlotSubList&& rhs) noexcept
|
|
|
|
: FreeMask{rhs.FreeMask}, EffectSlots{rhs.EffectSlots}
|
|
|
|
{ rhs.FreeMask = ~0_u64; rhs.EffectSlots = nullptr; }
|
|
|
|
~EffectSlotSubList();
|
|
|
|
|
|
|
|
EffectSlotSubList& operator=(const EffectSlotSubList&) = delete;
|
|
|
|
EffectSlotSubList& operator=(EffectSlotSubList&& rhs) noexcept
|
|
|
|
{ std::swap(FreeMask, rhs.FreeMask); std::swap(EffectSlots, rhs.EffectSlots); return *this; }
|
|
|
|
};
|
2018-11-17 23:02:27 -08:00
|
|
|
|
2019-08-01 13:28:53 -07:00
|
|
|
struct ALCcontext : public al::intrusive_ref<ALCcontext> {
|
2019-07-30 09:05:54 -07:00
|
|
|
al::vector<SourceSubList> mSourceList;
|
|
|
|
ALuint mNumSources{0};
|
|
|
|
std::mutex mSourceLock;
|
2018-11-17 23:02:27 -08:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
al::vector<EffectSlotSubList> mEffectSlotList;
|
|
|
|
ALuint mNumEffectSlots{0u};
|
|
|
|
std::mutex mEffectSlotLock;
|
2018-11-17 23:02:27 -08:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::atomic<ALenum> mLastError{AL_NO_ERROR};
|
2018-11-17 23:02:27 -08:00
|
|
|
|
2018-11-18 05:40:00 -08:00
|
|
|
DistanceModel mDistanceModel{DistanceModel::Default};
|
2019-07-30 09:05:54 -07:00
|
|
|
ALboolean mSourceDistanceModel{AL_FALSE};
|
2018-11-17 23:02:27 -08:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
ALfloat mDopplerFactor{1.0f};
|
|
|
|
ALfloat mDopplerVelocity{1.0f};
|
2019-08-02 18:30:22 -07:00
|
|
|
ALfloat mSpeedOfSound{SPEEDOFSOUNDMETRESPERSEC};
|
2018-11-17 23:02:27 -08:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::atomic_flag mPropsClean;
|
|
|
|
std::atomic<bool> mDeferUpdates{false};
|
2018-11-17 23:02:27 -08:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::mutex mPropLock;
|
2018-11-17 23:02:27 -08:00
|
|
|
|
|
|
|
/* Counter for the pre-mixing updates, in 31.1 fixed point (lowest bit
|
|
|
|
* indicates if updates are currently happening).
|
|
|
|
*/
|
2019-07-30 09:05:54 -07:00
|
|
|
RefCount mUpdateCount{0u};
|
|
|
|
std::atomic<bool> mHoldUpdates{false};
|
2018-11-17 23:02:27 -08:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
ALfloat mGainBoost{1.0f};
|
2018-11-17 23:02:27 -08:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::atomic<ALcontextProps*> mUpdate{nullptr};
|
2018-11-17 23:02:27 -08:00
|
|
|
|
|
|
|
/* Linked lists of unused property containers, free to use for future
|
|
|
|
* updates.
|
|
|
|
*/
|
2019-07-30 09:05:54 -07:00
|
|
|
std::atomic<ALcontextProps*> mFreeContextProps{nullptr};
|
|
|
|
std::atomic<ALlistenerProps*> mFreeListenerProps{nullptr};
|
|
|
|
std::atomic<ALvoiceProps*> mFreeVoiceProps{nullptr};
|
|
|
|
std::atomic<ALeffectslotProps*> mFreeEffectslotProps{nullptr};
|
2018-11-17 23:02:27 -08:00
|
|
|
|
2020-02-20 22:50:37 -08:00
|
|
|
/* Asynchronous voice change actions are processed as a linked list of
|
|
|
|
* VoiceChange objects by the mixer, which is atomically appended to.
|
|
|
|
* However, to avoid allocating each object individually, they're allocated
|
|
|
|
* in clusters that are stored in a vector for easy automatic cleanup.
|
|
|
|
*/
|
|
|
|
using VoiceChangeCluster = std::unique_ptr<VoiceChange[]>;
|
2020-02-21 20:14:28 -08:00
|
|
|
al::vector<VoiceChangeCluster> mVoiceChangeClusters;
|
2020-02-20 22:50:37 -08:00
|
|
|
|
|
|
|
/* The voice change tail is the beginning of the "free" elements, up to and
|
|
|
|
* *excluding* the current. If tail==current, there's no free elements and
|
|
|
|
* new ones need to be allocated. The current voice change is the element
|
|
|
|
* last processed, and any after are pending.
|
|
|
|
*/
|
|
|
|
VoiceChange *mVoiceChangeTail{};
|
|
|
|
std::atomic<VoiceChange*> mCurrentVoiceChange{};
|
|
|
|
|
|
|
|
void allocVoiceChanges(size_t addcount);
|
|
|
|
|
2020-02-21 20:14:28 -08:00
|
|
|
|
|
|
|
using VoiceCluster = std::unique_ptr<ALvoice[]>;
|
|
|
|
al::vector<VoiceCluster> mVoiceClusters;
|
|
|
|
|
|
|
|
using ALvoiceArray = al::FlexArray<ALvoice*>;
|
|
|
|
std::atomic<ALvoiceArray*> mVoices{};
|
|
|
|
std::atomic<size_t> mActiveVoiceCount{};
|
|
|
|
|
|
|
|
void allocVoices(size_t addcount);
|
|
|
|
al::span<ALvoice*> getVoicesSpan() const noexcept
|
|
|
|
{
|
|
|
|
return {mVoices.load(std::memory_order_relaxed)->data(),
|
|
|
|
mActiveVoiceCount.load(std::memory_order_relaxed)};
|
|
|
|
}
|
|
|
|
al::span<ALvoice*> getVoicesSpanAcquired() const noexcept
|
|
|
|
{
|
|
|
|
return {mVoices.load(std::memory_order_acquire)->data(),
|
|
|
|
mActiveVoiceCount.load(std::memory_order_acquire)};
|
|
|
|
}
|
|
|
|
|
2018-11-17 23:02:27 -08:00
|
|
|
|
2019-01-11 07:28:44 -08:00
|
|
|
using ALeffectslotArray = al::FlexArray<ALeffectslot*>;
|
2019-07-30 09:05:54 -07:00
|
|
|
std::atomic<ALeffectslotArray*> mActiveAuxSlots{nullptr};
|
2018-11-17 23:02:27 -08:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::thread mEventThread;
|
|
|
|
al::semaphore mEventSem;
|
|
|
|
std::unique_ptr<RingBuffer> mAsyncEvents;
|
|
|
|
std::atomic<ALbitfieldSOFT> mEnabledEvts{0u};
|
|
|
|
std::mutex mEventCbLock;
|
|
|
|
ALEVENTPROCSOFT mEventCb{};
|
|
|
|
void *mEventParam{nullptr};
|
2018-11-17 23:02:27 -08:00
|
|
|
|
|
|
|
/* Default effect slot */
|
2019-07-30 09:05:54 -07:00
|
|
|
std::unique_ptr<ALeffectslot> mDefaultSlot;
|
2018-11-17 23:02:27 -08:00
|
|
|
|
2019-08-01 19:44:09 -07:00
|
|
|
const al::intrusive_ptr<ALCdevice> mDevice;
|
2019-07-30 09:05:54 -07:00
|
|
|
const ALCchar *mExtensionList{nullptr};
|
2018-11-17 23:02:27 -08:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
ALlistener mListener{};
|
2018-11-18 05:40:00 -08:00
|
|
|
|
|
|
|
|
2019-08-01 19:44:09 -07:00
|
|
|
ALCcontext(al::intrusive_ptr<ALCdevice> device);
|
2019-01-01 18:13:33 -08:00
|
|
|
ALCcontext(const ALCcontext&) = delete;
|
|
|
|
ALCcontext& operator=(const ALCcontext&) = delete;
|
|
|
|
~ALCcontext();
|
2018-11-18 00:38:31 -08:00
|
|
|
|
2019-08-02 18:30:22 -07:00
|
|
|
void init();
|
|
|
|
/**
|
|
|
|
* Removes the context from its device and removes it from being current on
|
|
|
|
* the running thread or globally. Returns true if other contexts still
|
|
|
|
* exist on the device.
|
|
|
|
*/
|
|
|
|
bool deinit();
|
|
|
|
|
2019-07-30 14:13:05 -07:00
|
|
|
/**
|
|
|
|
* Defers/suspends updates for the given context's listener and sources.
|
|
|
|
* This does *NOT* stop mixing, but rather prevents certain property
|
|
|
|
* changes from taking effect.
|
|
|
|
*/
|
2019-08-01 09:21:56 -07:00
|
|
|
void deferUpdates() noexcept { mDeferUpdates.store(true); }
|
2019-07-30 14:13:05 -07:00
|
|
|
|
|
|
|
/** Resumes update processing after being deferred. */
|
|
|
|
void processUpdates();
|
|
|
|
|
2019-07-30 21:32:05 -07:00
|
|
|
void setError(ALenum errorCode, const char *msg, ...) DECL_FORMAT(printf, 3, 4);
|
|
|
|
|
2018-11-18 00:38:31 -08:00
|
|
|
DEF_NEWDEL(ALCcontext)
|
2018-11-17 23:02:27 -08:00
|
|
|
};
|
|
|
|
|
2019-07-30 21:32:05 -07:00
|
|
|
#define SETERR_RETURN(ctx, err, retval, ...) do { \
|
|
|
|
(ctx)->setError((err), __VA_ARGS__); \
|
|
|
|
return retval; \
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
|
2019-08-01 15:19:37 -07:00
|
|
|
using ContextRef = al::intrusive_ptr<ALCcontext>;
|
2019-06-29 22:38:38 -07:00
|
|
|
|
2018-11-24 14:07:32 -08:00
|
|
|
ContextRef GetContextRef(void);
|
|
|
|
|
2019-08-01 15:19:37 -07:00
|
|
|
void UpdateContextProps(ALCcontext *context);
|
|
|
|
|
2018-11-17 23:02:27 -08:00
|
|
|
|
2019-07-30 21:32:05 -07:00
|
|
|
extern bool TrapALError;
|
|
|
|
|
2018-11-17 23:02:27 -08:00
|
|
|
#endif /* ALCONTEXT_H */
|