openal-soft/alc/alcontext.h

191 lines
5.3 KiB
C
Raw Normal View History

#ifndef ALCONTEXT_H
#define ALCONTEXT_H
#include <atomic>
2019-08-01 09:21:56 -07:00
#include <cstddef>
#include <cstdint>
#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
#include "AL/al.h"
#include "AL/alc.h"
#include "al/listener.h"
2018-11-18 00:38:31 -08:00
#include "almalloc.h"
#include "alnumeric.h"
#include "alu.h"
#include "atomic.h"
#include "inprogext.h"
#include "intrusive_ptr.h"
#include "logging.h"
#include "threads.h"
#include "vector.h"
struct ALeffectslot;
struct ALeffectslotProps;
2019-08-01 09:21:56 -07:00
struct ALsource;
struct RingBuffer;
2019-08-01 09:21:56 -07: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;
ALfloat MetersPerUnit;
std::atomic<ALcontextProps*> next;
};
struct SourceSubList {
uint64_t FreeMask{~0_u64};
ALsource *Sources{nullptr}; /* 64 */
SourceSubList() noexcept = default;
SourceSubList(const SourceSubList&) = delete;
SourceSubList(SourceSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Sources{rhs.Sources}
{ rhs.FreeMask = ~0_u64; rhs.Sources = nullptr; }
~SourceSubList();
SourceSubList& operator=(const SourceSubList&) = delete;
SourceSubList& operator=(SourceSubList&& rhs) noexcept
{ std::swap(FreeMask, rhs.FreeMask); std::swap(Sources, rhs.Sources); return *this; }
};
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; }
};
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;
2019-07-30 09:05:54 -07:00
al::vector<EffectSlotSubList> mEffectSlotList;
ALuint mNumEffectSlots{0u};
std::mutex mEffectSlotLock;
2019-07-30 09:05:54 -07:00
std::atomic<ALenum> mLastError{AL_NO_ERROR};
DistanceModel mDistanceModel{DistanceModel::Default};
2019-07-30 09:05:54 -07:00
ALboolean mSourceDistanceModel{AL_FALSE};
2019-07-30 09:05:54 -07:00
ALfloat mDopplerFactor{1.0f};
ALfloat mDopplerVelocity{1.0f};
ALfloat mSpeedOfSound{};
ALfloat mMetersPerUnit{1.0f};
2019-07-30 09:05:54 -07:00
std::atomic_flag mPropsClean;
std::atomic<bool> mDeferUpdates{false};
2019-07-30 09:05:54 -07:00
std::mutex mPropLock;
/* 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};
2019-07-30 09:05:54 -07:00
ALfloat mGainBoost{1.0f};
2019-07-30 09:05:54 -07:00
std::atomic<ALcontextProps*> mUpdate{nullptr};
/* 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};
2019-07-30 09:05:54 -07:00
std::unique_ptr<al::FlexArray<ALvoice>> mVoices{nullptr};
std::atomic<ALuint> mVoiceCount{0u};
using ALeffectslotArray = al::FlexArray<ALeffectslot*>;
2019-07-30 09:05:54 -07:00
std::atomic<ALeffectslotArray*> mActiveAuxSlots{nullptr};
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};
/* Default effect slot */
2019-07-30 09:05:54 -07:00
std::unique_ptr<ALeffectslot> mDefaultSlot;
2019-07-30 09:05:54 -07:00
ALCdevice *const mDevice;
const ALCchar *mExtensionList{nullptr};
2019-07-30 09:05:54 -07:00
ALlistener mListener{};
ALCcontext(ALCdevice *device);
ALCcontext(const ALCcontext&) = delete;
ALCcontext& operator=(const ALCcontext&) = delete;
~ALCcontext();
2018-11-18 00:38:31 -08:00
2019-07-30 14:13:05 -07:00
void allocVoices(size_t num_voices);
/**
* 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();
void setError(ALenum errorCode, const char *msg, ...) DECL_FORMAT(printf, 3, 4);
2018-11-18 00:38:31 -08:00
DEF_NEWDEL(ALCcontext)
};
#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>;
2018-11-24 14:07:32 -08:00
ContextRef GetContextRef(void);
2019-08-01 15:19:37 -07:00
void UpdateContextProps(ALCcontext *context);
extern bool TrapALError;
#endif /* ALCONTEXT_H */