diff options
-rw-r--r-- | Alc/alc.cpp | 19 | ||||
-rw-r--r-- | Alc/alu.cpp | 44 | ||||
-rw-r--r-- | Alc/mixvoice.cpp | 12 | ||||
-rw-r--r-- | OpenAL32/alSource.cpp | 14 | ||||
-rw-r--r-- | OpenAL32/event.cpp | 35 |
5 files changed, 93 insertions, 31 deletions
diff --git a/Alc/alc.cpp b/Alc/alc.cpp index b6065e97..d13cfc54 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2465,6 +2465,25 @@ ALCcontext_struct::~ALCcontext_struct() } TRACE("Freed " SZFMT " listener property object%s\n", count, (count==1)?"":"s"); + count = 0; + auto evt_vec = ll_ringbuffer_get_read_vector(AsyncEvents); + while(evt_vec.first.len > 0) + { + reinterpret_cast<AsyncEvent*>(evt_vec.first.buf)->~AsyncEvent(); + evt_vec.first.buf += sizeof(AsyncEvent); + evt_vec.first.len -= 1; + ++count; + } + while(evt_vec.second.len > 0) + { + reinterpret_cast<AsyncEvent*>(evt_vec.second.buf)->~AsyncEvent(); + evt_vec.second.buf += sizeof(AsyncEvent); + evt_vec.second.len -= 1; + ++count; + } + if(count > 0) + TRACE("Destructed " SZFMT " orphaned event%s\n", count, (count==1)?"":"s"); + delete AsyncEvents; AsyncEvents = nullptr; diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 01b4f3c3..abe938f1 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -293,12 +293,14 @@ void SendSourceStoppedEvent(ALCcontext *context, ALuint id) ALbitfieldSOFT enabledevt{context->EnabledEvts.load(std::memory_order_acquire)}; if(!(enabledevt&EventType_SourceStateChange)) return; - AsyncEvent evt{EventType_SourceStateChange}; - evt.u.srcstate.id = id; - evt.u.srcstate.state = AL_STOPPED; - - if(ll_ringbuffer_write(context->AsyncEvents, &evt, 1) == 1) - context->EventSem.post(); + auto evt_data = ll_ringbuffer_get_write_vector(context->AsyncEvents).first; + if(evt_data.len < 1) return; + + AsyncEvent *evt{new (evt_data.buf) AsyncEvent{EventType_SourceStateChange}}; + evt->u.srcstate.id = id; + evt->u.srcstate.state = AL_STOPPED; + ll_ringbuffer_write_advance(context->AsyncEvents, 1); + context->EventSem.post(); } @@ -394,6 +396,7 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) } state = props->State; + props->State = nullptr; if(state == slot->Params.mEffectState) { @@ -402,21 +405,23 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) * 0 refs since the current params also hold a reference). */ DecrementRef(&state->mRef); - props->State = nullptr; } else { /* Otherwise, replace it and send off the old one with a release * event. */ - AsyncEvent evt{EventType_ReleaseEffectState}; - evt.u.mEffectState = slot->Params.mEffectState; - + EffectState *oldstate{slot->Params.mEffectState}; slot->Params.mEffectState = state; - props->State = nullptr; - if(LIKELY(ll_ringbuffer_write(context->AsyncEvents, &evt, 1) != 0)) + auto evt_data = ll_ringbuffer_get_write_vector(context->AsyncEvents).first; + if(LIKELY(evt_data.len > 0)) + { + AsyncEvent *evt{new (evt_data.buf) AsyncEvent{EventType_ReleaseEffectState}}; + evt->u.mEffectState = oldstate; + ll_ringbuffer_write_advance(context->AsyncEvents, 1); context->EventSem.post(); + } else { /* If writing the event failed, the queue was probably full. @@ -424,7 +429,7 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) * eventually be cleaned up sometime later (not ideal, but * better than blocking or leaking). */ - props->State = evt.u.mEffectState; + props->State = oldstate; } } @@ -1828,9 +1833,16 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) while(ctx) { const ALbitfieldSOFT enabledevt{ctx->EnabledEvts.load(std::memory_order_acquire)}; - if((enabledevt&EventType_Disconnected) && - ll_ringbuffer_write(ctx->AsyncEvents, &evt, 1) == 1) - ctx->EventSem.post(); + if((enabledevt&EventType_Disconnected)) + { + auto evt_data = ll_ringbuffer_get_write_vector(ctx->AsyncEvents).first; + if(evt_data.len > 0) + { + new (evt_data.buf) AsyncEvent{evt}; + ll_ringbuffer_write_advance(ctx->AsyncEvents, 1); + ctx->EventSem.post(); + } + } std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount.load(std::memory_order_acquire), [ctx](ALvoice *voice) -> void diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index 680f4a31..f68c0f0a 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -721,11 +721,15 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize ALbitfieldSOFT enabledevt{Context->EnabledEvts.load(std::memory_order_acquire)}; if(buffers_done > 0 && (enabledevt&EventType_BufferCompleted)) { - AsyncEvent evt{EventType_BufferCompleted}; - evt.u.bufcomp.id = SourceID; - evt.u.bufcomp.count = buffers_done; - if(ll_ringbuffer_write(Context->AsyncEvents, &evt, 1) == 1) + auto evt_data = ll_ringbuffer_get_write_vector(Context->AsyncEvents).first; + if(evt_data.len > 0) + { + AsyncEvent *evt{new (evt_data.buf) AsyncEvent{EventType_BufferCompleted}}; + evt->u.bufcomp.id = SourceID; + evt->u.bufcomp.count = buffers_done; + ll_ringbuffer_write_advance(Context->AsyncEvents, 1); Context->EventSem.post(); + } } return isplaying; diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index e88df598..b70fc872 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -687,16 +687,18 @@ void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state) ALbitfieldSOFT enabledevt{context->EnabledEvts.load(std::memory_order_acquire)}; if(!(enabledevt&EventType_SourceStateChange)) return; - AsyncEvent evt{EventType_SourceStateChange}; - evt.u.srcstate.id = id; - evt.u.srcstate.state = state; - /* The mixer may have queued a state change that's not yet been processed, * and we don't want state change messages to occur out of order, so send * it through the async queue to ensure proper ordering. */ - if(ll_ringbuffer_write(context->AsyncEvents, &evt, 1) == 1) - context->EventSem.post(); + auto evt_data = ll_ringbuffer_get_write_vector(context->AsyncEvents).first; + if(evt_data.len < 1) return; + + AsyncEvent *evt{new (evt_data.buf) AsyncEvent{EventType_SourceStateChange}}; + evt->u.srcstate.id = id; + evt->u.srcstate.state = state; + ll_ringbuffer_write_advance(context->AsyncEvents, 1); + context->EventSem.post(); } diff --git a/OpenAL32/event.cpp b/OpenAL32/event.cpp index 6a3dc4bc..6399603b 100644 --- a/OpenAL32/event.cpp +++ b/OpenAL32/event.cpp @@ -18,10 +18,10 @@ static int EventThread(ALCcontext *context) { bool quitnow{false}; - AsyncEvent evt{}; while(LIKELY(!quitnow)) { - if(ll_ringbuffer_read(context->AsyncEvents, &evt, 1) == 0) + auto evt_data = ll_ringbuffer_get_read_vector(context->AsyncEvents).first; + if(evt_data.len == 0) { context->EventSem.wait(); continue; @@ -29,6 +29,22 @@ static int EventThread(ALCcontext *context) std::lock_guard<std::mutex> _{context->EventCbLock}; do { + auto &evt = *reinterpret_cast<AsyncEvent*>(evt_data.buf); + evt_data.buf += sizeof(AsyncEvent); + evt_data.len -= 1; + /* This automatically destructs the event object and advances the + * ringbuffer's read offset at the end of scope. + */ + const struct EventAutoDestructor { + AsyncEvent &evt; + ll_ringbuffer *ring; + ~EventAutoDestructor() + { + evt.~AsyncEvent(); + ll_ringbuffer_read_advance(ring, 1); + } + } _{evt, context->AsyncEvents}; + quitnow = evt.EnumType == EventType_KillThread; if(UNLIKELY(quitnow)) break; @@ -73,7 +89,7 @@ static int EventThread(ALCcontext *context) static_cast<ALsizei>(strlen(evt.u.user.msg)), evt.u.user.msg, context->EventParam ); - } while(ll_ringbuffer_read(context->AsyncEvents, &evt, 1) != 0); + } while(evt_data.len != 0); } return 0; } @@ -94,8 +110,17 @@ void StartEventThrd(ALCcontext *ctx) void StopEventThrd(ALCcontext *ctx) { static constexpr AsyncEvent kill_evt{EventType_KillThread}; - while(ll_ringbuffer_write(ctx->AsyncEvents, &kill_evt, 1) == 0) - std::this_thread::yield(); + ll_ringbuffer_data evt_data = ll_ringbuffer_get_write_vector(ctx->AsyncEvents).first; + if(evt_data.len == 0) + { + do { + std::this_thread::yield(); + evt_data = ll_ringbuffer_get_write_vector(ctx->AsyncEvents).first; + } while(evt_data.len == 0); + } + new (evt_data.buf) AsyncEvent{kill_evt}; + ll_ringbuffer_write_advance(ctx->AsyncEvents, 1); + ctx->EventSem.post(); if(ctx->EventThread.joinable()) ctx->EventThread.join(); |