Store the wet buffers in the context
This is rather ugly, but we need the wet buffers to remain allocated after its effect slot is deleted, because a voice can still use it for its final fade-out mix.
This commit is contained in:
@@ -216,7 +216,7 @@ ALeffectslot *AllocEffectSlot(ALCcontext *context)
|
||||
context->setError(err, "Effect slot object initialization failed");
|
||||
return nullptr;
|
||||
}
|
||||
aluInitEffectPanning(slot, context->mDevice.get());
|
||||
aluInitEffectPanning(slot, context);
|
||||
|
||||
/* Add 1 to avoid source ID 0. */
|
||||
slot->id = ((lidx<<6) | slidx) + 1;
|
||||
@@ -822,6 +822,8 @@ ALeffectslot::~ALeffectslot()
|
||||
delete props;
|
||||
}
|
||||
|
||||
if(mWetBuffer)
|
||||
mWetBuffer->mInUse = false;
|
||||
if(Params.mEffectState)
|
||||
Params.mEffectState->release();
|
||||
}
|
||||
|
||||
+2
-1
@@ -18,6 +18,7 @@
|
||||
struct ALbuffer;
|
||||
struct ALeffect;
|
||||
struct ALeffectslot;
|
||||
struct WetBuffer;
|
||||
|
||||
|
||||
using ALeffectslotArray = al::FlexArray<ALeffectslot*>;
|
||||
@@ -87,7 +88,7 @@ struct ALeffectslot {
|
||||
ALuint id{};
|
||||
|
||||
/* Mixing buffer used by the Wet mix. */
|
||||
al::vector<FloatBufferLine, 16> MixBuffer;
|
||||
WetBuffer *mWetBuffer{nullptr};
|
||||
|
||||
/* Wet buffer configuration is ACN channel order with N3D scaling.
|
||||
* Consequently, effects that only want to work with mono input can use
|
||||
|
||||
+29
-5
@@ -2100,9 +2100,35 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
|
||||
FPUCtl mixer_mode{};
|
||||
for(ALCcontext *context : *device->mContexts.load())
|
||||
{
|
||||
std::unique_lock<std::mutex> proplock{context->mPropLock};
|
||||
std::unique_lock<std::mutex> slotlock{context->mEffectSlotLock};
|
||||
/* HACK: Clear the effect slots' wet buffer references, and clear the wet
|
||||
* buffer array so they're reallocated (with potentially a new channel
|
||||
* count) when reinitialized.
|
||||
*/
|
||||
if(ALeffectslot *slot{context->mDefaultSlot.get()})
|
||||
{
|
||||
aluInitEffectPanning(slot, device);
|
||||
slot->mWetBuffer = nullptr;
|
||||
slot->Wet.Buffer = {};
|
||||
}
|
||||
for(auto &sublist : context->mEffectSlotList)
|
||||
{
|
||||
uint64_t usemask{~sublist.FreeMask};
|
||||
while(usemask)
|
||||
{
|
||||
const ALsizei idx{CountTrailingZeros(usemask)};
|
||||
ALeffectslot *slot{sublist.EffectSlots + idx};
|
||||
usemask &= ~(1_u64 << idx);
|
||||
|
||||
slot->mWetBuffer = nullptr;
|
||||
slot->Wet.Buffer = {};
|
||||
}
|
||||
}
|
||||
decltype(context->mWetBuffers){}.swap(context->mWetBuffers);
|
||||
|
||||
if(ALeffectslot *slot{context->mDefaultSlot.get()})
|
||||
{
|
||||
aluInitEffectPanning(slot, context);
|
||||
|
||||
EffectState *state{slot->Effect.State.get()};
|
||||
state->mOutTarget = device->Dry.Buffer;
|
||||
@@ -2112,8 +2138,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
|
||||
slot->updateProps(context);
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> proplock{context->mPropLock};
|
||||
std::unique_lock<std::mutex> slotlock{context->mEffectSlotLock};
|
||||
if(ALeffectslotArray *curarray{context->mActiveAuxSlots.load(std::memory_order_relaxed)})
|
||||
std::fill_n(curarray->end(), curarray->size(), nullptr);
|
||||
for(auto &sublist : context->mEffectSlotList)
|
||||
@@ -2125,7 +2149,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
|
||||
ALeffectslot *slot{sublist.EffectSlots + idx};
|
||||
usemask &= ~(1_u64 << idx);
|
||||
|
||||
aluInitEffectPanning(slot, device);
|
||||
aluInitEffectPanning(slot, context);
|
||||
|
||||
EffectState *state{slot->Effect.State.get()};
|
||||
state->mOutTarget = device->Dry.Buffer;
|
||||
@@ -2439,7 +2463,7 @@ void ALCcontext::init()
|
||||
{
|
||||
mDefaultSlot = std::unique_ptr<ALeffectslot>{new ALeffectslot{}};
|
||||
if(mDefaultSlot->init() == AL_NO_ERROR)
|
||||
aluInitEffectPanning(mDefaultSlot.get(), mDevice.get());
|
||||
aluInitEffectPanning(mDefaultSlot.get(), this);
|
||||
else
|
||||
{
|
||||
mDefaultSlot = nullptr;
|
||||
|
||||
@@ -148,6 +148,7 @@ public:
|
||||
al::span<DistData,MAX_OUTPUT_CHANNELS> as_span() { return mChannels; }
|
||||
};
|
||||
|
||||
|
||||
struct BFChannelConfig {
|
||||
float Scale;
|
||||
ALuint Index;
|
||||
|
||||
@@ -42,6 +42,17 @@ enum class DistanceModel {
|
||||
};
|
||||
|
||||
|
||||
struct WetBuffer {
|
||||
bool mInUse;
|
||||
al::FlexArray<FloatBufferLine, 16> mBuffer;
|
||||
|
||||
WetBuffer(size_t count) : mBuffer{count} { }
|
||||
|
||||
DEF_FAM_NEWDEL(WetBuffer, mBuffer)
|
||||
};
|
||||
using WetBufferPtr = std::unique_ptr<WetBuffer>;
|
||||
|
||||
|
||||
struct ALcontextProps {
|
||||
float DopplerFactor;
|
||||
float DopplerVelocity;
|
||||
@@ -178,6 +189,9 @@ struct ALCcontext : public al::intrusive_ref<ALCcontext> {
|
||||
}
|
||||
|
||||
|
||||
/* Wet buffers used by effect slots. */
|
||||
al::vector<WetBufferPtr> mWetBuffers;
|
||||
|
||||
using ALeffectslotArray = al::FlexArray<ALeffectslot*>;
|
||||
std::atomic<ALeffectslotArray*> mActiveAuxSlots{nullptr};
|
||||
|
||||
|
||||
+1
-1
@@ -1739,7 +1739,7 @@ void ProcessContexts(ALCdevice *device, const ALuint SamplesToDo)
|
||||
/* Clear auxiliary effect slot mixing buffers. */
|
||||
for(ALeffectslot *slot : auxslots)
|
||||
{
|
||||
for(auto &buffer : slot->MixBuffer)
|
||||
for(auto &buffer : slot->Wet.Buffer)
|
||||
buffer.fill(0.0f);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "alcmain.h"
|
||||
#include "alspan.h"
|
||||
|
||||
struct ALCcontext;
|
||||
struct ALbufferlistitem;
|
||||
struct ALeffectslot;
|
||||
|
||||
@@ -73,7 +74,7 @@ void aluInitMixer(void);
|
||||
void aluInitRenderer(ALCdevice *device, int hrtf_id, HrtfRequestMode hrtf_appreq,
|
||||
HrtfRequestMode hrtf_userreq);
|
||||
|
||||
void aluInitEffectPanning(ALeffectslot *slot, ALCdevice *device);
|
||||
void aluInitEffectPanning(ALeffectslot *slot, ALCcontext *context);
|
||||
|
||||
/**
|
||||
* Calculates ambisonic encoder coefficients using the X, Y, and Z direction
|
||||
|
||||
+21
-6
@@ -40,6 +40,7 @@
|
||||
#include "al/auxeffectslot.h"
|
||||
#include "alcmain.h"
|
||||
#include "alconfig.h"
|
||||
#include "alcontext.h"
|
||||
#include "almalloc.h"
|
||||
#include "alnumeric.h"
|
||||
#include "aloptional.h"
|
||||
@@ -1034,19 +1035,33 @@ no_hrtf:
|
||||
}
|
||||
|
||||
|
||||
void aluInitEffectPanning(ALeffectslot *slot, ALCdevice *device)
|
||||
void aluInitEffectPanning(ALeffectslot *slot, ALCcontext *context)
|
||||
{
|
||||
ALCdevice *device{context->mDevice.get()};
|
||||
const size_t count{AmbiChannelsFromOrder(device->mAmbiOrder)};
|
||||
slot->MixBuffer.resize(count);
|
||||
slot->MixBuffer.shrink_to_fit();
|
||||
|
||||
ALuint idx{0};
|
||||
for(auto &wetbuffer : context->mWetBuffers)
|
||||
{
|
||||
if(!wetbuffer->mInUse)
|
||||
break;
|
||||
++idx;
|
||||
}
|
||||
if(idx == context->mWetBuffers.size())
|
||||
{
|
||||
auto newbuffer = WetBufferPtr{new(FamCount(count)) WetBuffer{count}};
|
||||
context->mWetBuffers.emplace_back(std::move(newbuffer));
|
||||
}
|
||||
auto *wetbuffer = context->mWetBuffers[idx].get();
|
||||
slot->mWetBuffer = wetbuffer;
|
||||
wetbuffer->mInUse = true;
|
||||
|
||||
auto acnmap_end = AmbiIndex::FromACN.begin() + count;
|
||||
auto iter = std::transform(AmbiIndex::FromACN.begin(), acnmap_end, slot->Wet.AmbiMap.begin(),
|
||||
[](const uint8_t &acn) noexcept -> BFChannelConfig
|
||||
{ return BFChannelConfig{1.0f, acn}; }
|
||||
);
|
||||
{ return BFChannelConfig{1.0f, acn}; });
|
||||
std::fill(iter, slot->Wet.AmbiMap.end(), BFChannelConfig{});
|
||||
slot->Wet.Buffer = {slot->MixBuffer.data(), slot->MixBuffer.size()};
|
||||
slot->Wet.Buffer = {wetbuffer->mBuffer.data(), count};
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user