Audio: Implement support for ALC_EXT_thread_local_context

This commit is contained in:
SirLynix 2023-12-04 17:38:05 +01:00
parent 3e1b61070c
commit 3fb1096d07
3 changed files with 74 additions and 14 deletions

View File

@ -27,6 +27,7 @@ namespace Nz
enum class OpenALExtension enum class OpenALExtension
{ {
SourceLatency, SourceLatency,
ThreadLocalContext,
Max = SourceLatency Max = SourceLatency
}; };
@ -82,6 +83,8 @@ namespace Nz
OpenALDevice& operator=(const OpenALDevice&) = delete; OpenALDevice& operator=(const OpenALDevice&) = delete;
OpenALDevice& operator=(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). // 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. // 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; #define NAZARA_AUDIO_AL_ALC_FUNCTION(name) decltype(&::name) name;

View File

@ -28,6 +28,18 @@
#define NAZARA_AUDIO_AL_EXT_END() #define NAZARA_AUDIO_AL_EXT_END()
#endif #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(alBuffer3f)
NAZARA_AUDIO_AL_FUNCTION(alBuffer3i) NAZARA_AUDIO_AL_FUNCTION(alBuffer3i)
NAZARA_AUDIO_AL_FUNCTION(alBufferData) NAZARA_AUDIO_AL_FUNCTION(alBufferData)
@ -102,7 +114,7 @@ NAZARA_AUDIO_AL_FUNCTION(alSourceStopv)
NAZARA_AUDIO_AL_FUNCTION(alSourceUnqueueBuffers) NAZARA_AUDIO_AL_FUNCTION(alSourceUnqueueBuffers)
NAZARA_AUDIO_AL_FUNCTION(alSpeedOfSound) 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_BEGIN(AL_SOFT_source_latency)
NAZARA_AUDIO_AL_EXT_FUNCTION(alGetSource3dSOFT) NAZARA_AUDIO_AL_EXT_FUNCTION(alGetSource3dSOFT)
NAZARA_AUDIO_AL_EXT_FUNCTION(alGetSource3i64SOFT) NAZARA_AUDIO_AL_EXT_FUNCTION(alGetSource3i64SOFT)
@ -140,9 +152,19 @@ NAZARA_AUDIO_ALC_FUNCTION(alcOpenDevice)
NAZARA_AUDIO_ALC_FUNCTION(alcProcessContext) NAZARA_AUDIO_ALC_FUNCTION(alcProcessContext)
NAZARA_AUDIO_ALC_FUNCTION(alcSuspendContext) 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_FUNCTION
#undef NAZARA_AUDIO_AL_ALC_FUNCTION #undef NAZARA_AUDIO_AL_ALC_FUNCTION
#undef NAZARA_AUDIO_AL_EXT_FUNCTION #undef NAZARA_AUDIO_AL_EXT_FUNCTION
#undef NAZARA_AUDIO_ALC_FUNCTION
#undef NAZARA_AUDIO_AL_EXT_BEGIN #undef NAZARA_AUDIO_AL_EXT_BEGIN
#undef NAZARA_AUDIO_AL_EXT_END #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

View File

@ -23,7 +23,9 @@ namespace Nz
#include <Nazara/Audio/OpenALFunctions.hpp> #include <Nazara/Audio/OpenALFunctions.hpp>
}; };
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<typename FuncType, std::size_t FuncIndex, typename> template<typename FuncType, std::size_t FuncIndex, typename>
struct ALWrapper; struct ALWrapper;
@ -35,7 +37,7 @@ namespace Nz
{ {
return [](Args... args) -> Ret return [](Args... args) -> Ret
{ {
const OpenALDevice* device = s_currentALDevice; //< pay TLS cost once const OpenALDevice* device = OpenALDevice::GetCurrentDevice();
assert(device); assert(device);
FuncType funcPtr = reinterpret_cast<FuncType>(device->GetFunctionByIndex(FuncIndex)); FuncType funcPtr = reinterpret_cast<FuncType>(device->GetFunctionByIndex(FuncIndex));
@ -121,7 +123,7 @@ namespace Nz
if (m_library.alcMakeContextCurrent(m_context) != AL_TRUE) if (m_library.alcMakeContextCurrent(m_context) != AL_TRUE)
throw std::runtime_error("failed to activate OpenAL context"); throw std::runtime_error("failed to activate OpenAL context");
s_currentALDevice = this; s_currentGlobalALDevice = this;
SymbolLoader loader(*this); SymbolLoader loader(*this);
#ifdef NAZARA_DEBUG #ifdef NAZARA_DEBUG
@ -131,6 +133,7 @@ namespace Nz
#define NAZARA_AUDIO_AL_FUNCTION(name) loader.Load<decltype(&::name), UnderlyingCast(FunctionIndex:: name), false>(name, #name, library.name); #define NAZARA_AUDIO_AL_FUNCTION(name) loader.Load<decltype(&::name), UnderlyingCast(FunctionIndex:: name), false>(name, #name, library.name);
#define NAZARA_AUDIO_ALC_FUNCTION(name) loader.Load<decltype(&::name), UnderlyingCast(FunctionIndex:: name), true>(name, #name, library.name); #define NAZARA_AUDIO_ALC_FUNCTION(name) loader.Load<decltype(&::name), UnderlyingCast(FunctionIndex:: name), true>(name, #name, library.name);
#define NAZARA_AUDIO_AL_EXT_FUNCTION(name) loader.Load<decltype(&::name), UnderlyingCast(FunctionIndex:: name), false>(name, #name, nullptr); #define NAZARA_AUDIO_AL_EXT_FUNCTION(name) loader.Load<decltype(&::name), UnderlyingCast(FunctionIndex:: name), false>(name, #name, nullptr);
#define NAZARA_AUDIO_ALC_EXT_FUNCTION(name) loader.Load<decltype(&::name), UnderlyingCast(FunctionIndex:: name), true>(name, #name, nullptr);
#include <Nazara/Audio/OpenALFunctions.hpp> #include <Nazara/Audio/OpenALFunctions.hpp>
m_renderer = reinterpret_cast<const char*>(alGetString(AL_RENDERER)); m_renderer = reinterpret_cast<const char*>(alGetString(AL_RENDERER));
@ -157,6 +160,9 @@ namespace Nz
if (library.alIsExtensionPresent("AL_SOFT_source_latency")) if (library.alIsExtensionPresent("AL_SOFT_source_latency"))
m_extensionStatus[OpenALExtension::SourceLatency] = true; m_extensionStatus[OpenALExtension::SourceLatency] = true;
if (library.alIsExtensionPresent("ALC_EXT_thread_local_context"))
m_extensionStatus[OpenALExtension::ThreadLocalContext] = true;
SetListenerDirection(Vector3f::Forward()); SetListenerDirection(Vector3f::Forward());
} }
@ -164,20 +170,23 @@ namespace Nz
{ {
NAZARA_USE_ANONYMOUS_NAMESPACE NAZARA_USE_ANONYMOUS_NAMESPACE
MakeContextCurrent(); // alcMakeContextCurrent resets the thread context
alcMakeContextCurrent(m_context);
alcDestroyContext(m_context); alcDestroyContext(m_context);
alcCloseDevice(m_device); alcCloseDevice(m_device);
if (s_currentALDevice == this) if (s_currentThreadALDevice)
s_currentALDevice = nullptr; s_currentThreadALDevice = nullptr;
if (s_currentGlobalALDevice == this)
s_currentGlobalALDevice = nullptr;
} }
bool OpenALDevice::ClearErrorFlag() const bool OpenALDevice::ClearErrorFlag() const
{ {
NAZARA_USE_ANONYMOUS_NAMESPACE NAZARA_USE_ANONYMOUS_NAMESPACE
assert(s_currentALDevice == this); assert(GetCurrentDevice() == this);
alGetError(); alGetError();
return true; return true;
@ -322,10 +331,27 @@ namespace Nz
{ {
NAZARA_USE_ANONYMOUS_NAMESPACE NAZARA_USE_ANONYMOUS_NAMESPACE
if (s_currentALDevice != this) if (alcSetThreadContext)
{ {
m_library.alcMakeContextCurrent(m_context); if (s_currentThreadALDevice != this)
s_currentALDevice = 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 NAZARA_USE_ANONYMOUS_NAMESPACE
assert(s_currentALDevice == this); assert(GetCurrentDevice() == this);
bool hasAnyError = false; bool hasAnyError = false;
if (ALuint lastError = alGetError(); lastError != AL_NO_ERROR) if (ALuint lastError = alGetError(); lastError != AL_NO_ERROR)
@ -485,4 +511,13 @@ namespace Nz
alSpeedOfSound(speed); alSpeedOfSound(speed);
} }
const OpenALDevice* OpenALDevice::GetCurrentDevice()
{
const OpenALDevice* device = s_currentThreadALDevice;
if (device)
return device;
return s_currentGlobalALDevice;
}
} }