diff options
-rw-r--r-- | al/event.cpp | 94 | ||||
-rw-r--r-- | alc/alu.cpp | 31 | ||||
-rw-r--r-- | core/async_event.h | 89 | ||||
-rw-r--r-- | core/context.h | 3 | ||||
-rw-r--r-- | core/voice.cpp | 20 |
5 files changed, 129 insertions, 108 deletions
diff --git a/al/event.cpp b/al/event.cpp index 4fa1bf56..eb6af45c 100644 --- a/al/event.cpp +++ b/al/event.cpp @@ -32,7 +32,15 @@ #include "threads.h" -static int EventThread(ALCcontext *context) +namespace { + +template<typename... Ts> +struct overloaded : Ts... { using Ts::operator()...; }; + +template<typename... Ts> +overloaded(Ts...) -> overloaded<Ts...>; + +int EventThread(ALCcontext *context) { RingBuffer *ring{context->mAsyncEvents.get()}; bool quitnow{false}; @@ -51,81 +59,87 @@ static int EventThread(ALCcontext *context) evt_data.buf += sizeof(AsyncEvent); evt_data.len -= 1; - AsyncEvent evt{*evt_ptr}; + AsyncEvent event{std::move(*evt_ptr)}; std::destroy_at(evt_ptr); ring->readAdvance(1); - quitnow = evt.EnumType == AsyncEvent::KillThread; + quitnow = std::holds_alternative<AsyncKillThread>(event); if(quitnow) UNLIKELY break; - if(evt.EnumType == AsyncEvent::ReleaseEffectState) - { - al::intrusive_ptr<EffectState>{evt.u.mEffectState}; - continue; - } - auto enabledevts = context->mEnabledEvts.load(std::memory_order_acquire); - if(!context->mEventCb) continue; - - if(evt.EnumType == AsyncEvent::SourceStateChange) + auto proc_killthread = [](AsyncKillThread&) { }; + auto proc_release = [](AsyncEffectReleaseEvent &evt) + { + al::intrusive_ptr<EffectState>{evt.mEffectState}; + }; + auto proc_srcstate = [context,enabledevts](AsyncSourceStateEvent &evt) { - if(!enabledevts.test(AsyncEvent::SourceStateChange)) - continue; + if(!context->mEventCb + || !enabledevts.test(al::to_underlying(AsyncEnableBits::SourceState))) + return; ALuint state{}; - std::string msg{"Source ID " + std::to_string(evt.u.srcstate.id)}; + std::string msg{"Source ID " + std::to_string(evt.mId)}; msg += " state has changed to "; - switch(evt.u.srcstate.state) + switch(evt.mState) { - case AsyncEvent::SrcState::Reset: + case AsyncSrcState::Reset: msg += "AL_INITIAL"; state = AL_INITIAL; break; - case AsyncEvent::SrcState::Stop: + case AsyncSrcState::Stop: msg += "AL_STOPPED"; state = AL_STOPPED; break; - case AsyncEvent::SrcState::Play: + case AsyncSrcState::Play: msg += "AL_PLAYING"; state = AL_PLAYING; break; - case AsyncEvent::SrcState::Pause: + case AsyncSrcState::Pause: msg += "AL_PAUSED"; state = AL_PAUSED; break; } - context->mEventCb(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT, evt.u.srcstate.id, - state, static_cast<ALsizei>(msg.length()), msg.c_str(), context->mEventParam); - } - else if(evt.EnumType == AsyncEvent::BufferCompleted) + context->mEventCb(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT, evt.mId, state, + static_cast<ALsizei>(msg.length()), msg.c_str(), context->mEventParam); + }; + auto proc_buffercomp = [context,enabledevts](AsyncBufferCompleteEvent &evt) { - if(!enabledevts.test(AsyncEvent::BufferCompleted)) - continue; + if(!context->mEventCb + || !enabledevts.test(al::to_underlying(AsyncEnableBits::BufferCompleted))) + return; - std::string msg{std::to_string(evt.u.bufcomp.count)}; - if(evt.u.bufcomp.count == 1) msg += " buffer completed"; + std::string msg{std::to_string(evt.mCount)}; + if(evt.mCount == 1) msg += " buffer completed"; else msg += " buffers completed"; - context->mEventCb(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, evt.u.bufcomp.id, - evt.u.bufcomp.count, static_cast<ALsizei>(msg.length()), msg.c_str(), - context->mEventParam); - } - else if(evt.EnumType == AsyncEvent::Disconnected) + context->mEventCb(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, evt.mId, evt.mCount, + static_cast<ALsizei>(msg.length()), msg.c_str(), context->mEventParam); + }; + auto proc_disconnect = [context,enabledevts](AsyncDisconnectEvent &evt) { - const std::string_view message{evt.u.disconnect.msg}; + const std::string_view message{evt.msg}; context->debugMessage(DebugSource::System, DebugType::Error, 0, DebugSeverity::High, static_cast<ALsizei>(message.length()), message.data()); - if(enabledevts.test(AsyncEvent::Disconnected)) + if(context->mEventCb + && enabledevts.test(al::to_underlying(AsyncEnableBits::Disconnected))) context->mEventCb(AL_EVENT_TYPE_DISCONNECTED_SOFT, 0, 0, static_cast<ALsizei>(message.length()), message.data(), context->mEventParam); - } + }; + + std::visit(overloaded + {proc_srcstate, proc_buffercomp, proc_release, proc_disconnect, proc_killthread}, + event); } while(evt_data.len != 0); } return 0; } +} // namespace + + void StartEventThrd(ALCcontext *ctx) { try { @@ -150,7 +164,7 @@ void StopEventThrd(ALCcontext *ctx) evt_data = ring->getWriteVector().first; } while(evt_data.len == 0); } - al::construct_at(reinterpret_cast<AsyncEvent*>(evt_data.buf), AsyncEvent::KillThread); + std::ignore = InitAsyncEvent<AsyncKillThread>(reinterpret_cast<AsyncEvent*>(evt_data.buf)); ring->writeAdvance(1); ctx->mEventSem.post(); @@ -174,11 +188,11 @@ START_API_FUNC [&flags](ALenum type) noexcept -> bool { if(type == AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT) - flags.set(AsyncEvent::BufferCompleted); + flags.set(al::to_underlying(AsyncEnableBits::BufferCompleted)); else if(type == AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT) - flags.set(AsyncEvent::SourceStateChange); + flags.set(al::to_underlying(AsyncEnableBits::SourceState)); else if(type == AL_EVENT_TYPE_DISCONNECTED_SOFT) - flags.set(AsyncEvent::Disconnected); + flags.set(al::to_underlying(AsyncEnableBits::Disconnected)); else return false; return true; diff --git a/alc/alu.cpp b/alc/alu.cpp index 1157aca3..cf250988 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -491,9 +491,9 @@ bool CalcEffectSlotParams(EffectSlot *slot, EffectSlot **sorted_slots, ContextBa auto evt_vec = ring->getWriteVector(); if(evt_vec.first.len > 0) LIKELY { - AsyncEvent *evt{al::construct_at(reinterpret_cast<AsyncEvent*>(evt_vec.first.buf), - AsyncEvent::ReleaseEffectState)}; - evt->u.mEffectState = oldstate; + AsyncEffectReleaseEvent &evt = InitAsyncEvent<AsyncEffectReleaseEvent>( + reinterpret_cast<AsyncEvent*>(evt_vec.first.buf)); + evt.mEffectState = oldstate; ring->writeAdvance(1); } else @@ -1701,22 +1701,22 @@ void SendSourceStateEvent(ContextBase *context, uint id, VChangeState state) auto evt_vec = ring->getWriteVector(); if(evt_vec.first.len < 1) return; - AsyncEvent *evt{al::construct_at(reinterpret_cast<AsyncEvent*>(evt_vec.first.buf), - AsyncEvent::SourceStateChange)}; - evt->u.srcstate.id = id; + AsyncSourceStateEvent &evt = InitAsyncEvent<AsyncSourceStateEvent>( + reinterpret_cast<AsyncEvent*>(evt_vec.first.buf)); + evt.mId = id; switch(state) { case VChangeState::Reset: - evt->u.srcstate.state = AsyncEvent::SrcState::Reset; + evt.mState = AsyncSrcState::Reset; break; case VChangeState::Stop: - evt->u.srcstate.state = AsyncEvent::SrcState::Stop; + evt.mState = AsyncSrcState::Stop; break; case VChangeState::Play: - evt->u.srcstate.state = AsyncEvent::SrcState::Play; + evt.mState = AsyncSrcState::Play; break; case VChangeState::Pause: - evt->u.srcstate.state = AsyncEvent::SrcState::Pause; + evt.mState = AsyncSrcState::Pause; break; /* Shouldn't happen. */ case VChangeState::Restart: @@ -1813,7 +1813,7 @@ void ProcessVoiceChanges(ContextBase *ctx) } oldvoice->mPendingChange.store(false, std::memory_order_release); } - if(sendevt && enabledevt.test(AsyncEvent::SourceStateChange)) + if(sendevt && enabledevt.test(al::to_underlying(AsyncEnableBits::SourceState))) SendSourceStateEvent(ctx, cur->mSourceID, cur->mState); next = cur->mNext.load(std::memory_order_acquire); @@ -2166,15 +2166,16 @@ void DeviceBase::handleDisconnect(const char *msg, ...) IncrementRef(MixCount); if(Connected.exchange(false, std::memory_order_acq_rel)) { - AsyncEvent evt{AsyncEvent::Disconnected}; + AsyncEvent evt{std::in_place_type<AsyncDisconnectEvent>}; + auto &disconnect = std::get<AsyncDisconnectEvent>(evt); va_list args; va_start(args, msg); - int msglen{vsnprintf(evt.u.disconnect.msg, sizeof(evt.u.disconnect.msg), msg, args)}; + int msglen{vsnprintf(disconnect.msg, sizeof(disconnect.msg), msg, args)}; va_end(args); - if(msglen < 0 || static_cast<size_t>(msglen) >= sizeof(evt.u.disconnect.msg)) - evt.u.disconnect.msg[sizeof(evt.u.disconnect.msg)-1] = 0; + if(msglen < 0 || static_cast<size_t>(msglen) >= sizeof(disconnect.msg)) + disconnect.msg[sizeof(disconnect.msg)-1] = 0; for(ContextBase *ctx : *mContexts.load()) { diff --git a/core/async_event.h b/core/async_event.h index 5a2f5f91..9e2d1193 100644 --- a/core/async_event.h +++ b/core/async_event.h @@ -1,6 +1,9 @@ #ifndef CORE_EVENT_H #define CORE_EVENT_H +#include <stdint.h> +#include <variant> + #include "almalloc.h" struct EffectState; @@ -8,48 +11,50 @@ struct EffectState; using uint = unsigned int; -struct AsyncEvent { - enum : uint { - /* User event types. */ - SourceStateChange, - BufferCompleted, - Disconnected, - UserEventCount, - - /* Internal events, always processed. */ - ReleaseEffectState = 128, - - /* End event thread processing. */ - KillThread, - }; - - enum class SrcState { - Reset, - Stop, - Play, - Pause - }; - - const uint EnumType; - union { - char dummy; - struct { - uint id; - SrcState state; - } srcstate; - struct { - uint id; - uint count; - } bufcomp; - struct { - char msg[244]; - } disconnect; - EffectState *mEffectState; - } u{}; - - constexpr AsyncEvent(uint type) noexcept : EnumType{type} { } - - DISABLE_ALLOC() +enum class AsyncEnableBits : uint8_t { + SourceState, + BufferCompleted, + Disconnected, + + Count +}; + + +enum class AsyncSrcState : uint8_t { + Reset, + Stop, + Play, + Pause +}; + +using AsyncKillThread = std::monostate; + +struct AsyncSourceStateEvent { + uint mId; + AsyncSrcState mState; }; +struct AsyncBufferCompleteEvent { + uint mId; + uint mCount; +}; + +struct AsyncDisconnectEvent { + char msg[244]; +}; + +struct AsyncEffectReleaseEvent { + EffectState *mEffectState; +}; + +using AsyncEvent = std::variant<AsyncKillThread, + AsyncSourceStateEvent, + AsyncBufferCompleteEvent, + AsyncEffectReleaseEvent, + AsyncDisconnectEvent>; + +template<typename T, typename ...Args> +auto &InitAsyncEvent(AsyncEvent *evt, Args&& ...args) +{ return std::get<T>(*al::construct_at(evt, std::in_place_type<T>, std::forward<Args>(args)...)); } + #endif diff --git a/core/context.h b/core/context.h index 9723eac3..4febd38d 100644 --- a/core/context.h +++ b/core/context.h @@ -13,6 +13,7 @@ #include "async_event.h" #include "atomic.h" #include "bufferline.h" +#include "opthelpers.h" #include "threads.h" #include "vecmat.h" #include "vector.h" @@ -137,7 +138,7 @@ struct ContextBase { std::thread mEventThread; al::semaphore mEventSem; std::unique_ptr<RingBuffer> mAsyncEvents; - using AsyncEventBitset = std::bitset<AsyncEvent::UserEventCount>; + using AsyncEventBitset = std::bitset<al::to_underlying(AsyncEnableBits::Count)>; std::atomic<AsyncEventBitset> mEnabledEvts{0u}; /* Asynchronous voice change actions are processed as a linked list of diff --git a/core/voice.cpp b/core/voice.cpp index 478ea81f..3e78b176 100644 --- a/core/voice.cpp +++ b/core/voice.cpp @@ -226,10 +226,10 @@ void SendSourceStoppedEvent(ContextBase *context, uint id) auto evt_vec = ring->getWriteVector(); if(evt_vec.first.len < 1) return; - AsyncEvent *evt{al::construct_at(reinterpret_cast<AsyncEvent*>(evt_vec.first.buf), - AsyncEvent::SourceStateChange)}; - evt->u.srcstate.id = id; - evt->u.srcstate.state = AsyncEvent::SrcState::Stop; + AsyncSourceStateEvent &evt = InitAsyncEvent<AsyncSourceStateEvent>( + reinterpret_cast<AsyncEvent*>(evt_vec.first.buf)); + evt.mId = id; + evt.mState = AsyncSrcState::Stop; ring->writeAdvance(1); } @@ -1145,16 +1145,16 @@ void Voice::mix(const State vstate, ContextBase *Context, const nanoseconds devi /* Send any events now, after the position/buffer info was updated. */ const auto enabledevt = Context->mEnabledEvts.load(std::memory_order_acquire); - if(buffers_done > 0 && enabledevt.test(AsyncEvent::BufferCompleted)) + if(buffers_done > 0 && enabledevt.test(al::to_underlying(AsyncEnableBits::BufferCompleted))) { RingBuffer *ring{Context->mAsyncEvents.get()}; auto evt_vec = ring->getWriteVector(); if(evt_vec.first.len > 0) { - AsyncEvent *evt{al::construct_at(reinterpret_cast<AsyncEvent*>(evt_vec.first.buf), - AsyncEvent::BufferCompleted)}; - evt->u.bufcomp.id = SourceID; - evt->u.bufcomp.count = buffers_done; + AsyncBufferCompleteEvent &evt = InitAsyncEvent<AsyncBufferCompleteEvent>( + reinterpret_cast<AsyncEvent*>(evt_vec.first.buf)); + evt.mId = SourceID; + evt.mCount = buffers_done; ring->writeAdvance(1); } } @@ -1165,7 +1165,7 @@ void Voice::mix(const State vstate, ContextBase *Context, const nanoseconds devi * ensures any residual noise fades to 0 amplitude. */ mPlayState.store(Stopping, std::memory_order_release); - if(enabledevt.test(AsyncEvent::SourceStateChange)) + if(enabledevt.test(al::to_underlying(AsyncEnableBits::SourceState))) SendSourceStoppedEvent(Context, SourceID); } } |