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:
Chris Robinson
2020-11-02 04:24:36 -08:00
parent 6e05adf955
commit 52d58a4023
8 changed files with 73 additions and 15 deletions
+3 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+1
View File
@@ -148,6 +148,7 @@ public:
al::span<DistData,MAX_OUTPUT_CHANNELS> as_span() { return mChannels; }
};
struct BFChannelConfig {
float Scale;
ALuint Index;
+14
View File
@@ -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
View File
@@ -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);
}
+2 -1
View File
@@ -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
View File
@@ -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};
}