Use RAII when handling the mixer's FPU state

This commit is contained in:
Chris Robinson 2018-11-21 09:07:02 -08:00
parent 8f43f737ba
commit 9f2a77f788
6 changed files with 47 additions and 61 deletions

View File

@ -2241,7 +2241,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
* allocated with the appropriate size.
*/
update_failed = AL_FALSE;
START_MIXER_MODE();
FPUCtl mixer_mode{};
context = device->ContextList.load();
while(context)
{
@ -2354,7 +2354,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
context = context->next.load(std::memory_order_relaxed);
}
END_MIXER_MODE();
mixer_mode.leave();
if(update_failed)
return ALC_INVALID_DEVICE;

View File

@ -1697,7 +1697,7 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples)
ALCcontext *ctx;
ALsizei i, c;
START_MIXER_MODE();
FPUCtl mixer_mode{};
for(SamplesDone = 0;SamplesDone < NumSamples;)
{
SamplesToDo = mini(NumSamples-SamplesDone, BUFFERSIZE);
@ -1815,7 +1815,6 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples)
SamplesDone += SamplesToDo;
}
END_MIXER_MODE();
}

View File

@ -154,7 +154,7 @@ SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType
converter->mFracOffset = 0;
/* Have to set the mixer FPU mode since that's what the resampler code expects. */
START_MIXER_MODE();
FPUCtl mixer_mode{};
step = (ALsizei)mind(((ALdouble)srcRate/dstRate*FRACTIONONE) + 0.5,
MAX_PITCH * FRACTIONONE);
converter->mIncrement = maxi(step, 1);
@ -166,7 +166,6 @@ SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType
BsincPrepare(converter->mIncrement, &converter->mState.bsinc, &bsinc12);
converter->mResample = SelectResampler(BSinc12Resampler);
}
END_MIXER_MODE();
return converter;
}
@ -227,7 +226,7 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs
const ALsizei increment = converter->mIncrement;
ALsizei pos = 0;
START_MIXER_MODE();
FPUCtl mixer_mode{};
while(pos < dstframes && *srcframes > 0)
{
ALfloat *RESTRICT SrcData = converter->mSrcSamples;
@ -339,7 +338,6 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs
dst = (ALbyte*)dst + DstFrameSize*DstSize;
pos += DstSize;
}
END_MIXER_MODE();
return pos;
}

View File

@ -1,41 +1,25 @@
#ifndef FPU_MODES_H
#define FPU_MODES_H
#ifdef HAVE_FENV_H
#include <fenv.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct FPUCtl {
class FPUCtl {
#if defined(__GNUC__) && defined(HAVE_SSE)
unsigned int sse_state;
unsigned int sse_state{};
#elif defined(HAVE___CONTROL87_2)
unsigned int state;
unsigned int sse_state;
unsigned int state{};
unsigned int sse_state{};
#elif defined(HAVE__CONTROLFP)
unsigned int state;
unsigned int state{};
#endif
} FPUCtl;
void SetMixerFPUMode(FPUCtl *ctl);
void RestoreFPUMode(const FPUCtl *ctl);
bool in_mode{};
#ifdef __GNUC__
/* Use an alternate macro set with GCC to avoid accidental continue or break
* statements within the mixer mode.
*/
#define START_MIXER_MODE() __extension__({ FPUCtl _oldMode; SetMixerFPUMode(&_oldMode)
#define END_MIXER_MODE() RestoreFPUMode(&_oldMode); })
#else
#define START_MIXER_MODE() do { FPUCtl _oldMode; SetMixerFPUMode(&_oldMode)
#define END_MIXER_MODE() RestoreFPUMode(&_oldMode); } while(0)
#endif
#define LEAVE_MIXER_MODE() RestoreFPUMode(&_oldMode)
public:
FPUCtl() noexcept;
~FPUCtl() { leave(); }
#ifdef __cplusplus
} // extern "C"
#endif
FPUCtl(const FPUCtl&) = delete;
FPUCtl& operator=(const FPUCtl&) = delete;
void leave() noexcept;
};
#endif /* FPU_MODES_H */

View File

@ -260,13 +260,13 @@ void FillCPUCaps(int capfilter)
}
void SetMixerFPUMode(FPUCtl *ctl)
FPUCtl::FPUCtl() noexcept
{
#if defined(__GNUC__) && defined(HAVE_SSE)
if((CPUCapFlags&CPU_CAP_SSE))
{
__asm__ __volatile__("stmxcsr %0" : "=m" (*&ctl->sse_state));
unsigned int sseState = ctl->sse_state;
__asm__ __volatile__("stmxcsr %0" : "=m" (*&this->sse_state));
unsigned int sseState = this->sse_state;
sseState |= 0x8000; /* set flush-to-zero */
if((CPUCapFlags&CPU_CAP_SSE2))
sseState |= 0x0040; /* set denormals-are-zero */
@ -275,32 +275,37 @@ void SetMixerFPUMode(FPUCtl *ctl)
#elif defined(HAVE___CONTROL87_2)
__control87_2(0, 0, &ctl->state, &ctl->sse_state);
__control87_2(0, 0, &this->state, &this->sse_state);
_control87(_DN_FLUSH, _MCW_DN);
#elif defined(HAVE__CONTROLFP)
ctl->state = _controlfp(0, 0);
this->state = _controlfp(0, 0);
_controlfp(_DN_FLUSH, _MCW_DN);
#endif
this->in_mode = true;
}
void RestoreFPUMode(const FPUCtl *ctl)
void FPUCtl::leave() noexcept
{
if(!this->in_mode) return;
#if defined(__GNUC__) && defined(HAVE_SSE)
if((CPUCapFlags&CPU_CAP_SSE))
__asm__ __volatile__("ldmxcsr %0" : : "m" (*&ctl->sse_state));
__asm__ __volatile__("ldmxcsr %0" : : "m" (*&this->sse_state));
#elif defined(HAVE___CONTROL87_2)
unsigned int mode;
__control87_2(ctl->state, _MCW_DN, &mode, nullptr);
__control87_2(ctl->sse_state, _MCW_DN, nullptr, &mode);
__control87_2(this->state, _MCW_DN, &mode, nullptr);
__control87_2(this->sse_state, _MCW_DN, nullptr, &mode);
#elif defined(HAVE__CONTROLFP)
_controlfp(ctl->state, _MCW_DN);
_controlfp(this->state, _MCW_DN);
#endif
this->in_mode = false;
}

View File

@ -514,19 +514,19 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect
EffectState *State{factory->create()};
if(!State) return AL_OUT_OF_MEMORY;
START_MIXER_MODE(); {
ALCdevice *Device{Context->Device};
std::unique_lock<almtx_t> backlock{Device->BackendLock};
State->mOutBuffer = Device->Dry.Buffer;
State->mOutChannels = Device->Dry.NumChannels;
if(State->deviceUpdate(Device) == AL_FALSE)
{
backlock.unlock();
LEAVE_MIXER_MODE();
State->DecRef();
return AL_OUT_OF_MEMORY;
}
} END_MIXER_MODE();
FPUCtl mixer_mode{};
ALCdevice *Device{Context->Device};
std::unique_lock<almtx_t> backlock{Device->BackendLock};
State->mOutBuffer = Device->Dry.Buffer;
State->mOutChannels = Device->Dry.NumChannels;
if(State->deviceUpdate(Device) == AL_FALSE)
{
backlock.unlock();
mixer_mode.leave();
State->DecRef();
return AL_OUT_OF_MEMORY;
}
mixer_mode.leave();
if(!effect)
{