aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2020-11-02 04:24:36 -0800
committerChris Robinson <[email protected]>2020-11-02 04:24:36 -0800
commit52d58a40234b8829801f0a587375eca91694c30f (patch)
treecaa8d283de74feeb4f23eab39ea57b3835c3bffc
parent6e05adf955bdd81c82a1feabb25f6f27d7bc56e0 (diff)
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.
-rw-r--r--al/auxeffectslot.cpp4
-rw-r--r--al/auxeffectslot.h3
-rw-r--r--alc/alc.cpp34
-rw-r--r--alc/alcmain.h1
-rw-r--r--alc/alcontext.h14
-rw-r--r--alc/alu.cpp2
-rw-r--r--alc/alu.h3
-rw-r--r--alc/panning.cpp27
8 files changed, 73 insertions, 15 deletions
diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp
index 74005aaa..df04f430 100644
--- a/al/auxeffectslot.cpp
+++ b/al/auxeffectslot.cpp
@@ -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();
}
diff --git a/al/auxeffectslot.h b/al/auxeffectslot.h
index fdab99ef..03ba034a 100644
--- a/al/auxeffectslot.h
+++ b/al/auxeffectslot.h
@@ -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
diff --git a/alc/alc.cpp b/alc/alc.cpp
index c4fdad95..b3da9209 100644
--- a/alc/alc.cpp
+++ b/alc/alc.cpp
@@ -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()})
+ {
+ 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, device);
+ 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;
diff --git a/alc/alcmain.h b/alc/alcmain.h
index 7a6c952f..abeb0201 100644
--- a/alc/alcmain.h
+++ b/alc/alcmain.h
@@ -148,6 +148,7 @@ public:
al::span<DistData,MAX_OUTPUT_CHANNELS> as_span() { return mChannels; }
};
+
struct BFChannelConfig {
float Scale;
ALuint Index;
diff --git a/alc/alcontext.h b/alc/alcontext.h
index 59775849..20e48253 100644
--- a/alc/alcontext.h
+++ b/alc/alcontext.h
@@ -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};
diff --git a/alc/alu.cpp b/alc/alu.cpp
index 5bc1f6bf..262986e4 100644
--- a/alc/alu.cpp
+++ b/alc/alu.cpp
@@ -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);
}
diff --git a/alc/alu.h b/alc/alu.h
index 37210ce1..f87da792 100644
--- a/alc/alu.h
+++ b/alc/alu.h
@@ -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
diff --git a/alc/panning.cpp b/alc/panning.cpp
index 15a05136..ee7f39eb 100644
--- a/alc/panning.cpp
+++ b/alc/panning.cpp
@@ -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};
}