Use an AL-specific buffer queue item struct for sources

This commit is contained in:
Chris Robinson 2021-01-25 09:08:49 -08:00
parent 6151d11253
commit 71e6bcbd62
5 changed files with 68 additions and 79 deletions

View File

@ -184,7 +184,7 @@ void UpdateSourceProps(const ALsource *source, Voice *voice, ALCcontext *context
int64_t GetSourceSampleOffset(ALsource *Source, ALCcontext *context, nanoseconds *clocktime)
{
ALCdevice *device{context->mDevice.get()};
const BufferlistItem *Current{};
const VoiceBufferItem *Current{};
uint64_t readPos{};
ALuint refcount;
Voice *voice;
@ -223,7 +223,7 @@ int64_t GetSourceSampleOffset(ALsource *Source, ALCcontext *context, nanoseconds
double GetSourceSecOffset(ALsource *Source, ALCcontext *context, nanoseconds *clocktime)
{
ALCdevice *device{context->mDevice.get()};
const BufferlistItem *Current{};
const VoiceBufferItem *Current{};
uint64_t readPos{};
ALuint refcount;
Voice *voice;
@ -245,7 +245,7 @@ double GetSourceSecOffset(ALsource *Source, ALCcontext *context, nanoseconds *cl
if(!voice)
return 0.0f;
const BufferStorage *BufferFmt{nullptr};
const ALbuffer *BufferFmt{nullptr};
auto BufferList = Source->mQueue.cbegin();
while(BufferList != Source->mQueue.cend() && std::addressof(*BufferList) != Current)
{
@ -272,7 +272,7 @@ double GetSourceSecOffset(ALsource *Source, ALCcontext *context, nanoseconds *cl
double GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context)
{
ALCdevice *device{context->mDevice.get()};
const BufferlistItem *Current{};
const VoiceBufferItem *Current{};
ALuint readPos{};
ALuint readPosFrac{};
ALuint refcount;
@ -294,20 +294,17 @@ double GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context)
if(!voice)
return 0.0;
auto BufferList = Source->mQueue.cbegin();
const ALbuffer *BufferFmt{nullptr};
auto BufferList = Source->mQueue.cbegin();
while(BufferList != Source->mQueue.cend() && std::addressof(*BufferList) != Current)
{
if(!BufferFmt)
BufferFmt = static_cast<const ALbuffer*>(BufferList->mBuffer);
if(!BufferFmt) BufferFmt = BufferList->mBuffer;
readPos += BufferList->mSampleLen;
++BufferList;
}
while(BufferList != Source->mQueue.cend() && !BufferFmt)
{
BufferFmt = static_cast<const ALbuffer*>(BufferList->mBuffer);
BufferFmt = BufferList->mBuffer;
++BufferList;
}
assert(BufferFmt != nullptr);
@ -355,7 +352,7 @@ double GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context)
struct VoicePos {
ALuint pos, frac;
BufferlistItem *bufferitem;
VoiceBufferItem *bufferitem;
};
/**
@ -365,15 +362,15 @@ struct VoicePos {
* using the givem offset type and offset. If the offset is out of range,
* returns an empty optional.
*/
al::optional<VoicePos> GetSampleOffset(al::deque<BufferlistItem> &BufferList, ALenum OffsetType,
al::optional<VoicePos> GetSampleOffset(al::deque<ALbufferQueueItem> &BufferList, ALenum OffsetType,
double Offset)
{
/* Find the first valid Buffer in the Queue */
const ALbuffer *BufferFmt{nullptr};
for(auto &item : BufferList)
{
BufferFmt = static_cast<const ALbuffer*>(item.mBuffer);
if(BufferFmt != nullptr) break;
BufferFmt = item.mBuffer;
if(BufferFmt) break;
}
if(!BufferFmt)
return al::nullopt;
@ -435,13 +432,13 @@ al::optional<VoicePos> GetSampleOffset(al::deque<BufferlistItem> &BufferList, AL
}
void InitVoice(Voice *voice, ALsource *source, BufferlistItem *BufferList, ALCcontext *context,
void InitVoice(Voice *voice, ALsource *source, ALbufferQueueItem *BufferList, ALCcontext *context,
ALCdevice *device)
{
voice->mLoopBuffer.store(source->Looping ? &source->mQueue.front() : nullptr,
std::memory_order_relaxed);
BufferStorage *buffer{BufferList->mBuffer};
ALbuffer *buffer{BufferList->mBuffer};
ALuint num_channels{buffer->channelsFromFmt()};
voice->mFrequency = buffer->mSampleRate;
voice->mFmtChannels = buffer->mChannels;
@ -1328,7 +1325,7 @@ bool SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a
{
ALCdevice *device{Context->mDevice.get()};
ALeffectslot *slot{nullptr};
al::deque<BufferlistItem> oldlist{};
al::deque<ALbufferQueueItem> oldlist;
std::unique_lock<std::mutex> slotlock;
float fvals[6];
@ -1395,21 +1392,21 @@ bool SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a
"Setting already-set callback buffer %u", buffer->id);
/* Add the selected buffer to a one-item queue */
al::deque<BufferlistItem> newlist;
al::deque<ALbufferQueueItem> newlist;
newlist.emplace_back();
newlist.back().mCallback = buffer->mCallback;
newlist.back().mUserData = buffer->mUserData;
newlist.back().mSampleLen = buffer->mSampleLen;
newlist.back().mLoopStart = buffer->mLoopStart;
newlist.back().mLoopEnd = buffer->mLoopEnd;
newlist.back().mSamples = buffer->mData;
newlist.back().mSamples = buffer->mData.data();
newlist.back().mBuffer = buffer;
IncrementRef(buffer->ref);
/* Source is now Static */
Source->SourceType = AL_STATIC;
oldlist = std::move(Source->mQueue);
Source->mQueue = std::move(newlist);
Source->mQueue.swap(oldlist);
Source->mQueue.swap(newlist);
}
else
{
@ -1421,7 +1418,7 @@ bool SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a
/* Delete all elements in the previous queue */
for(auto &item : oldlist)
{
if(auto *buffer{static_cast<ALbuffer*>(item.mBuffer)})
if(ALbuffer *buffer{item.mBuffer})
DecrementRef(buffer->ref);
}
return true;
@ -1972,9 +1969,9 @@ bool GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a
case AL_BUFFER:
CHECKSIZE(values, 1);
{
BufferlistItem *BufferList{(Source->SourceType == AL_STATIC)
ALbufferQueueItem *BufferList{(Source->SourceType == AL_STATIC)
? &Source->mQueue.front() : nullptr};
ALbuffer *buffer{BufferList ? static_cast<ALbuffer*>(BufferList->mBuffer) : nullptr};
ALbuffer *buffer{BufferList ? BufferList->mBuffer : nullptr};
values[0] = buffer ? static_cast<int>(buffer->id) : 0;
}
return true;
@ -2003,7 +2000,7 @@ bool GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a
int played{0};
if(Source->state != AL_INITIAL)
{
const BufferlistItem *Current{nullptr};
const VoiceBufferItem *Current{nullptr};
if(Voice *voice{GetSourceVoice(Source, Context)})
Current = voice->mCurrentBuffer.load(std::memory_order_relaxed);
for(auto &item : Source->mQueue)
@ -2921,9 +2918,8 @@ START_API_FUNC
auto BufferList = source->mQueue.begin();
for(;BufferList != source->mQueue.end();++BufferList)
{
if(BufferList->mSampleLen != 0) break;
BufferStorage *buffer{BufferList->mBuffer};
if(buffer && buffer->mCallback) break;
if(BufferList->mSampleLen != 0 || BufferList->mCallback)
break;
}
/* If there's nothing to play, go right to stopped. */
@ -3008,7 +3004,7 @@ START_API_FUNC
voice->mPosition.store(vpos->pos, std::memory_order_relaxed);
voice->mPositionFrac.store(vpos->frac, std::memory_order_relaxed);
voice->mCurrentBuffer.store(vpos->bufferitem, std::memory_order_relaxed);
if(vpos->pos != 0 || vpos->frac != 0 || vpos->bufferitem != &source->mQueue.front())
if(vpos->pos!=0 || vpos->frac!=0 || vpos->bufferitem!=&source->mQueue.front())
voice->mFlags |= VoiceIsFading;
}
}
@ -3255,13 +3251,13 @@ START_API_FUNC
ALbuffer *BufferFmt{nullptr};
for(auto &item : source->mQueue)
{
BufferFmt = static_cast<ALbuffer*>(item.mBuffer);
BufferFmt = item.mBuffer;
if(BufferFmt) break;
}
std::unique_lock<std::mutex> buflock{device->BufferLock};
const size_t NewListStart{source->mQueue.size()};
BufferlistItem *BufferList{nullptr};
ALbufferQueueItem *BufferList{nullptr};
for(ALsizei i{0};i < nb;i++)
{
bool fmt_mismatch{false};
@ -3289,7 +3285,7 @@ START_API_FUNC
if(!buffer) continue;
BufferList->mSampleLen = buffer->mSampleLen;
BufferList->mLoopEnd = buffer->mSampleLen;
BufferList->mSamples = buffer->mData;
BufferList->mSamples = buffer->mData.data();
BufferList->mBuffer = buffer;
IncrementRef(buffer->ref);
@ -3325,7 +3321,7 @@ START_API_FUNC
auto iter = source->mQueue.begin() + ptrdiff_t(NewListStart);
for(;iter != source->mQueue.end();++iter)
{
if(auto *buf{static_cast<ALbuffer*>(iter->mBuffer)})
if(ALbuffer *buf{iter->mBuffer})
DecrementRef(buf->ref);
}
source->mQueue.resize(NewListStart);
@ -3371,7 +3367,7 @@ START_API_FUNC
uint processed{0u};
if LIKELY(source->state != AL_INITIAL)
{
BufferlistItem *Current{nullptr};
VoiceBufferItem *Current{nullptr};
if(Voice *voice{GetSourceVoice(source, context.get())})
Current = voice->mCurrentBuffer.load(std::memory_order_relaxed);
for(auto &item : source->mQueue)
@ -3387,7 +3383,7 @@ START_API_FUNC
do {
auto &head = source->mQueue.front();
if(auto *buffer{static_cast<ALbuffer*>(head.mBuffer)})
if(ALbuffer *buffer{head.mBuffer})
{
*(buffers++) = buffer->id;
DecrementRef(buffer->ref);
@ -3424,7 +3420,7 @@ ALsource::~ALsource()
{
for(auto &item : mQueue)
{
if(auto *buffer{static_cast<ALbuffer*>(item.mBuffer)})
if(ALbuffer *buffer{item.mBuffer})
DecrementRef(buffer->ref);
}

View File

@ -21,7 +21,6 @@
struct ALbuffer;
struct ALeffectslot;
struct BufferlistItem;
namespace al {
@ -35,6 +34,12 @@ using deque = std::deque<T, al::allocator<T>>;
#define INVALID_VOICE_IDX static_cast<ALuint>(-1)
struct ALbufferQueueItem : public VoiceBufferItem {
ALbuffer *mBuffer{nullptr};
DISABLE_ALLOC()
};
struct ALsource {
/** Source properties. */
@ -108,7 +113,7 @@ struct ALsource {
ALenum state{AL_INITIAL};
/** Source Buffer Queue head. */
al::deque<BufferlistItem> mQueue;
al::deque<ALbufferQueueItem> mQueue;
std::atomic_flag PropsClean;

View File

@ -4,8 +4,6 @@
#include <atomic>
#include "albyte.h"
#include "almalloc.h"
#include "alspan.h"
using uint = unsigned int;
@ -71,22 +69,4 @@ struct BufferStorage {
{ return mChannels == FmtBFormat2D || mChannels == FmtBFormat3D; }
};
struct BufferlistItem {
std::atomic<BufferlistItem*> mNext{nullptr};
CallbackType mCallback{nullptr};
void *mUserData{nullptr};
uint mSampleLen{0u};
uint mLoopStart{0u};
uint mLoopEnd{0u};
al::span<al::byte> mSamples;
BufferStorage *mBuffer{nullptr};
DEF_NEWDEL(BufferlistItem)
};
#endif /* ALC_BUFFER_STORAGE_H */

View File

@ -234,7 +234,7 @@ void LoadSamples(float *RESTRICT dst, const al::byte *src, const size_t srcstep,
#undef HANDLE_FMT
}
float *LoadBufferStatic(BufferlistItem *buffer, BufferlistItem *&bufferLoopItem,
float *LoadBufferStatic(VoiceBufferItem *buffer, VoiceBufferItem *&bufferLoopItem,
const size_t numChannels, const FmtType sampleType, const size_t sampleSize, const size_t chan,
size_t dataPosInt, al::span<float> srcBuffer)
{
@ -250,9 +250,7 @@ float *LoadBufferStatic(BufferlistItem *buffer, BufferlistItem *&bufferLoopItem,
/* Load what's left to play from the buffer */
const size_t DataRem{minz(srcBuffer.size(), buffer->mSampleLen-dataPosInt)};
const al::byte *Data{buffer->mSamples.data()};
Data += (dataPosInt*numChannels + chan)*sampleSize;
const al::byte *Data{buffer->mSamples + (dataPosInt*numChannels + chan)*sampleSize};
LoadSamples(srcBuffer.data(), Data, numChannels, sampleType, DataRem);
srcBuffer = srcBuffer.subspan(DataRem);
}
@ -261,9 +259,7 @@ float *LoadBufferStatic(BufferlistItem *buffer, BufferlistItem *&bufferLoopItem,
/* Load what's left of this loop iteration */
const size_t DataRem{minz(srcBuffer.size(), LoopEnd-dataPosInt)};
const al::byte *Data{buffer->mSamples.data()};
Data += (dataPosInt*numChannels + chan)*sampleSize;
const al::byte *Data{buffer->mSamples + (dataPosInt*numChannels + chan)*sampleSize};
LoadSamples(srcBuffer.data(), Data, numChannels, sampleType, DataRem);
srcBuffer = srcBuffer.subspan(DataRem);
@ -273,7 +269,7 @@ float *LoadBufferStatic(BufferlistItem *buffer, BufferlistItem *&bufferLoopItem,
{
const size_t DataSize{minz(srcBuffer.size(), LoopSize)};
Data = buffer->mSamples.data() + (LoopStart*numChannels + chan)*sampleSize;
Data = buffer->mSamples + (LoopStart*numChannels + chan)*sampleSize;
LoadSamples(srcBuffer.data(), Data, numChannels, sampleType, DataSize);
srcBuffer = srcBuffer.subspan(DataSize);
@ -282,22 +278,21 @@ float *LoadBufferStatic(BufferlistItem *buffer, BufferlistItem *&bufferLoopItem,
return srcBuffer.begin();
}
float *LoadBufferCallback(BufferlistItem *buffer, const size_t numChannels,
float *LoadBufferCallback(VoiceBufferItem *buffer, const size_t numChannels,
const FmtType sampleType, const size_t sampleSize, const size_t chan,
size_t numCallbackSamples, al::span<float> srcBuffer)
{
/* Load what's left to play from the buffer */
const size_t DataRem{minz(srcBuffer.size(), numCallbackSamples)};
const al::byte *Data{buffer->mSamples.data() + chan*sampleSize};
const al::byte *Data{buffer->mSamples + chan*sampleSize};
LoadSamples(srcBuffer.data(), Data, numChannels, sampleType, DataRem);
srcBuffer = srcBuffer.subspan(DataRem);
return srcBuffer.begin();
}
float *LoadBufferQueue(BufferlistItem *buffer, BufferlistItem *bufferLoopItem,
float *LoadBufferQueue(VoiceBufferItem *buffer, VoiceBufferItem *bufferLoopItem,
const size_t numChannels, const FmtType sampleType, const size_t sampleSize, const size_t chan,
size_t dataPosInt, al::span<float> srcBuffer)
{
@ -314,9 +309,7 @@ float *LoadBufferQueue(BufferlistItem *buffer, BufferlistItem *bufferLoopItem,
const size_t DataSize{minz(srcBuffer.size(), buffer->mSampleLen-dataPosInt)};
const al::byte *Data{buffer->mSamples.data()};
Data += (dataPosInt*numChannels + chan)*sampleSize;
const al::byte *Data{buffer->mSamples + (dataPosInt*numChannels + chan)*sampleSize};
LoadSamples(srcBuffer.data(), Data, numChannels, sampleType, DataSize);
srcBuffer = srcBuffer.subspan(DataSize);
if(srcBuffer.empty()) break;
@ -443,8 +436,8 @@ void Voice::mix(const State vstate, ALCcontext *Context, const uint SamplesToDo)
/* Get voice info */
uint DataPosInt{mPosition.load(std::memory_order_relaxed)};
uint DataPosFrac{mPositionFrac.load(std::memory_order_relaxed)};
BufferlistItem *BufferListItem{mCurrentBuffer.load(std::memory_order_relaxed)};
BufferlistItem *BufferLoopItem{mLoopBuffer.load(std::memory_order_relaxed)};
VoiceBufferItem *BufferListItem{mCurrentBuffer.load(std::memory_order_relaxed)};
VoiceBufferItem *BufferLoopItem{mLoopBuffer.load(std::memory_order_relaxed)};
const FmtType SampleType{mFmtType};
const uint SampleSize{mSampleSize};
const uint increment{mStep};
@ -724,7 +717,7 @@ void Voice::mix(const State vstate, ALCcontext *Context, const uint SamplesToDo)
{
const size_t byteOffset{SrcSamplesDone*FrameSize};
const size_t byteEnd{mNumCallbackSamples*FrameSize};
al::byte *data{BufferListItem->mSamples.data()};
al::byte *data{BufferListItem->mSamples};
std::copy(data+byteOffset, data+byteEnd, data);
mNumCallbackSamples -= SrcSamplesDone;
}

View File

@ -74,6 +74,20 @@ struct SendParams {
};
struct VoiceBufferItem {
std::atomic<VoiceBufferItem*> mNext{nullptr};
CallbackType mCallback{nullptr};
void *mUserData{nullptr};
uint mSampleLen{0u};
uint mLoopStart{0u};
uint mLoopEnd{0u};
al::byte *mSamples{nullptr};
};
struct VoiceProps {
float Pitch;
float Gain;
@ -166,12 +180,12 @@ struct Voice {
std::atomic<uint> mPositionFrac;
/* Current buffer queue item being played. */
std::atomic<BufferlistItem*> mCurrentBuffer;
std::atomic<VoiceBufferItem*> mCurrentBuffer;
/* Buffer queue item to loop to at end of queue (will be NULL for non-
* looping voices).
*/
std::atomic<BufferlistItem*> mLoopBuffer;
std::atomic<VoiceBufferItem*> mLoopBuffer;
/* Properties for the attached buffer(s). */
FmtChannels mFmtChannels;
@ -211,8 +225,9 @@ struct Voice {
al::vector<ChannelData> mChans{2};
Voice() = default;
Voice(const Voice&) = delete;
~Voice() { delete mUpdate.exchange(nullptr, std::memory_order_acq_rel); }
Voice(const Voice&) = delete;
Voice& operator=(const Voice&) = delete;
void mix(const State vstate, ALCcontext *Context, const uint SamplesToDo);