diff options
Diffstat (limited to 'router')
-rw-r--r-- | router/al.cpp | 51 | ||||
-rw-r--r-- | router/alc.cpp | 279 | ||||
-rw-r--r-- | router/router.cpp | 68 | ||||
-rw-r--r-- | router/router.h | 71 |
4 files changed, 329 insertions, 140 deletions
diff --git a/router/al.cpp b/router/al.cpp index 4c8b0006..06c314eb 100644 --- a/router/al.cpp +++ b/router/al.cpp @@ -11,31 +11,31 @@ std::atomic<DriverIface*> CurrentCtxDriver{nullptr}; #define DECL_THUNK1(R,n,T1) AL_API R AL_APIENTRY n(T1 a) \ { \ - DriverIface *iface = ThreadCtxDriver; \ + DriverIface *iface = GetThreadDriver(); \ if(!iface) iface = CurrentCtxDriver.load(std::memory_order_acquire); \ return iface->n(a); \ } #define DECL_THUNK2(R,n,T1,T2) AL_API R AL_APIENTRY n(T1 a, T2 b) \ { \ - DriverIface *iface = ThreadCtxDriver; \ + DriverIface *iface = GetThreadDriver(); \ if(!iface) iface = CurrentCtxDriver.load(std::memory_order_acquire); \ return iface->n(a, b); \ } #define DECL_THUNK3(R,n,T1,T2,T3) AL_API R AL_APIENTRY n(T1 a, T2 b, T3 c) \ { \ - DriverIface *iface = ThreadCtxDriver; \ + DriverIface *iface = GetThreadDriver(); \ if(!iface) iface = CurrentCtxDriver.load(std::memory_order_acquire); \ return iface->n(a, b, c); \ } #define DECL_THUNK4(R,n,T1,T2,T3,T4) AL_API R AL_APIENTRY n(T1 a, T2 b, T3 c, T4 d) \ { \ - DriverIface *iface = ThreadCtxDriver; \ + DriverIface *iface = GetThreadDriver(); \ if(!iface) iface = CurrentCtxDriver.load(std::memory_order_acquire); \ return iface->n(a, b, c, d); \ } #define DECL_THUNK5(R,n,T1,T2,T3,T4,T5) AL_API R AL_APIENTRY n(T1 a, T2 b, T3 c, T4 d, T5 e) \ { \ - DriverIface *iface = ThreadCtxDriver; \ + DriverIface *iface = GetThreadDriver(); \ if(!iface) iface = CurrentCtxDriver.load(std::memory_order_acquire); \ return iface->n(a, b, c, d, e); \ } @@ -46,7 +46,7 @@ std::atomic<DriverIface*> CurrentCtxDriver{nullptr}; */ AL_API ALenum AL_APIENTRY alGetError(void) { - DriverIface *iface = ThreadCtxDriver; + DriverIface *iface = GetThreadDriver(); if(!iface) iface = CurrentCtxDriver.load(std::memory_order_acquire); return iface ? iface->alGetError() : AL_NO_ERROR; } @@ -130,3 +130,42 @@ DECL_THUNK3(void, alGetBufferi, ALuint, ALenum, ALint*) DECL_THUNK5(void, alGetBuffer3i, ALuint, ALenum, ALint*, ALint*, ALint*) DECL_THUNK3(void, alGetBufferiv, ALuint, ALenum, ALint*) DECL_THUNK5(void, alBufferData, ALuint, ALenum, const ALvoid*, ALsizei, ALsizei) + +/* EFX 1.0. Required here to be exported from libOpenAL32.dll.a/OpenAL32.lib + * with the router enabled. + */ +DECL_THUNK2(void, alGenFilters, ALsizei, ALuint*) +DECL_THUNK2(void, alDeleteFilters, ALsizei, const ALuint*) +DECL_THUNK1(ALboolean, alIsFilter, ALuint) +DECL_THUNK3(void, alFilterf, ALuint, ALenum, ALfloat) +DECL_THUNK3(void, alFilterfv, ALuint, ALenum, const ALfloat*) +DECL_THUNK3(void, alFilteri, ALuint, ALenum, ALint) +DECL_THUNK3(void, alFilteriv, ALuint, ALenum, const ALint*) +DECL_THUNK3(void, alGetFilterf, ALuint, ALenum, ALfloat*) +DECL_THUNK3(void, alGetFilterfv, ALuint, ALenum, ALfloat*) +DECL_THUNK3(void, alGetFilteri, ALuint, ALenum, ALint*) +DECL_THUNK3(void, alGetFilteriv, ALuint, ALenum, ALint*) + +DECL_THUNK2(void, alGenEffects, ALsizei, ALuint*) +DECL_THUNK2(void, alDeleteEffects, ALsizei, const ALuint*) +DECL_THUNK1(ALboolean, alIsEffect, ALuint) +DECL_THUNK3(void, alEffectf, ALuint, ALenum, ALfloat) +DECL_THUNK3(void, alEffectfv, ALuint, ALenum, const ALfloat*) +DECL_THUNK3(void, alEffecti, ALuint, ALenum, ALint) +DECL_THUNK3(void, alEffectiv, ALuint, ALenum, const ALint*) +DECL_THUNK3(void, alGetEffectf, ALuint, ALenum, ALfloat*) +DECL_THUNK3(void, alGetEffectfv, ALuint, ALenum, ALfloat*) +DECL_THUNK3(void, alGetEffecti, ALuint, ALenum, ALint*) +DECL_THUNK3(void, alGetEffectiv, ALuint, ALenum, ALint*) + +DECL_THUNK2(void, alGenAuxiliaryEffectSlots, ALsizei, ALuint*) +DECL_THUNK2(void, alDeleteAuxiliaryEffectSlots, ALsizei, const ALuint*) +DECL_THUNK1(ALboolean, alIsAuxiliaryEffectSlot, ALuint) +DECL_THUNK3(void, alAuxiliaryEffectSlotf, ALuint, ALenum, ALfloat) +DECL_THUNK3(void, alAuxiliaryEffectSlotfv, ALuint, ALenum, const ALfloat*) +DECL_THUNK3(void, alAuxiliaryEffectSloti, ALuint, ALenum, ALint) +DECL_THUNK3(void, alAuxiliaryEffectSlotiv, ALuint, ALenum, const ALint*) +DECL_THUNK3(void, alGetAuxiliaryEffectSlotf, ALuint, ALenum, ALfloat*) +DECL_THUNK3(void, alGetAuxiliaryEffectSlotfv, ALuint, ALenum, ALfloat*) +DECL_THUNK3(void, alGetAuxiliaryEffectSloti, ALuint, ALenum, ALint*) +DECL_THUNK3(void, alGetAuxiliaryEffectSlotiv, ALuint, ALenum, ALint*) diff --git a/router/alc.cpp b/router/alc.cpp index c99e7c93..3aa3382b 100644 --- a/router/alc.cpp +++ b/router/alc.cpp @@ -17,10 +17,10 @@ #define DECL(x) { #x, reinterpret_cast<void*>(x) } struct FuncExportEntry { - const ALCchar *funcName; - ALCvoid *address; + const char *funcName; + void *address; }; -static const std::array<FuncExportEntry,95> alcFunctions{{ +static const std::array<FuncExportEntry,128> alcFunctions{{ DECL(alcCreateContext), DECL(alcMakeContextCurrent), DECL(alcProcessContext), @@ -118,6 +118,41 @@ static const std::array<FuncExportEntry,95> alcFunctions{{ DECL(alDopplerVelocity), DECL(alSpeedOfSound), DECL(alDistanceModel), + + /* EFX 1.0 */ + DECL(alGenFilters), + DECL(alDeleteFilters), + DECL(alIsFilter), + DECL(alFilterf), + DECL(alFilterfv), + DECL(alFilteri), + DECL(alFilteriv), + DECL(alGetFilterf), + DECL(alGetFilterfv), + DECL(alGetFilteri), + DECL(alGetFilteriv), + DECL(alGenEffects), + DECL(alDeleteEffects), + DECL(alIsEffect), + DECL(alEffectf), + DECL(alEffectfv), + DECL(alEffecti), + DECL(alEffectiv), + DECL(alGetEffectf), + DECL(alGetEffectfv), + DECL(alGetEffecti), + DECL(alGetEffectiv), + DECL(alGenAuxiliaryEffectSlots), + DECL(alDeleteAuxiliaryEffectSlots), + DECL(alIsAuxiliaryEffectSlot), + DECL(alAuxiliaryEffectSlotf), + DECL(alAuxiliaryEffectSlotfv), + DECL(alAuxiliaryEffectSloti), + DECL(alAuxiliaryEffectSlotiv), + DECL(alGetAuxiliaryEffectSlotf), + DECL(alGetAuxiliaryEffectSlotfv), + DECL(alGetAuxiliaryEffectSloti), + DECL(alGetAuxiliaryEffectSlotiv), }}; #undef DECL @@ -249,7 +284,7 @@ static const ALCint alcMajorVersion = 1; static const ALCint alcMinorVersion = 1; -static std::mutex EnumerationLock; +static std::recursive_mutex EnumerationLock; static std::mutex ContextSwitchLock; static std::atomic<ALCenum> LastError{ALC_NO_ERROR}; @@ -309,6 +344,56 @@ static ALint GetDriverIndexForName(const EnumeratedList *list, const ALCchar *na } +static void InitCtxFuncs(DriverIface &iface) +{ + ALCdevice *device{iface.alcGetContextsDevice(iface.alcGetCurrentContext())}; + +#define LOAD_PROC(x) do { \ + iface.x = reinterpret_cast<decltype(iface.x)>(iface.alGetProcAddress(#x));\ + if(!iface.x) \ + ERR("Failed to find entry point for %s in %ls\n", #x, \ + iface.Name.c_str()); \ +} while(0) + if(iface.alcIsExtensionPresent(device, "ALC_EXT_EFX")) + { + LOAD_PROC(alGenFilters); + LOAD_PROC(alDeleteFilters); + LOAD_PROC(alIsFilter); + LOAD_PROC(alFilterf); + LOAD_PROC(alFilterfv); + LOAD_PROC(alFilteri); + LOAD_PROC(alFilteriv); + LOAD_PROC(alGetFilterf); + LOAD_PROC(alGetFilterfv); + LOAD_PROC(alGetFilteri); + LOAD_PROC(alGetFilteriv); + LOAD_PROC(alGenEffects); + LOAD_PROC(alDeleteEffects); + LOAD_PROC(alIsEffect); + LOAD_PROC(alEffectf); + LOAD_PROC(alEffectfv); + LOAD_PROC(alEffecti); + LOAD_PROC(alEffectiv); + LOAD_PROC(alGetEffectf); + LOAD_PROC(alGetEffectfv); + LOAD_PROC(alGetEffecti); + LOAD_PROC(alGetEffectiv); + LOAD_PROC(alGenAuxiliaryEffectSlots); + LOAD_PROC(alDeleteAuxiliaryEffectSlots); + LOAD_PROC(alIsAuxiliaryEffectSlot); + LOAD_PROC(alAuxiliaryEffectSlotf); + LOAD_PROC(alAuxiliaryEffectSlotfv); + LOAD_PROC(alAuxiliaryEffectSloti); + LOAD_PROC(alAuxiliaryEffectSlotiv); + LOAD_PROC(alGetAuxiliaryEffectSlotf); + LOAD_PROC(alGetAuxiliaryEffectSlotfv); + LOAD_PROC(alGetAuxiliaryEffectSloti); + LOAD_PROC(alGetAuxiliaryEffectSlotiv); + } +#undef LOAD_PROC +} + + ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename) { ALCdevice *device = nullptr; @@ -325,7 +410,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename) devicename = nullptr; if(devicename) { - { std::lock_guard<std::mutex> _{EnumerationLock}; + { + std::lock_guard<std::recursive_mutex> _{EnumerationLock}; if(DevicesList.Names.empty()) (void)alcGetString(nullptr, ALC_DEVICE_SPECIFIER); idx = GetDriverIndexForName(&DevicesList, devicename); @@ -344,17 +430,17 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename) return nullptr; } TRACE("Found driver %d for name \"%s\"\n", idx, devicename); - device = DriverList[idx].alcOpenDevice(devicename); + device = DriverList[idx]->alcOpenDevice(devicename); } else { for(const auto &drv : DriverList) { - if(drv.ALCVer >= MAKE_ALC_VER(1, 1) || - drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) + if(drv->ALCVer >= MAKE_ALC_VER(1, 1) + || drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) { TRACE("Using default device from driver %d\n", idx); - device = drv.alcOpenDevice(nullptr); + device = drv->alcOpenDevice(nullptr); break; } ++idx; @@ -365,7 +451,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename) { if(DeviceIfaceMap.insert(device, idx) != ALC_NO_ERROR) { - DriverList[idx].alcCloseDevice(device); + DriverList[idx]->alcCloseDevice(device); device = nullptr; } } @@ -382,7 +468,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) LastError.store(ALC_INVALID_DEVICE); return ALC_FALSE; } - if(!DriverList[idx].alcCloseDevice(device)) + if(!DriverList[idx]->alcCloseDevice(device)) return ALC_FALSE; DeviceIfaceMap.removeByKey(device); return ALC_TRUE; @@ -399,12 +485,12 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin LastError.store(ALC_INVALID_DEVICE); return nullptr; } - context = DriverList[idx].alcCreateContext(device, attrlist); + context = DriverList[idx]->alcCreateContext(device, attrlist); if(context) { if(ContextIfaceMap.insert(context, idx) != ALC_NO_ERROR) { - DriverList[idx].alcDestroyContext(context); + DriverList[idx]->alcDestroyContext(context); context = nullptr; } } @@ -425,8 +511,11 @@ ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) LastError.store(ALC_INVALID_CONTEXT); return ALC_FALSE; } - if(!DriverList[idx].alcMakeContextCurrent(context)) + if(!DriverList[idx]->alcMakeContextCurrent(context)) return ALC_FALSE; + + auto do_init = [idx]() { InitCtxFuncs(*DriverList[idx]); }; + std::call_once(DriverList[idx]->InitOnceCtx, do_init); } /* Unset the context from the old driver if it's different from the new @@ -434,21 +523,21 @@ ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) */ if(idx < 0) { - DriverIface *oldiface = ThreadCtxDriver; + DriverIface *oldiface = GetThreadDriver(); if(oldiface) oldiface->alcSetThreadContext(nullptr); oldiface = CurrentCtxDriver.exchange(nullptr); if(oldiface) oldiface->alcMakeContextCurrent(nullptr); } else { - DriverIface *oldiface = ThreadCtxDriver; - if(oldiface && oldiface != &DriverList[idx]) + DriverIface *oldiface = GetThreadDriver(); + if(oldiface && oldiface != DriverList[idx].get()) oldiface->alcSetThreadContext(nullptr); - oldiface = CurrentCtxDriver.exchange(&DriverList[idx]); - if(oldiface && oldiface != &DriverList[idx]) + oldiface = CurrentCtxDriver.exchange(DriverList[idx].get()); + if(oldiface && oldiface != DriverList[idx].get()) oldiface->alcMakeContextCurrent(nullptr); } - ThreadCtxDriver = nullptr; + SetThreadDriver(nullptr); return ALC_TRUE; } @@ -459,7 +548,7 @@ ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context) { ALint idx = ContextIfaceMap.lookupByKey(context); if(idx >= 0) - return DriverList[idx].alcProcessContext(context); + return DriverList[idx]->alcProcessContext(context); } LastError.store(ALC_INVALID_CONTEXT); } @@ -470,7 +559,7 @@ ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context) { ALint idx = ContextIfaceMap.lookupByKey(context); if(idx >= 0) - return DriverList[idx].alcSuspendContext(context); + return DriverList[idx]->alcSuspendContext(context); } LastError.store(ALC_INVALID_CONTEXT); } @@ -485,13 +574,13 @@ ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context) return; } - DriverList[idx].alcDestroyContext(context); + DriverList[idx]->alcDestroyContext(context); ContextIfaceMap.removeByKey(context); } ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void) { - DriverIface *iface = ThreadCtxDriver; + DriverIface *iface = GetThreadDriver(); if(!iface) iface = CurrentCtxDriver.load(); return iface ? iface->alcGetCurrentContext() : nullptr; } @@ -502,7 +591,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context) { ALint idx = ContextIfaceMap.lookupByKey(context); if(idx >= 0) - return DriverList[idx].alcGetContextsDevice(context); + return DriverList[idx]->alcGetContextsDevice(context); } LastError.store(ALC_INVALID_CONTEXT); return nullptr; @@ -515,7 +604,7 @@ ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) { ALint idx = DeviceIfaceMap.lookupByKey(device); if(idx < 0) return ALC_INVALID_DEVICE; - return DriverList[idx].alcGetError(device); + return DriverList[idx]->alcGetError(device); } return LastError.exchange(ALC_NO_ERROR); } @@ -533,7 +622,7 @@ ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const A LastError.store(ALC_INVALID_DEVICE); return ALC_FALSE; } - return DriverList[idx].alcIsExtensionPresent(device, extname); + return DriverList[idx]->alcIsExtensionPresent(device, extname); } len = strlen(extname); @@ -562,7 +651,7 @@ ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *f LastError.store(ALC_INVALID_DEVICE); return nullptr; } - return DriverList[idx].alcGetProcAddress(device, funcname); + return DriverList[idx]->alcGetProcAddress(device, funcname); } auto iter = std::find_if(alcFunctions.cbegin(), alcFunctions.cend(), @@ -582,7 +671,7 @@ ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *e LastError.store(ALC_INVALID_DEVICE); return 0; } - return DriverList[idx].alcGetEnumValue(device, enumname); + return DriverList[idx]->alcGetEnumValue(device, enumname); } auto iter = std::find_if(alcEnumerations.cbegin(), alcEnumerations.cend(), @@ -602,7 +691,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum para LastError.store(ALC_INVALID_DEVICE); return nullptr; } - return DriverList[idx].alcGetString(device, param); + return DriverList[idx]->alcGetString(device, param); } switch(param) @@ -623,18 +712,18 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum para return alcExtensionList; case ALC_DEVICE_SPECIFIER: - { std::lock_guard<std::mutex> _{EnumerationLock}; + { + std::lock_guard<std::recursive_mutex> _{EnumerationLock}; DevicesList.clear(); - ALint idx = 0; + ALint idx{0}; for(const auto &drv : DriverList) { /* Only enumerate names from drivers that support it. */ - if(drv.ALCVer >= MAKE_ALC_VER(1, 1) || - drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) + if(drv->ALCVer >= MAKE_ALC_VER(1, 1) + || drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) AppendDeviceList(&DevicesList, - drv.alcGetString(nullptr, ALC_DEVICE_SPECIFIER), idx - ); - idx++; + drv->alcGetString(nullptr, ALC_DEVICE_SPECIFIER), idx); + ++idx; } /* Ensure the list is double-null termianted. */ if(DevicesList.Names.empty()) @@ -644,23 +733,22 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum para } case ALC_ALL_DEVICES_SPECIFIER: - { std::lock_guard<std::mutex> _{EnumerationLock}; + { + std::lock_guard<std::recursive_mutex> _{EnumerationLock}; AllDevicesList.clear(); - ALint idx = 0; + ALint idx{0}; for(const auto &drv : DriverList) { /* If the driver doesn't support ALC_ENUMERATE_ALL_EXT, substitute * standard enumeration. */ - if(drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT")) + if(drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT")) AppendDeviceList(&AllDevicesList, - drv.alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER), idx - ); - else if(drv.ALCVer >= MAKE_ALC_VER(1, 1) || - drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) + drv->alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER), idx); + else if(drv->ALCVer >= MAKE_ALC_VER(1, 1) + || drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) AppendDeviceList(&AllDevicesList, - drv.alcGetString(nullptr, ALC_DEVICE_SPECIFIER), idx - ); + drv->alcGetString(nullptr, ALC_DEVICE_SPECIFIER), idx); ++idx; } /* Ensure the list is double-null termianted. */ @@ -671,16 +759,16 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum para } case ALC_CAPTURE_DEVICE_SPECIFIER: - { std::lock_guard<std::mutex> _{EnumerationLock}; + { + std::lock_guard<std::recursive_mutex> _{EnumerationLock}; CaptureDevicesList.clear(); - ALint idx = 0; + ALint idx{0}; for(const auto &drv : DriverList) { - if(drv.ALCVer >= MAKE_ALC_VER(1, 1) || - drv.alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE")) + if(drv->ALCVer >= MAKE_ALC_VER(1, 1) + || drv->alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE")) AppendDeviceList(&CaptureDevicesList, - drv.alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER), idx - ); + drv->alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER), idx); ++idx; } /* Ensure the list is double-null termianted. */ @@ -692,40 +780,33 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum para case ALC_DEFAULT_DEVICE_SPECIFIER: { - auto iter = std::find_if(DriverList.cbegin(), DriverList.cend(), - [](const DriverIface &drv) -> bool - { - return drv.ALCVer >= MAKE_ALC_VER(1, 1) || - drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"); - } - ); - if(iter != DriverList.cend()) - return iter->alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER); + for(const auto &drv : DriverList) + { + if(drv->ALCVer >= MAKE_ALC_VER(1, 1) + || drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) + return drv->alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER); + } return ""; } case ALC_DEFAULT_ALL_DEVICES_SPECIFIER: { - auto iter = std::find_if(DriverList.cbegin(), DriverList.cend(), - [](const DriverIface &drv) -> bool - { return drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT") != ALC_FALSE; } - ); - if(iter != DriverList.cend()) - return iter->alcGetString(nullptr, ALC_DEFAULT_ALL_DEVICES_SPECIFIER); + for(const auto &drv : DriverList) + { + if(drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT") != ALC_FALSE) + return drv->alcGetString(nullptr, ALC_DEFAULT_ALL_DEVICES_SPECIFIER); + } return ""; } case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER: { - auto iter = std::find_if(DriverList.cbegin(), DriverList.cend(), - [](const DriverIface &drv) -> bool - { - return drv.ALCVer >= MAKE_ALC_VER(1, 1) || - drv.alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"); - } - ); - if(iter != DriverList.cend()) - return iter->alcGetString(nullptr, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER); + for(const auto &drv : DriverList) + { + if(drv->ALCVer >= MAKE_ALC_VER(1, 1) + || drv->alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE")) + return drv->alcGetString(nullptr, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER); + } return ""; } @@ -746,7 +827,7 @@ ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsi LastError.store(ALC_INVALID_DEVICE); return; } - return DriverList[idx].alcGetIntegerv(device, param, size, values); + return DriverList[idx]->alcGetIntegerv(device, param, size, values); } if(size <= 0 || values == nullptr) @@ -800,7 +881,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, devicename = nullptr; if(devicename) { - { std::lock_guard<std::mutex> _{EnumerationLock}; + { + std::lock_guard<std::recursive_mutex> _{EnumerationLock}; if(CaptureDevicesList.Names.empty()) (void)alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER); idx = GetDriverIndexForName(&CaptureDevicesList, devicename); @@ -813,21 +895,17 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, return nullptr; } TRACE("Found driver %d for name \"%s\"\n", idx, devicename); - device = DriverList[idx].alcCaptureOpenDevice( - devicename, frequency, format, buffersize - ); + device = DriverList[idx]->alcCaptureOpenDevice(devicename, frequency, format, buffersize); } else { for(const auto &drv : DriverList) { - if(drv.ALCVer >= MAKE_ALC_VER(1, 1) || - drv.alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE")) + if(drv->ALCVer >= MAKE_ALC_VER(1, 1) + || drv->alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE")) { TRACE("Using default capture device from driver %d\n", idx); - device = drv.alcCaptureOpenDevice( - nullptr, frequency, format, buffersize - ); + device = drv->alcCaptureOpenDevice(nullptr, frequency, format, buffersize); break; } ++idx; @@ -838,7 +916,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, { if(DeviceIfaceMap.insert(device, idx) != ALC_NO_ERROR) { - DriverList[idx].alcCaptureCloseDevice(device); + DriverList[idx]->alcCaptureCloseDevice(device); device = nullptr; } } @@ -855,7 +933,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) LastError.store(ALC_INVALID_DEVICE); return ALC_FALSE; } - if(!DriverList[idx].alcCaptureCloseDevice(device)) + if(!DriverList[idx]->alcCaptureCloseDevice(device)) return ALC_FALSE; DeviceIfaceMap.removeByKey(device); return ALC_TRUE; @@ -867,7 +945,7 @@ ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) { ALint idx = DeviceIfaceMap.lookupByKey(device); if(idx >= 0) - return DriverList[idx].alcCaptureStart(device); + return DriverList[idx]->alcCaptureStart(device); } LastError.store(ALC_INVALID_DEVICE); } @@ -878,7 +956,7 @@ ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) { ALint idx = DeviceIfaceMap.lookupByKey(device); if(idx >= 0) - return DriverList[idx].alcCaptureStop(device); + return DriverList[idx]->alcCaptureStop(device); } LastError.store(ALC_INVALID_DEVICE); } @@ -889,7 +967,7 @@ ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, { ALint idx = DeviceIfaceMap.lookupByKey(device); if(idx >= 0) - return DriverList[idx].alcCaptureSamples(device, buffer, samples); + return DriverList[idx]->alcCaptureSamples(device, buffer, samples); } LastError.store(ALC_INVALID_DEVICE); } @@ -902,27 +980,30 @@ ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context) if(!context) { - DriverIface *oldiface = ThreadCtxDriver; + DriverIface *oldiface = GetThreadDriver(); if(oldiface && !oldiface->alcSetThreadContext(nullptr)) return ALC_FALSE; - ThreadCtxDriver = nullptr; + SetThreadDriver(nullptr); return ALC_TRUE; } idx = ContextIfaceMap.lookupByKey(context); if(idx >= 0) { - if(DriverList[idx].alcSetThreadContext(context)) + if(DriverList[idx]->alcSetThreadContext(context)) { - DriverIface *oldiface = ThreadCtxDriver; - if(oldiface != &DriverList[idx]) + auto do_init = [idx]() { InitCtxFuncs(*DriverList[idx]); }; + std::call_once(DriverList[idx]->InitOnceCtx, do_init); + + DriverIface *oldiface = GetThreadDriver(); + if(oldiface != DriverList[idx].get()) { - ThreadCtxDriver = &DriverList[idx]; + SetThreadDriver(DriverList[idx].get()); if(oldiface) oldiface->alcSetThreadContext(nullptr); } return ALC_TRUE; } - err = DriverList[idx].alcGetError(nullptr); + err = DriverList[idx]->alcGetError(nullptr); } LastError.store(err); return ALC_FALSE; @@ -930,7 +1011,7 @@ ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context) ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void) { - DriverIface *iface = ThreadCtxDriver; + DriverIface *iface = GetThreadDriver(); if(iface) return iface->alcGetThreadContext(); return nullptr; } diff --git a/router/router.cpp b/router/router.cpp index 85a75aea..3c891053 100644 --- a/router/router.cpp +++ b/router/router.cpp @@ -17,13 +17,18 @@ #include "version.h" -std::vector<DriverIface> DriverList; +std::vector<DriverIfacePtr> DriverList; thread_local DriverIface *ThreadCtxDriver; enum LogLevel LogLevel = LogLevel_Error; FILE *LogFile; +#ifdef __MINGW32__ +DriverIface *GetThreadDriver() noexcept { return ThreadCtxDriver; } +void SetThreadDriver(DriverIface *driver) noexcept { ThreadCtxDriver = driver; } +#endif + static void LoadDriverList(void); @@ -79,13 +84,13 @@ static void AddModule(HMODULE module, const WCHAR *name) { for(auto &drv : DriverList) { - if(drv.Module == module) + if(drv->Module == module) { TRACE("Skipping already-loaded module %p\n", decltype(std::declval<void*>()){module}); FreeLibrary(module); return; } - if(drv.Name == name) + if(drv->Name == name) { TRACE("Skipping similarly-named module %ls\n", name); FreeLibrary(module); @@ -93,8 +98,8 @@ static void AddModule(HMODULE module, const WCHAR *name) } } - DriverList.emplace_back(name, module); - DriverIface &newdrv = DriverList.back(); + DriverList.emplace_back(std::make_unique<DriverIface>(name, module)); + DriverIface &newdrv = *DriverList.back(); /* Load required functions. */ int err = 0; @@ -184,18 +189,6 @@ static void AddModule(HMODULE module, const WCHAR *name) LOAD_PROC(alGenBuffers); LOAD_PROC(alDeleteBuffers); LOAD_PROC(alIsBuffer); - LOAD_PROC(alBufferf); - LOAD_PROC(alBuffer3f); - LOAD_PROC(alBufferfv); - LOAD_PROC(alBufferi); - LOAD_PROC(alBuffer3i); - LOAD_PROC(alBufferiv); - LOAD_PROC(alGetBufferf); - LOAD_PROC(alGetBuffer3f); - LOAD_PROC(alGetBufferfv); - LOAD_PROC(alGetBufferi); - LOAD_PROC(alGetBuffer3i); - LOAD_PROC(alGetBufferiv); LOAD_PROC(alBufferData); LOAD_PROC(alDopplerFactor); LOAD_PROC(alDopplerVelocity); @@ -209,7 +202,32 @@ static void AddModule(HMODULE module, const WCHAR *name) if(newdrv.alcGetError(nullptr) == ALC_NO_ERROR) newdrv.ALCVer = MAKE_ALC_VER(alc_ver[0], alc_ver[1]); else + { + WARN("Failed to query ALC version for %ls, assuming 1.0\n", name); newdrv.ALCVer = MAKE_ALC_VER(1, 0); + } + +#undef LOAD_PROC +#define LOAD_PROC(x) do { \ + newdrv.x = reinterpret_cast<decltype(newdrv.x)>(reinterpret_cast<void*>( \ + GetProcAddress(module, #x))); \ + if(!newdrv.x) \ + { \ + WARN("Failed to find optional entry point for %s in %ls\n", #x, name); \ + } \ +} while(0) + LOAD_PROC(alBufferf); + LOAD_PROC(alBuffer3f); + LOAD_PROC(alBufferfv); + LOAD_PROC(alBufferi); + LOAD_PROC(alBuffer3i); + LOAD_PROC(alBufferiv); + LOAD_PROC(alGetBufferf); + LOAD_PROC(alGetBuffer3f); + LOAD_PROC(alGetBufferfv); + LOAD_PROC(alGetBufferi); + LOAD_PROC(alGetBuffer3i); + LOAD_PROC(alGetBufferiv); #undef LOAD_PROC #define LOAD_PROC(x) do { \ @@ -360,7 +378,7 @@ PtrIntMap::~PtrIntMap() mCapacity = 0; } -ALenum PtrIntMap::insert(ALvoid *key, ALint value) +ALenum PtrIntMap::insert(void *key, int value) { std::lock_guard<std::mutex> maplock{mLock}; auto iter = std::lower_bound(mKeys, mKeys+mSize, key); @@ -370,15 +388,15 @@ ALenum PtrIntMap::insert(ALvoid *key, ALint value) { if(mSize == mCapacity) { - ALvoid **newkeys{nullptr}; + void **newkeys{nullptr}; ALsizei newcap{mCapacity ? (mCapacity<<1) : 4}; if(newcap > mCapacity) - newkeys = static_cast<ALvoid**>( + newkeys = static_cast<void**>( al_calloc(16, (sizeof(mKeys[0])+sizeof(mValues[0]))*newcap) ); if(!newkeys) return AL_OUT_OF_MEMORY; - auto newvalues = reinterpret_cast<ALint*>(&newkeys[newcap]); + auto newvalues = reinterpret_cast<int*>(&newkeys[newcap]); if(mKeys) { @@ -404,9 +422,9 @@ ALenum PtrIntMap::insert(ALvoid *key, ALint value) return AL_NO_ERROR; } -ALint PtrIntMap::removeByKey(ALvoid *key) +int PtrIntMap::removeByKey(void *key) { - ALint ret = -1; + int ret = -1; std::lock_guard<std::mutex> maplock{mLock}; auto iter = std::lower_bound(mKeys, mKeys+mSize, key); @@ -425,9 +443,9 @@ ALint PtrIntMap::removeByKey(ALvoid *key) return ret; } -ALint PtrIntMap::lookupByKey(ALvoid *key) +int PtrIntMap::lookupByKey(void *key) { - ALint ret = -1; + int ret = -1; std::lock_guard<std::mutex> maplock{mLock}; auto iter = std::lower_bound(mKeys, mKeys+mSize, key); diff --git a/router/router.h b/router/router.h index 007b6a16..2a126d42 100644 --- a/router/router.h +++ b/router/router.h @@ -7,10 +7,12 @@ #include <stdio.h> -#include <vector> -#include <string> #include <atomic> +#include <memory> #include <mutex> +#include <string> +#include <utility> +#include <vector> #include "AL/alc.h" #include "AL/al.h" @@ -23,6 +25,7 @@ struct DriverIface { std::wstring Name; HMODULE Module{nullptr}; int ALCVer{0}; + std::once_flag InitOnceCtx{}; LPALCCREATECONTEXT alcCreateContext{nullptr}; LPALCMAKECONTEXTCURRENT alcMakeContextCurrent{nullptr}; @@ -122,8 +125,44 @@ struct DriverIface { LPALSPEEDOFSOUND alSpeedOfSound{nullptr}; LPALDISTANCEMODEL alDistanceModel{nullptr}; - DriverIface(std::wstring name, HMODULE mod) - : Name(std::move(name)), Module(mod) + /* Functions to load after first context creation. */ + LPALGENFILTERS alGenFilters{nullptr}; + LPALDELETEFILTERS alDeleteFilters{nullptr}; + LPALISFILTER alIsFilter{nullptr}; + LPALFILTERF alFilterf{nullptr}; + LPALFILTERFV alFilterfv{nullptr}; + LPALFILTERI alFilteri{nullptr}; + LPALFILTERIV alFilteriv{nullptr}; + LPALGETFILTERF alGetFilterf{nullptr}; + LPALGETFILTERFV alGetFilterfv{nullptr}; + LPALGETFILTERI alGetFilteri{nullptr}; + LPALGETFILTERIV alGetFilteriv{nullptr}; + LPALGENEFFECTS alGenEffects{nullptr}; + LPALDELETEEFFECTS alDeleteEffects{nullptr}; + LPALISEFFECT alIsEffect{nullptr}; + LPALEFFECTF alEffectf{nullptr}; + LPALEFFECTFV alEffectfv{nullptr}; + LPALEFFECTI alEffecti{nullptr}; + LPALEFFECTIV alEffectiv{nullptr}; + LPALGETEFFECTF alGetEffectf{nullptr}; + LPALGETEFFECTFV alGetEffectfv{nullptr}; + LPALGETEFFECTI alGetEffecti{nullptr}; + LPALGETEFFECTIV alGetEffectiv{nullptr}; + LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots{nullptr}; + LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots{nullptr}; + LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot{nullptr}; + LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf{nullptr}; + LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv{nullptr}; + LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti{nullptr}; + LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv{nullptr}; + LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf{nullptr}; + LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv{nullptr}; + LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti{nullptr}; + LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv{nullptr}; + + template<typename T> + DriverIface(T&& name, HMODULE mod) + : Name(std::forward<T>(name)), Module(mod) { } ~DriverIface() { @@ -132,17 +171,29 @@ struct DriverIface { Module = nullptr; } }; +using DriverIfacePtr = std::unique_ptr<DriverIface>; -extern std::vector<DriverIface> DriverList; +extern std::vector<DriverIfacePtr> DriverList; extern thread_local DriverIface *ThreadCtxDriver; extern std::atomic<DriverIface*> CurrentCtxDriver; +/* HACK: MinGW generates bad code when accessing an extern thread_local object. + * Add a wrapper function for it that only accesses it where it's defined. + */ +#ifdef __MINGW32__ +DriverIface *GetThreadDriver() noexcept; +void SetThreadDriver(DriverIface *driver) noexcept; +#else +inline DriverIface *GetThreadDriver() noexcept { return ThreadCtxDriver; } +inline void SetThreadDriver(DriverIface *driver) noexcept { ThreadCtxDriver = driver; } +#endif + class PtrIntMap { - ALvoid **mKeys{nullptr}; + void **mKeys{nullptr}; /* Shares memory with keys. */ - ALint *mValues{nullptr}; + int *mValues{nullptr}; ALsizei mSize{0}; ALsizei mCapacity{0}; @@ -152,9 +203,9 @@ public: PtrIntMap() = default; ~PtrIntMap(); - ALenum insert(ALvoid *key, ALint value); - ALint removeByKey(ALvoid *key); - ALint lookupByKey(ALvoid *key); + ALenum insert(void *key, int value); + int removeByKey(void *key); + int lookupByKey(void *key); }; |