Add methods to lookup cached buffers without loading them
[alure.git] / src / context.h
blob67c59ec4d0a203b220a4627afaa95d667f6ae96e
1 #ifndef CONTEXT_H
2 #define CONTEXT_H
4 #include "main.h"
6 #include <condition_variable>
7 #include <unordered_map>
8 #include <stdexcept>
9 #include <thread>
10 #include <mutex>
11 #include <stack>
12 #include <queue>
13 #include <set>
14 #if __cplusplus >= 201703L
15 #include <variant>
16 #else
17 #include "mpark/variant.hpp"
18 #endif
20 #include "device.h"
21 #include "source.h"
24 #define F_PI (3.14159265358979323846f)
26 #if !(__cplusplus >= 201703L)
27 namespace std {
28 using mpark::variant;
29 using mpark::get;
30 using mpark::get_if;
31 using mpark::holds_alternative;
32 } // namespace std
33 #endif
35 namespace alure {
37 enum class AL {
38 EXT_EFX,
40 EXT_FLOAT32,
41 EXT_MCFORMATS,
42 EXT_BFORMAT,
44 EXT_MULAW,
45 EXT_MULAW_MCFORMATS,
46 EXT_MULAW_BFORMAT,
48 SOFT_loop_points,
49 SOFT_source_latency,
50 SOFT_source_resampler,
51 SOFT_source_spatialize,
53 EXT_disconnect,
55 EXT_SOURCE_RADIUS,
56 EXT_STEREO_ANGLES,
58 EXTENSION_MAX
61 // Batches OpenAL updates while the object is alive, if batching isn't already
62 // in progress.
63 class Batcher {
64 ALCcontext *mContext;
66 public:
67 Batcher(ALCcontext *context) : mContext(context) { }
68 Batcher(Batcher&& rhs) : mContext(rhs.mContext) { rhs.mContext = nullptr; }
69 Batcher(const Batcher&) = delete;
70 ~Batcher()
72 if(mContext)
73 alcProcessContext(mContext);
76 Batcher& operator=(Batcher&&) = delete;
77 Batcher& operator=(const Batcher&) = delete;
81 class ListenerImpl {
82 ContextImpl *const mContext;
84 public:
85 ListenerImpl(ContextImpl *ctx) : mContext(ctx) { }
87 void setGain(ALfloat gain);
89 void set3DParameters(const Vector3 &position, const Vector3 &velocity, const std::pair<Vector3,Vector3> &orientation);
91 void setPosition(ALfloat x, ALfloat y, ALfloat z);
92 void setPosition(const ALfloat *pos);
94 void setVelocity(ALfloat x, ALfloat y, ALfloat z);
95 void setVelocity(const ALfloat *vel);
97 void setOrientation(ALfloat x1, ALfloat y1, ALfloat z1, ALfloat x2, ALfloat y2, ALfloat z2);
98 void setOrientation(const ALfloat *at, const ALfloat *up);
99 void setOrientation(const ALfloat *ori);
101 void setMetersPerUnit(ALfloat m_u);
105 using DecoderOrExceptT = std::variant<SharedPtr<Decoder>,std::runtime_error>;
106 using BufferOrExceptT = std::variant<Buffer,std::runtime_error>;
108 class ContextImpl {
109 static ContextImpl *sCurrentCtx;
110 static thread_local ContextImpl *sThreadCurrentCtx;
112 public:
113 static void MakeCurrent(ContextImpl *context);
114 static ContextImpl *GetCurrent()
116 auto thrd_ctx = sThreadCurrentCtx;
117 return thrd_ctx ? thrd_ctx : sCurrentCtx;
120 static void MakeThreadCurrent(ContextImpl *context);
121 static ContextImpl *GetThreadCurrent() { return sThreadCurrentCtx; }
123 static std::atomic<uint64_t> sContextSetCount;
124 mutable uint64_t mContextSetCounter;
126 private:
127 ListenerImpl mListener;
128 ALCcontext *mContext;
129 std::stack<ALuint> mSourceIds;
131 struct PendingFuture { BufferImpl *mBuffer; SharedFuture<Buffer> mFuture; };
132 struct PendingSource { SourceImpl *mSource; SharedFuture<Buffer> mFuture; };
134 DeviceImpl *const mDevice;
135 Vector<PendingFuture> mFutureBuffers;
136 Vector<UniquePtr<BufferImpl>> mBuffers;
137 Vector<UniquePtr<SourceGroupImpl>> mSourceGroups;
138 std::deque<SourceImpl> mAllSources;
139 Vector<SourceImpl*> mFreeSources;
141 Vector<PendingSource> mPendingSources;
142 Vector<SourceImpl*> mFadingSources;
143 Vector<SourceBufferUpdateEntry> mPlaySources;
144 Vector<SourceStreamUpdateEntry> mStreamSources;
146 Vector<SourceImpl*> mStreamingSources;
147 std::mutex mSourceStreamMutex;
149 std::atomic<std::chrono::milliseconds> mWakeInterval;
150 std::mutex mWakeMutex;
151 std::condition_variable mWakeThread;
153 SharedPtr<MessageHandler> mMessage;
155 struct PendingBuffer {
156 BufferImpl *mBuffer{nullptr};
157 SharedPtr<Decoder> mDecoder;
158 ALenum mFormat{0};
159 ALuint mFrames{0};
160 Promise<Buffer> mPromise;
162 std::atomic<PendingBuffer*> mNext{nullptr};
164 PendingBuffer() = default;
165 PendingBuffer(BufferImpl *buffer, SharedPtr<Decoder> decoder, ALenum format, ALuint frames,
166 Promise<Buffer> promise)
167 : mBuffer(buffer), mDecoder(std::move(decoder)), mFormat(format), mFrames(frames)
168 , mPromise(std::move(promise)), mNext(nullptr)
171 std::atomic<PendingBuffer*> mPendingCurrent;
172 PendingBuffer *mPendingTail;
173 PendingBuffer *mPendingHead;
175 std::atomic<bool> mQuitThread;
176 std::thread mThread;
177 void backgroundProc();
179 size_t mRefs;
181 Vector<String> mResamplers;
183 Bitfield<static_cast<size_t>(AL::EXTENSION_MAX)> mHasExt;
185 std::once_flag mSetExts;
186 void setupExts();
188 DecoderOrExceptT findDecoder(StringView name);
189 BufferOrExceptT doCreateBuffer(StringView name, Vector<UniquePtr<BufferImpl>>::iterator iter, SharedPtr<Decoder> decoder);
190 BufferOrExceptT doCreateBufferAsync(StringView name, Vector<UniquePtr<BufferImpl>>::iterator iter, SharedPtr<Decoder> decoder, Promise<Buffer> promise);
192 bool mIsConnected : 1;
193 bool mIsBatching : 1;
195 public:
196 ContextImpl(ALCcontext *context, DeviceImpl *device);
197 ~ContextImpl();
199 ALCcontext *getALCcontext() const { return mContext; }
200 long addRef() { return ++mRefs; }
201 long decRef() { return --mRefs; }
203 bool hasExtension(AL ext) const { return mHasExt[static_cast<size_t>(ext)]; }
205 LPALGETSTRINGISOFT alGetStringiSOFT;
206 LPALGETSOURCEI64VSOFT alGetSourcei64vSOFT;
207 LPALGETSOURCEDVSOFT alGetSourcedvSOFT;
209 LPALGENEFFECTS alGenEffects;
210 LPALDELETEEFFECTS alDeleteEffects;
211 LPALISEFFECT alIsEffect;
212 LPALEFFECTI alEffecti;
213 LPALEFFECTIV alEffectiv;
214 LPALEFFECTF alEffectf;
215 LPALEFFECTFV alEffectfv;
216 LPALGETEFFECTI alGetEffecti;
217 LPALGETEFFECTIV alGetEffectiv;
218 LPALGETEFFECTF alGetEffectf;
219 LPALGETEFFECTFV alGetEffectfv;
221 LPALGENFILTERS alGenFilters;
222 LPALDELETEFILTERS alDeleteFilters;
223 LPALISFILTER alIsFilter;
224 LPALFILTERI alFilteri;
225 LPALFILTERIV alFilteriv;
226 LPALFILTERF alFilterf;
227 LPALFILTERFV alFilterfv;
228 LPALGETFILTERI alGetFilteri;
229 LPALGETFILTERIV alGetFilteriv;
230 LPALGETFILTERF alGetFilterf;
231 LPALGETFILTERFV alGetFilterfv;
233 LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots;
234 LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots;
235 LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot;
236 LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti;
237 LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv;
238 LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf;
239 LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv;
240 LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti;
241 LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv;
242 LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf;
243 LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv;
245 ALuint getSourceId(ALuint maxprio);
246 void insertSourceId(ALuint id) { mSourceIds.push(id); }
248 void addPendingSource(SourceImpl *source, SharedFuture<Buffer> future);
249 void removePendingSource(SourceImpl *source);
250 bool isPendingSource(const SourceImpl *source) const;
251 void addFadingSource(SourceImpl *source);
252 void removeFadingSource(SourceImpl *source);
253 void addPlayingSource(SourceImpl *source, ALuint id);
254 void addPlayingSource(SourceImpl *source);
255 void removePlayingSource(SourceImpl *source);
257 void addStream(SourceImpl *source);
258 void removeStream(SourceImpl *source);
259 void removeStreamNoLock(SourceImpl *source);
261 void freeSource(SourceImpl *source) { mFreeSources.push_back(source); }
262 void freeSourceGroup(SourceGroupImpl *group);
264 Batcher getBatcher()
266 if(mIsBatching)
267 return Batcher(nullptr);
268 alcSuspendContext(mContext);
269 return Batcher(mContext);
272 std::unique_lock<std::mutex> getSourceStreamLock()
273 { return std::unique_lock<std::mutex>(mSourceStreamMutex); }
275 template<typename R, typename... Args>
276 void send(R MessageHandler::* func, Args&&... args)
277 { if(mMessage.get()) (mMessage.get()->*func)(std::forward<Args>(args)...); }
279 Device getDevice() { return Device(mDevice); }
281 void destroy();
283 void startBatch();
284 void endBatch();
286 Listener getListener() { return Listener(&mListener); }
288 SharedPtr<MessageHandler> setMessageHandler(SharedPtr<MessageHandler>&& handler);
289 SharedPtr<MessageHandler> getMessageHandler() const { return mMessage; }
291 void setAsyncWakeInterval(std::chrono::milliseconds interval);
292 std::chrono::milliseconds getAsyncWakeInterval() const { return mWakeInterval.load(); }
294 SharedPtr<Decoder> createDecoder(StringView name);
296 bool isSupported(ChannelConfig channels, SampleType type) const;
298 ArrayView<String> getAvailableResamplers();
299 ALsizei getDefaultResamplerIndex() const;
301 Buffer getBuffer(StringView name);
302 SharedFuture<Buffer> getBufferAsync(StringView name);
303 void precacheBuffersAsync(ArrayView<StringView> names);
304 Buffer createBufferFrom(StringView name, SharedPtr<Decoder>&& decoder);
305 SharedFuture<Buffer> createBufferAsyncFrom(StringView name, SharedPtr<Decoder>&& decoder);
306 Buffer findBuffer(StringView name);
307 SharedFuture<Buffer> findBufferAsync(StringView name);
308 void removeBuffer(StringView name);
309 void removeBuffer(Buffer buffer) { removeBuffer(buffer.getName()); }
311 Source createSource();
313 AuxiliaryEffectSlot createAuxiliaryEffectSlot();
315 Effect createEffect();
317 SourceGroup createSourceGroup(StringView name);
318 SourceGroup getSourceGroup(StringView name);
320 void setDopplerFactor(ALfloat factor);
322 void setSpeedOfSound(ALfloat speed);
324 void setDistanceModel(DistanceModel model);
326 void update();
330 inline void CheckContext(const ContextImpl *ctx)
332 auto count = ContextImpl::sContextSetCount.load(std::memory_order_acquire);
333 if(UNLIKELY(count != ctx->mContextSetCounter))
335 if(UNLIKELY(ctx != ContextImpl::GetCurrent()))
336 throw std::runtime_error("Called context is not current");
337 ctx->mContextSetCounter = count;
341 inline void CheckContexts(const ContextImpl *ctx0, const ContextImpl *ctx1)
343 if(UNLIKELY(ctx0 != ctx1))
344 throw std::runtime_error("Mismatched object contexts");
348 } // namespace alure
350 #endif /* CONTEXT_H */