diff --git a/include/Nazara/Audio/OpenALDevice.hpp b/include/Nazara/Audio/OpenALDevice.hpp index ce236b88e..09d170e3b 100644 --- a/include/Nazara/Audio/OpenALDevice.hpp +++ b/include/Nazara/Audio/OpenALDevice.hpp @@ -27,6 +27,7 @@ namespace Nz enum class OpenALExtension { SourceLatency, + ThreadLocalContext, Max = SourceLatency }; @@ -82,6 +83,8 @@ namespace Nz OpenALDevice& operator=(const OpenALDevice&) = delete; OpenALDevice& operator=(OpenALDevice&&) = delete; + static const OpenALDevice* GetCurrentDevice(); + // We give each device its own set of function pointer, even though regular OpenAL extensions are always the same (for a set library). // This makes it easier to wrap them (for error handling), and extension pointers are device-local anyway. #define NAZARA_AUDIO_AL_ALC_FUNCTION(name) decltype(&::name) name; diff --git a/include/Nazara/Audio/OpenALFunctions.hpp b/include/Nazara/Audio/OpenALFunctions.hpp index fb58e77dc..1af59b728 100644 --- a/include/Nazara/Audio/OpenALFunctions.hpp +++ b/include/Nazara/Audio/OpenALFunctions.hpp @@ -28,6 +28,18 @@ #define NAZARA_AUDIO_AL_EXT_END() #endif +#ifndef NAZARA_AUDIO_ALC_EXT_FUNCTION +#define NAZARA_AUDIO_ALC_EXT_FUNCTION(func) NAZARA_AUDIO_AL_EXT_FUNCTION(func) +#endif + +#ifndef NAZARA_AUDIO_ALC_EXT_BEGIN +#define NAZARA_AUDIO_ALC_EXT_BEGIN(ext) NAZARA_AUDIO_AL_EXT_BEGIN(ext) +#endif + +#ifndef NAZARA_AUDIO_ALC_EXT_END +#define NAZARA_AUDIO_ALC_EXT_END() NAZARA_AUDIO_AL_EXT_END() +#endif + NAZARA_AUDIO_AL_FUNCTION(alBuffer3f) NAZARA_AUDIO_AL_FUNCTION(alBuffer3i) NAZARA_AUDIO_AL_FUNCTION(alBufferData) @@ -102,7 +114,7 @@ NAZARA_AUDIO_AL_FUNCTION(alSourceStopv) NAZARA_AUDIO_AL_FUNCTION(alSourceUnqueueBuffers) NAZARA_AUDIO_AL_FUNCTION(alSpeedOfSound) -#ifndef NAZARA_PLATFORM_WEB +#ifdef AL_SOFT_source_latency NAZARA_AUDIO_AL_EXT_BEGIN(AL_SOFT_source_latency) NAZARA_AUDIO_AL_EXT_FUNCTION(alGetSource3dSOFT) NAZARA_AUDIO_AL_EXT_FUNCTION(alGetSource3i64SOFT) @@ -140,9 +152,19 @@ NAZARA_AUDIO_ALC_FUNCTION(alcOpenDevice) NAZARA_AUDIO_ALC_FUNCTION(alcProcessContext) NAZARA_AUDIO_ALC_FUNCTION(alcSuspendContext) +#ifdef ALC_EXT_thread_local_context +NAZARA_AUDIO_ALC_EXT_BEGIN(ALC_EXT_thread_local_context) +NAZARA_AUDIO_ALC_EXT_FUNCTION(alcGetThreadContext) +NAZARA_AUDIO_ALC_EXT_FUNCTION(alcSetThreadContext) +NAZARA_AUDIO_ALC_EXT_END() +#endif + #undef NAZARA_AUDIO_AL_FUNCTION #undef NAZARA_AUDIO_AL_ALC_FUNCTION #undef NAZARA_AUDIO_AL_EXT_FUNCTION -#undef NAZARA_AUDIO_ALC_FUNCTION #undef NAZARA_AUDIO_AL_EXT_BEGIN #undef NAZARA_AUDIO_AL_EXT_END +#undef NAZARA_AUDIO_ALC_EXT_FUNCTION +#undef NAZARA_AUDIO_ALC_EXT_BEGIN +#undef NAZARA_AUDIO_ALC_EXT_END +#undef NAZARA_AUDIO_ALC_FUNCTION diff --git a/src/Nazara/Audio/OpenALDevice.cpp b/src/Nazara/Audio/OpenALDevice.cpp index 37aed3bf4..c36b8bd2e 100644 --- a/src/Nazara/Audio/OpenALDevice.cpp +++ b/src/Nazara/Audio/OpenALDevice.cpp @@ -23,7 +23,9 @@ namespace Nz #include }; - thread_local const OpenALDevice* s_currentALDevice; + // Regular OpenAL contexts are process-wide, but ALC_EXT_thread_local_context allows thread-local contexts + const OpenALDevice* s_currentGlobalALDevice; + thread_local const OpenALDevice* s_currentThreadALDevice; template struct ALWrapper; @@ -35,7 +37,7 @@ namespace Nz { return [](Args... args) -> Ret { - const OpenALDevice* device = s_currentALDevice; //< pay TLS cost once + const OpenALDevice* device = OpenALDevice::GetCurrentDevice(); assert(device); FuncType funcPtr = reinterpret_cast(device->GetFunctionByIndex(FuncIndex)); @@ -121,7 +123,7 @@ namespace Nz if (m_library.alcMakeContextCurrent(m_context) != AL_TRUE) throw std::runtime_error("failed to activate OpenAL context"); - s_currentALDevice = this; + s_currentGlobalALDevice = this; SymbolLoader loader(*this); #ifdef NAZARA_DEBUG @@ -131,6 +133,7 @@ namespace Nz #define NAZARA_AUDIO_AL_FUNCTION(name) loader.Load(name, #name, library.name); #define NAZARA_AUDIO_ALC_FUNCTION(name) loader.Load(name, #name, library.name); #define NAZARA_AUDIO_AL_EXT_FUNCTION(name) loader.Load(name, #name, nullptr); +#define NAZARA_AUDIO_ALC_EXT_FUNCTION(name) loader.Load(name, #name, nullptr); #include m_renderer = reinterpret_cast(alGetString(AL_RENDERER)); @@ -157,6 +160,9 @@ namespace Nz if (library.alIsExtensionPresent("AL_SOFT_source_latency")) m_extensionStatus[OpenALExtension::SourceLatency] = true; + if (library.alIsExtensionPresent("ALC_EXT_thread_local_context")) + m_extensionStatus[OpenALExtension::ThreadLocalContext] = true; + SetListenerDirection(Vector3f::Forward()); } @@ -164,20 +170,23 @@ namespace Nz { NAZARA_USE_ANONYMOUS_NAMESPACE - MakeContextCurrent(); - + // alcMakeContextCurrent resets the thread context + alcMakeContextCurrent(m_context); alcDestroyContext(m_context); alcCloseDevice(m_device); - if (s_currentALDevice == this) - s_currentALDevice = nullptr; + if (s_currentThreadALDevice) + s_currentThreadALDevice = nullptr; + + if (s_currentGlobalALDevice == this) + s_currentGlobalALDevice = nullptr; } bool OpenALDevice::ClearErrorFlag() const { NAZARA_USE_ANONYMOUS_NAMESPACE - assert(s_currentALDevice == this); + assert(GetCurrentDevice() == this); alGetError(); return true; @@ -322,10 +331,27 @@ namespace Nz { NAZARA_USE_ANONYMOUS_NAMESPACE - if (s_currentALDevice != this) + if (alcSetThreadContext) { - m_library.alcMakeContextCurrent(m_context); - s_currentALDevice = this; + if (s_currentThreadALDevice != this) + { + alcSetThreadContext(m_context); + s_currentThreadALDevice = this; + } + } + else + { + if (s_currentGlobalALDevice != this) + { + /* + From EXT_thread_local_context: + alcMakeContextCurrent changes the current process-wide context and set the current thread-local context to NULL. + This has the side effect of changing the current thread-local context, so that the new current process-wide context will be used. + */ + alcMakeContextCurrent(m_context); + s_currentGlobalALDevice = this; + s_currentThreadALDevice = nullptr; + } } } @@ -358,7 +384,7 @@ namespace Nz { NAZARA_USE_ANONYMOUS_NAMESPACE - assert(s_currentALDevice == this); + assert(GetCurrentDevice() == this); bool hasAnyError = false; if (ALuint lastError = alGetError(); lastError != AL_NO_ERROR) @@ -485,4 +511,13 @@ namespace Nz alSpeedOfSound(speed); } + + const OpenALDevice* OpenALDevice::GetCurrentDevice() + { + const OpenALDevice* device = s_currentThreadALDevice; + if (device) + return device; + + return s_currentGlobalALDevice; + } }