Audio: Fix loading of OpenAL extensions (pointers are context-local)

This commit is contained in:
SirLynix 2023-12-04 00:23:39 +01:00
parent 6059f608c0
commit f75a00efe2
12 changed files with 388 additions and 142 deletions

View File

@ -80,8 +80,6 @@ jobs:
- name: Run unit tests - name: Run unit tests
if: matrix.confs.mode != 'releasedbg' if: matrix.confs.mode != 'releasedbg'
run: xmake run UnitTests run: xmake run UnitTests
env:
NAZARA_NO_AUDIO: 1
# Setup installation configuration # Setup installation configuration
- name: Configure xmake for installation - name: Configure xmake for installation

View File

@ -22,7 +22,7 @@ namespace Nz
class NAZARA_AUDIO_API OpenALBuffer final : public AudioBuffer class NAZARA_AUDIO_API OpenALBuffer final : public AudioBuffer
{ {
public: public:
inline OpenALBuffer(std::shared_ptr<AudioDevice> device, OpenALLibrary& library, ALuint bufferId); inline OpenALBuffer(std::shared_ptr<AudioDevice> device, ALuint bufferId);
OpenALBuffer(const OpenALBuffer&) = delete; OpenALBuffer(const OpenALBuffer&) = delete;
OpenALBuffer(OpenALBuffer&&) = delete; OpenALBuffer(OpenALBuffer&&) = delete;
~OpenALBuffer(); ~OpenALBuffer();
@ -44,7 +44,6 @@ namespace Nz
const OpenALDevice& GetDevice() const; const OpenALDevice& GetDevice() const;
ALuint m_bufferId; ALuint m_bufferId;
OpenALLibrary& m_library;
}; };
} }

View File

@ -6,10 +6,9 @@
namespace Nz namespace Nz
{ {
inline OpenALBuffer::OpenALBuffer(std::shared_ptr<AudioDevice> device, OpenALLibrary& library, ALuint bufferId) : inline OpenALBuffer::OpenALBuffer(std::shared_ptr<AudioDevice> device, ALuint bufferId) :
AudioBuffer(std::move(device)), AudioBuffer(std::move(device)),
m_bufferId(bufferId), m_bufferId(bufferId)
m_library(library)
{ {
} }

View File

@ -31,9 +31,13 @@ namespace Nz
Max = SourceLatency Max = SourceLatency
}; };
using ALFunction = void(*)(void);
class NAZARA_AUDIO_API OpenALDevice : public AudioDevice class NAZARA_AUDIO_API OpenALDevice : public AudioDevice
{ {
friend OpenALLibrary; friend OpenALLibrary;
struct SymbolLoader;
friend SymbolLoader;
public: public:
OpenALDevice(OpenALLibrary& library, ALCdevice* device); OpenALDevice(OpenALLibrary& library, ALCdevice* device);
@ -41,11 +45,18 @@ namespace Nz
OpenALDevice(OpenALDevice&&) = delete; OpenALDevice(OpenALDevice&&) = delete;
~OpenALDevice(); ~OpenALDevice();
bool ClearErrorFlag() const;
std::shared_ptr<AudioBuffer> CreateBuffer() override; std::shared_ptr<AudioBuffer> CreateBuffer() override;
std::shared_ptr<AudioSource> CreateSource() override; std::shared_ptr<AudioSource> CreateSource() override;
inline bool DidLastCallSucceed() const;
float GetDopplerFactor() const override; float GetDopplerFactor() const override;
inline ALFunction GetFunctionByIndex(std::size_t funcIndex) const;
float GetGlobalVolume() const override; float GetGlobalVolume() const override;
inline OpenALLibrary& GetLibrary();
inline const OpenALLibrary& GetLibrary() const;
Vector3f GetListenerDirection(Vector3f* up = nullptr) const override; Vector3f GetListenerDirection(Vector3f* up = nullptr) const override;
Vector3f GetListenerPosition() const override; Vector3f GetListenerPosition() const override;
Quaternionf GetListenerRotation() const override; Quaternionf GetListenerRotation() const override;
@ -58,6 +69,9 @@ namespace Nz
void MakeContextCurrent() const; void MakeContextCurrent() const;
template<typename... Args> void PrintFunctionCall(std::size_t funcIndex, Args... args) const;
bool ProcessErrorFlag() const;
void SetDopplerFactor(float dopplerFactor) override; void SetDopplerFactor(float dopplerFactor) override;
void SetGlobalVolume(float volume) override; void SetGlobalVolume(float volume) override;
void SetListenerDirection(const Vector3f& direction, const Vector3f& up = Vector3f::Up()) override; void SetListenerDirection(const Vector3f& direction, const Vector3f& up = Vector3f::Up()) override;
@ -70,14 +84,30 @@ namespace Nz
OpenALDevice& operator=(const OpenALDevice&) = delete; OpenALDevice& operator=(const OpenALDevice&) = delete;
OpenALDevice& operator=(OpenALDevice&&) = delete; OpenALDevice& operator=(OpenALDevice&&) = delete;
// 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;
#include <Nazara/Audio/OpenALFunctions.hpp>
private: private:
EnumArray<AudioFormat, ALenum> m_audioFormatValues; enum class FunctionIndex
EnumArray<OpenALExtension, ALenum> m_extensionStatus; {
#define NAZARA_AUDIO_AL_ALC_FUNCTION(name) name,
#include <Nazara/Audio/OpenALFunctions.hpp>
Count
};
std::array<ALFunction, UnderlyingCast(FunctionIndex::Count)> m_originalFunctionPointer;
std::string m_renderer; std::string m_renderer;
std::string m_vendor; std::string m_vendor;
EnumArray<AudioFormat, ALenum> m_audioFormatValues;
EnumArray<OpenALExtension, ALenum> m_extensionStatus;
OpenALLibrary& m_library; OpenALLibrary& m_library;
MovablePtr<ALCcontext> m_context; MovablePtr<ALCcontext> m_context;
MovablePtr<ALCdevice> m_device; MovablePtr<ALCdevice> m_device;
mutable bool m_didCollectErrors;
mutable bool m_hadAnyError;
}; };
} }

View File

@ -7,6 +7,30 @@
namespace Nz namespace Nz
{ {
inline bool OpenALDevice::DidLastCallSucceed() const
{
if (!m_didCollectErrors)
ProcessErrorFlag();
return !m_hadAnyError;
}
inline ALFunction OpenALDevice::GetFunctionByIndex(std::size_t funcIndex) const
{
assert(funcIndex < m_originalFunctionPointer.size());
return m_originalFunctionPointer[funcIndex];
}
inline OpenALLibrary& OpenALDevice::GetLibrary()
{
return m_library;
}
inline const OpenALLibrary& OpenALDevice::GetLibrary() const
{
return m_library;
}
inline bool OpenALDevice::IsExtensionSupported(OpenALExtension extension) const inline bool OpenALDevice::IsExtensionSupported(OpenALExtension extension) const
{ {
return m_extensionStatus[extension]; return m_extensionStatus[extension];

View File

@ -44,6 +44,7 @@ namespace Nz
OpenALLibrary& operator=(OpenALLibrary&&) = delete; OpenALLibrary& operator=(OpenALLibrary&&) = delete;
#define NAZARA_AUDIO_AL_ALC_FUNCTION(name) decltype(&::name) name; #define NAZARA_AUDIO_AL_ALC_FUNCTION(name) decltype(&::name) name;
#define NAZARA_AUDIO_AL_EXT_FUNCTION(name)
#include <Nazara/Audio/OpenALFunctions.hpp> #include <Nazara/Audio/OpenALFunctions.hpp>
private: private:

View File

@ -23,7 +23,7 @@ namespace Nz
class NAZARA_AUDIO_API OpenALSource final : public AudioSource class NAZARA_AUDIO_API OpenALSource final : public AudioSource
{ {
public: public:
inline OpenALSource(std::shared_ptr<AudioDevice> device, OpenALLibrary& library, ALuint sourceId); inline OpenALSource(std::shared_ptr<AudioDevice> device, ALuint sourceId);
OpenALSource(const OpenALSource&) = delete; OpenALSource(const OpenALSource&) = delete;
OpenALSource(OpenALSource&&) = delete; OpenALSource(OpenALSource&&) = delete;
~OpenALSource(); ~OpenALSource();
@ -76,7 +76,6 @@ namespace Nz
std::shared_ptr<OpenALBuffer> m_currentBuffer; std::shared_ptr<OpenALBuffer> m_currentBuffer;
std::vector<std::shared_ptr<OpenALBuffer>> m_queuedBuffers; std::vector<std::shared_ptr<OpenALBuffer>> m_queuedBuffers;
ALuint m_sourceId; ALuint m_sourceId;
OpenALLibrary& m_library;
}; };
} }

View File

@ -6,10 +6,9 @@
namespace Nz namespace Nz
{ {
inline OpenALSource::OpenALSource(std::shared_ptr<AudioDevice> device, OpenALLibrary& library, ALuint sourceId) : inline OpenALSource::OpenALSource(std::shared_ptr<AudioDevice> device, ALuint sourceId) :
AudioSource(std::move(device)), AudioSource(std::move(device)),
m_sourceId(sourceId), m_sourceId(sourceId)
m_library(library)
{ {
} }
} }

View File

@ -12,18 +12,20 @@ namespace Nz
{ {
OpenALBuffer::~OpenALBuffer() OpenALBuffer::~OpenALBuffer()
{ {
GetDevice().MakeContextCurrent(); OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
m_library.alDeleteBuffers(1, &m_bufferId); device.alDeleteBuffers(1, &m_bufferId);
} }
UInt64 OpenALBuffer::GetSampleCount() const UInt64 OpenALBuffer::GetSampleCount() const
{ {
GetDevice().MakeContextCurrent(); const OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
ALint bits, size; ALint bits, size;
m_library.alGetBufferi(m_bufferId, AL_BITS, &bits); device.alGetBufferi(m_bufferId, AL_BITS, &bits);
m_library.alGetBufferi(m_bufferId, AL_SIZE, &size); device.alGetBufferi(m_bufferId, AL_SIZE, &size);
UInt64 sampleCount = 0; UInt64 sampleCount = 0;
if (bits != 0) if (bits != 0)
@ -34,20 +36,22 @@ namespace Nz
UInt64 OpenALBuffer::GetSize() const UInt64 OpenALBuffer::GetSize() const
{ {
GetDevice().MakeContextCurrent(); const OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
ALint size; ALint size;
m_library.alGetBufferi(m_bufferId, AL_SIZE, &size); device.alGetBufferi(m_bufferId, AL_SIZE, &size);
return SafeCast<UInt64>(size); return SafeCast<UInt64>(size);
} }
UInt32 OpenALBuffer::GetSampleRate() const UInt32 OpenALBuffer::GetSampleRate() const
{ {
GetDevice().MakeContextCurrent(); const OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
ALint sampleRate; ALint sampleRate;
m_library.alGetBufferi(m_bufferId, AL_FREQUENCY, &sampleRate); device.alGetBufferi(m_bufferId, AL_FREQUENCY, &sampleRate);
return SafeCast<UInt32>(sampleRate); return SafeCast<UInt32>(sampleRate);
} }
@ -55,7 +59,7 @@ namespace Nz
bool OpenALBuffer::IsCompatibleWith(const AudioDevice& device) const bool OpenALBuffer::IsCompatibleWith(const AudioDevice& device) const
{ {
// OpenAL buffers are shared among contexts and thus devices // OpenAL buffers are shared among contexts and thus devices
return device.GetSubSystemIdentifier() == &m_library; return device.GetSubSystemIdentifier() == &GetDevice().GetLibrary();
} }
bool OpenALBuffer::Reset(AudioFormat format, UInt64 sampleCount, UInt32 sampleRate, const void* samples) bool OpenALBuffer::Reset(AudioFormat format, UInt64 sampleCount, UInt32 sampleRate, const void* samples)
@ -72,11 +76,11 @@ namespace Nz
device.MakeContextCurrent(); device.MakeContextCurrent();
// We empty the error stack // We empty the error stack
while (m_library.alGetError() != AL_NO_ERROR); while (device.alGetError() != AL_NO_ERROR);
m_library.alBufferData(m_bufferId, alFormat, samples, SafeCast<ALsizei>(sampleCount * sizeof(Int16)), SafeCast<ALsizei>(sampleRate)); device.alBufferData(m_bufferId, alFormat, samples, SafeCast<ALsizei>(sampleCount * sizeof(Int16)), SafeCast<ALsizei>(sampleRate));
if (ALenum lastError = m_library.alGetError(); lastError != AL_NO_ERROR) if (ALenum lastError = device.alGetError(); lastError != AL_NO_ERROR)
{ {
NazaraErrorFmt("failed to reset OpenAL buffer: {0}", std::to_string(lastError)); NazaraErrorFmt("failed to reset OpenAL buffer: {0}", std::to_string(lastError));
return false; return false;

View File

@ -7,29 +7,134 @@
#include <Nazara/Audio/OpenALLibrary.hpp> #include <Nazara/Audio/OpenALLibrary.hpp>
#include <Nazara/Audio/OpenALSource.hpp> #include <Nazara/Audio/OpenALSource.hpp>
#include <Nazara/Audio/OpenALUtils.hpp> #include <Nazara/Audio/OpenALUtils.hpp>
#include <Nazara/Core/Log.hpp>
#include <NazaraUtils/Algorithm.hpp>
#include <array>
#include <cstring> #include <cstring>
#include <stdexcept> #include <stdexcept>
#include <Nazara/Audio/Debug.hpp> #include <Nazara/Audio/Debug.hpp>
namespace Nz namespace Nz
{ {
namespace namespace NAZARA_ANONYMOUS_NAMESPACE
{ {
thread_local ALCcontext* s_currentContext; constexpr std::array s_functionNames = {
#define NAZARA_AUDIO_AL_ALC_FUNCTION(name) #name,
#include <Nazara/Audio/OpenALFunctions.hpp>
};
thread_local const OpenALDevice* s_currentALDevice;
template<typename FuncType, std::size_t FuncIndex, typename>
struct ALWrapper;
template<typename FuncType, std::size_t FuncIndex, typename Ret, typename... Args>
struct ALWrapper<FuncType, FuncIndex, Ret(AL_APIENTRY*)(Args...)>
{
static auto WrapErrorHandling()
{
return [](Args... args) -> Ret
{
const OpenALDevice* device = s_currentALDevice; //< pay TLS cost once
assert(device);
FuncType funcPtr = reinterpret_cast<FuncType>(device->GetFunctionByIndex(FuncIndex));
if constexpr (std::is_same_v<Ret, void>)
{
funcPtr(args...);
if (device->ProcessErrorFlag())
device->PrintFunctionCall(FuncIndex, args...);
}
else
{
Ret r = funcPtr(args...);
if (device->ProcessErrorFlag())
device->PrintFunctionCall(FuncIndex, args...);
return r;
}
};
}
};
} }
struct OpenALDevice::SymbolLoader
{
SymbolLoader(OpenALDevice& parent) :
device(parent)
{
}
template<typename FuncType, std::size_t FuncIndex, bool ContextFunction, typename Func>
bool Load(Func& func, const char* funcName, FuncType libraryPtr)
{
NAZARA_USE_ANONYMOUS_NAMESPACE
ALFunction originalFuncPtr;
if constexpr (ContextFunction)
originalFuncPtr = BitCast<ALFunction>(device.m_library.alcGetProcAddress(device.m_device, funcName));
else
originalFuncPtr = BitCast<ALFunction>(device.m_library.alGetProcAddress(funcName));
// Fallback in case of faulty OpenAL implementations not returning core functions through alGetProcAddress/alcGetProcAddress
if (!originalFuncPtr)
originalFuncPtr = reinterpret_cast<ALFunction>(libraryPtr);
func = reinterpret_cast<FuncType>(originalFuncPtr);
if (func && wrapErrorHandling)
{
if constexpr (
FuncIndex != UnderlyingCast(FunctionIndex::alGetError) && //< Prevent infinite recursion
FuncIndex != UnderlyingCast(FunctionIndex::alcCloseDevice) && //< alcDestroyContext is called with no context
FuncIndex != UnderlyingCast(FunctionIndex::alcDestroyContext)) //< alcDestroyContext is called with no context
{
using Wrapper = ALWrapper<FuncType, FuncIndex, FuncType>;
func = Wrapper::WrapErrorHandling();
}
}
device.m_originalFunctionPointer[FuncIndex] = originalFuncPtr;
return func != nullptr;
}
OpenALDevice& device;
bool wrapErrorHandling = false;
};
OpenALDevice::OpenALDevice(OpenALLibrary& library, ALCdevice* device) : OpenALDevice::OpenALDevice(OpenALLibrary& library, ALCdevice* device) :
m_library(library), m_library(library),
m_device(device) m_device(device)
{ {
NAZARA_USE_ANONYMOUS_NAMESPACE
m_context = m_library.alcCreateContext(device, nullptr); m_context = m_library.alcCreateContext(device, nullptr);
if (!m_context) if (!m_context)
throw std::runtime_error("failed to create OpenAL context"); throw std::runtime_error("failed to create OpenAL context");
MakeContextCurrent(); // Don't use MakeContextCurrent as device pointers are not loaded yet
if (m_library.alcMakeContextCurrent(m_context) != AL_TRUE)
throw std::runtime_error("failed to activate OpenAL context");
m_renderer = reinterpret_cast<const char*>(m_library.alGetString(AL_RENDERER)); s_currentALDevice = this;
m_vendor = reinterpret_cast<const char*>(m_library.alGetString(AL_VENDOR));
SymbolLoader loader(*this);
#ifdef NAZARA_DEBUG
loader.wrapErrorHandling = true;
#endif
#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_AL_EXT_FUNCTION(name) loader.Load<decltype(&::name), UnderlyingCast(FunctionIndex:: name), false>(name, #name, nullptr);
#include <Nazara/Audio/OpenALFunctions.hpp>
m_renderer = reinterpret_cast<const char*>(alGetString(AL_RENDERER));
m_vendor = reinterpret_cast<const char*>(alGetString(AL_VENDOR));
// We complete the formats table // We complete the formats table
m_audioFormatValues.fill(0); m_audioFormatValues.fill(0);
@ -40,13 +145,13 @@ namespace Nz
// "The presence of an enum value does not guarantee the applicability of an extension to the current context." // "The presence of an enum value does not guarantee the applicability of an extension to the current context."
if (library.alIsExtensionPresent("AL_EXT_MCFORMATS")) if (library.alIsExtensionPresent("AL_EXT_MCFORMATS"))
{ {
m_audioFormatValues[AudioFormat::I16_Quad] = m_library.alGetEnumValue("AL_FORMAT_QUAD16"); m_audioFormatValues[AudioFormat::I16_Quad] = alGetEnumValue("AL_FORMAT_QUAD16");
m_audioFormatValues[AudioFormat::I16_5_1] = m_library.alGetEnumValue("AL_FORMAT_51CHN16"); m_audioFormatValues[AudioFormat::I16_5_1] = alGetEnumValue("AL_FORMAT_51CHN16");
m_audioFormatValues[AudioFormat::I16_6_1] = m_library.alGetEnumValue("AL_FORMAT_61CHN16"); m_audioFormatValues[AudioFormat::I16_6_1] = alGetEnumValue("AL_FORMAT_61CHN16");
m_audioFormatValues[AudioFormat::I16_7_1] = m_library.alGetEnumValue("AL_FORMAT_71CHN16"); m_audioFormatValues[AudioFormat::I16_7_1] = alGetEnumValue("AL_FORMAT_71CHN16");
} }
else if (library.alIsExtensionPresent("AL_LOKI_quadriphonic")) else if (library.alIsExtensionPresent("AL_LOKI_quadriphonic"))
m_audioFormatValues[AudioFormat::I16_Quad] = m_library.alGetEnumValue("AL_FORMAT_QUAD16_LOKI"); m_audioFormatValues[AudioFormat::I16_Quad] = alGetEnumValue("AL_FORMAT_QUAD16_LOKI");
m_extensionStatus.fill(false); m_extensionStatus.fill(false);
if (library.alIsExtensionPresent("AL_SOFT_source_latency")) if (library.alIsExtensionPresent("AL_SOFT_source_latency"))
@ -57,49 +162,65 @@ namespace Nz
OpenALDevice::~OpenALDevice() OpenALDevice::~OpenALDevice()
{ {
NAZARA_USE_ANONYMOUS_NAMESPACE
MakeContextCurrent(); MakeContextCurrent();
m_library.alcDestroyContext(m_context); alcDestroyContext(m_context);
m_library.alcCloseDevice(m_device); alcCloseDevice(m_device);
if (s_currentContext == m_context) if (s_currentALDevice == this)
s_currentContext = nullptr; s_currentALDevice = nullptr;
}
bool OpenALDevice::ClearErrorFlag() const
{
NAZARA_USE_ANONYMOUS_NAMESPACE
assert(s_currentALDevice == this);
alGetError();
m_didCollectErrors = false;
m_hadAnyError = false;
return true;
} }
std::shared_ptr<AudioBuffer> OpenALDevice::CreateBuffer() std::shared_ptr<AudioBuffer> OpenALDevice::CreateBuffer()
{ {
MakeContextCurrent(); MakeContextCurrent();
m_library.alGetError(); // Clear error flags ClearErrorFlag();
ALuint bufferId = 0; ALuint bufferId = 0;
m_library.alGenBuffers(1, &bufferId); alGenBuffers(1, &bufferId);
if (ALenum lastError = m_library.alGetError(); lastError != AL_NO_ERROR) if (!DidLastCallSucceed())
{ {
NazaraErrorFmt("failed to create OpenAL buffer: {0}", TranslateOpenALError(lastError)); NazaraError("failed to create OpenAL buffer");
return {}; return {};
} }
return std::make_shared<OpenALBuffer>(shared_from_this(), m_library, bufferId); return std::make_shared<OpenALBuffer>(shared_from_this(), bufferId);
} }
std::shared_ptr<AudioSource> OpenALDevice::CreateSource() std::shared_ptr<AudioSource> OpenALDevice::CreateSource()
{ {
MakeContextCurrent(); MakeContextCurrent();
m_library.alGetError(); // Clear error flags ClearErrorFlag();
ALuint sourceId = 0; ALuint sourceId = 0;
m_library.alGenSources(1, &sourceId); alGenSources(1, &sourceId);
if (ALenum lastError = m_library.alGetError(); lastError != AL_NO_ERROR) if (!DidLastCallSucceed())
{ {
NazaraErrorFmt("failed to create OpenAL source: {0}", TranslateOpenALError(lastError)); NazaraError("failed to create OpenAL buffer");
return {}; return {};
} }
return std::make_shared<OpenALSource>(shared_from_this(), m_library, sourceId); return std::make_shared<OpenALSource>(shared_from_this(), sourceId);
} }
/*! /*!
@ -110,7 +231,7 @@ namespace Nz
{ {
MakeContextCurrent(); MakeContextCurrent();
return m_library.alGetFloat(AL_DOPPLER_FACTOR); return alGetFloat(AL_DOPPLER_FACTOR);
} }
/*! /*!
@ -122,7 +243,7 @@ namespace Nz
MakeContextCurrent(); MakeContextCurrent();
ALfloat gain = 0.f; ALfloat gain = 0.f;
m_library.alGetListenerf(AL_GAIN, &gain); alGetListenerf(AL_GAIN, &gain);
return gain; return gain;
} }
@ -140,7 +261,7 @@ namespace Nz
MakeContextCurrent(); MakeContextCurrent();
ALfloat orientation[6]; ALfloat orientation[6];
m_library.alGetListenerfv(AL_ORIENTATION, orientation); alGetListenerfv(AL_ORIENTATION, orientation);
if (up) if (up)
(*up) = Vector3f(orientation[3], orientation[4], orientation[5]); (*up) = Vector3f(orientation[3], orientation[4], orientation[5]);
@ -159,7 +280,7 @@ namespace Nz
MakeContextCurrent(); MakeContextCurrent();
Vector3f position; Vector3f position;
m_library.alGetListenerfv(AL_POSITION, &position.x); alGetListenerfv(AL_POSITION, &position.x);
return position; return position;
} }
@ -177,7 +298,7 @@ namespace Nz
MakeContextCurrent(); MakeContextCurrent();
ALfloat orientation[6]; ALfloat orientation[6];
m_library.alGetListenerfv(AL_ORIENTATION, orientation); alGetListenerfv(AL_ORIENTATION, orientation);
Vector3f forward(orientation[0], orientation[1], orientation[2]); Vector3f forward(orientation[0], orientation[1], orientation[2]);
Vector3f up(orientation[3], orientation[4], orientation[5]); Vector3f up(orientation[3], orientation[4], orientation[5]);
@ -196,20 +317,68 @@ namespace Nz
MakeContextCurrent(); MakeContextCurrent();
Vector3f velocity; Vector3f velocity;
m_library.alGetListenerfv(AL_VELOCITY, &velocity.x); alGetListenerfv(AL_VELOCITY, &velocity.x);
return velocity; return velocity;
} }
void OpenALDevice::MakeContextCurrent() const void OpenALDevice::MakeContextCurrent() const
{ {
if (s_currentContext != m_context) NAZARA_USE_ANONYMOUS_NAMESPACE
if (s_currentALDevice != this)
{ {
m_library.alcMakeContextCurrent(m_context); m_library.alcMakeContextCurrent(m_context);
s_currentContext = m_context; s_currentALDevice = this;
} }
} }
template<typename... Args>
void OpenALDevice::PrintFunctionCall(std::size_t funcIndex, Args... args) const
{
NAZARA_USE_ANONYMOUS_NAMESPACE
std::stringstream ss;
ss << s_functionNames[funcIndex] << "(";
if constexpr (sizeof...(args) > 0)
{
bool first = true;
auto PrintParam = [&](auto value)
{
if (!first)
ss << ", ";
ss << +value;
first = false;
};
(PrintParam(args), ...);
}
ss << ")";
NazaraDebug(ss.str());
}
bool OpenALDevice::ProcessErrorFlag() const
{
NAZARA_USE_ANONYMOUS_NAMESPACE
assert(s_currentALDevice == this);
bool hasAnyError = false;
if (ALuint lastError = alGetError(); lastError != AL_NO_ERROR)
{
hasAnyError = true;
NazaraErrorFmt("OpenAL error: {0}", TranslateOpenALError(lastError));
}
m_didCollectErrors = true;
m_hadAnyError = hasAnyError;
return hasAnyError;
}
/*! /*!
* \brief Gets the speed of sound * \brief Gets the speed of sound
* \return Speed of sound * \return Speed of sound
@ -218,7 +387,7 @@ namespace Nz
{ {
MakeContextCurrent(); MakeContextCurrent();
return m_library.alGetFloat(AL_SPEED_OF_SOUND); return alGetFloat(AL_SPEED_OF_SOUND);
} }
const void* OpenALDevice::GetSubSystemIdentifier() const const void* OpenALDevice::GetSubSystemIdentifier() const
@ -249,7 +418,7 @@ namespace Nz
{ {
MakeContextCurrent(); MakeContextCurrent();
m_library.alDopplerFactor(dopplerFactor); alDopplerFactor(dopplerFactor);
} }
/*! /*!
@ -261,7 +430,7 @@ namespace Nz
{ {
MakeContextCurrent(); MakeContextCurrent();
m_library.alListenerf(AL_GAIN, volume); alListenerf(AL_GAIN, volume);
} }
/*! /*!
@ -282,7 +451,7 @@ namespace Nz
up.x, up.y, up.z up.x, up.y, up.z
}; };
m_library.alListenerfv(AL_ORIENTATION, orientation); alListenerfv(AL_ORIENTATION, orientation);
} }
/*! /*!
@ -296,7 +465,7 @@ namespace Nz
{ {
MakeContextCurrent(); MakeContextCurrent();
m_library.alListenerfv(AL_POSITION, &position.x); alListenerfv(AL_POSITION, &position.x);
} }
/*! /*!
@ -310,7 +479,7 @@ namespace Nz
{ {
MakeContextCurrent(); MakeContextCurrent();
m_library.alListenerfv(AL_VELOCITY, &velocity.x); alListenerfv(AL_VELOCITY, &velocity.x);
} }
/*! /*!
@ -322,6 +491,6 @@ namespace Nz
{ {
MakeContextCurrent(); MakeContextCurrent();
m_library.alSpeedOfSound(speed); alSpeedOfSound(speed);
} }
} }

View File

@ -23,13 +23,6 @@ namespace Nz
auto PostLoad = [&] auto PostLoad = [&]
{ {
// Load ext
#define NAZARA_AUDIO_AL_ALC_FUNCTION(name)
#define NAZARA_AUDIO_AL_EXT_BEGIN(ext) if (alIsExtensionPresent(#ext)) {
#define NAZARA_AUDIO_AL_EXT_END() }
#define NAZARA_AUDIO_AL_EXT_FUNCTION(name) name = reinterpret_cast<decltype(&::name)>(alGetProcAddress(#name));
#include <Nazara/Audio/OpenALFunctions.hpp>
m_hasCaptureSupport = alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"); m_hasCaptureSupport = alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE");
m_isLoaded = true; m_isLoaded = true;
@ -79,8 +72,6 @@ namespace Nz
try try
{ {
#define NAZARA_AUDIO_AL_ALC_FUNCTION(name) name = reinterpret_cast<decltype(&::name)>(LoadSymbol(#name, false)); #define NAZARA_AUDIO_AL_ALC_FUNCTION(name) name = reinterpret_cast<decltype(&::name)>(LoadSymbol(#name, false));
#define NAZARA_AUDIO_AL_EXT_BEGIN(name)
#define NAZARA_AUDIO_AL_EXT_END(name)
#define NAZARA_AUDIO_AL_EXT_FUNCTION(name) #define NAZARA_AUDIO_AL_EXT_FUNCTION(name)
#include <Nazara/Audio/OpenALFunctions.hpp> #include <Nazara/Audio/OpenALFunctions.hpp>
} }
@ -104,8 +95,6 @@ namespace Nz
// Load core // Load core
#define NAZARA_AUDIO_AL_ALC_FUNCTION(name) name = &::name; #define NAZARA_AUDIO_AL_ALC_FUNCTION(name) name = &::name;
#define NAZARA_AUDIO_AL_EXT_BEGIN(name)
#define NAZARA_AUDIO_AL_EXT_END(name)
#define NAZARA_AUDIO_AL_EXT_FUNCTION(name) #define NAZARA_AUDIO_AL_EXT_FUNCTION(name)
#include <Nazara/Audio/OpenALFunctions.hpp> #include <Nazara/Audio/OpenALFunctions.hpp>
@ -142,6 +131,7 @@ namespace Nz
return; return;
#define NAZARA_AUDIO_AL_ALC_FUNCTION(name) name = nullptr; #define NAZARA_AUDIO_AL_ALC_FUNCTION(name) name = nullptr;
#define NAZARA_AUDIO_AL_EXT_FUNCTION(name)
#include <Nazara/Audio/OpenALFunctions.hpp> #include <Nazara/Audio/OpenALFunctions.hpp>
m_library.Unload(); m_library.Unload();

View File

@ -15,63 +15,72 @@ namespace Nz
{ {
OpenALSource::~OpenALSource() OpenALSource::~OpenALSource()
{ {
GetDevice().MakeContextCurrent(); OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
m_library.alDeleteSources(1, &m_sourceId); device.alDeleteSources(1, &m_sourceId);
} }
void OpenALSource::EnableLooping(bool loop) void OpenALSource::EnableLooping(bool loop)
{ {
GetDevice().MakeContextCurrent(); OpenALDevice& device = GetDevice();
m_library.alSourcei(m_sourceId, AL_LOOPING, loop); device.MakeContextCurrent();
device.alSourcei(m_sourceId, AL_LOOPING, loop);
} }
void OpenALSource::EnableSpatialization(bool spatialization) void OpenALSource::EnableSpatialization(bool spatialization)
{ {
GetDevice().MakeContextCurrent(); OpenALDevice& device = GetDevice();
m_library.alSourcei(m_sourceId, AL_SOURCE_RELATIVE, !spatialization); device.MakeContextCurrent();
device.alSourcei(m_sourceId, AL_SOURCE_RELATIVE, !spatialization);
} }
float OpenALSource::GetAttenuation() const float OpenALSource::GetAttenuation() const
{ {
GetDevice().MakeContextCurrent(); const OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
ALfloat attenuation; ALfloat attenuation;
m_library.alGetSourcefv(m_sourceId, AL_ROLLOFF_FACTOR, &attenuation); device.alGetSourcefv(m_sourceId, AL_ROLLOFF_FACTOR, &attenuation);
return attenuation; return attenuation;
} }
float OpenALSource::GetMinDistance() const float OpenALSource::GetMinDistance() const
{ {
GetDevice().MakeContextCurrent(); const OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
ALfloat minDistance; ALfloat minDistance;
m_library.alGetSourcefv(m_sourceId, AL_REFERENCE_DISTANCE, &minDistance); device.alGetSourcefv(m_sourceId, AL_REFERENCE_DISTANCE, &minDistance);
return minDistance; return minDistance;
} }
float OpenALSource::GetPitch() const float OpenALSource::GetPitch() const
{ {
GetDevice().MakeContextCurrent(); const OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
ALfloat pitch; ALfloat pitch;
m_library.alGetSourcefv(m_sourceId, AL_PITCH, &pitch); device.alGetSourcefv(m_sourceId, AL_PITCH, &pitch);
return pitch; return pitch;
} }
Time OpenALSource::GetPlayingOffset() const Time OpenALSource::GetPlayingOffset() const
{ {
GetDevice().MakeContextCurrent(); const OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
#ifdef AL_SOFT_source_latency #ifdef AL_SOFT_source_latency
if (GetDevice().IsExtensionSupported(OpenALExtension::SourceLatency)) if (GetDevice().IsExtensionSupported(OpenALExtension::SourceLatency))
{ {
// alGetSourcedvSOFT has extra precision thanks to double // alGetSourcedvSOFT has extra precision thanks to double
ALdouble playingOffset; ALdouble playingOffset;
m_library.alGetSourcedvSOFT(m_sourceId, AL_SEC_OFFSET, &playingOffset); device.alGetSourcedvSOFT(m_sourceId, AL_SEC_OFFSET, &playingOffset);
return Time::Seconds(playingOffset); return Time::Seconds(playingOffset);
} }
@ -79,7 +88,7 @@ namespace Nz
#endif #endif
{ {
ALfloat playingOffset; ALfloat playingOffset;
m_library.alGetSourcefv(m_sourceId, AL_SEC_OFFSET, &playingOffset); device.alGetSourcefv(m_sourceId, AL_SEC_OFFSET, &playingOffset);
return Time::Seconds(playingOffset); return Time::Seconds(playingOffset);
} }
@ -87,20 +96,23 @@ namespace Nz
Vector3f OpenALSource::GetPosition() const Vector3f OpenALSource::GetPosition() const
{ {
GetDevice().MakeContextCurrent(); const OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
Vector3f position; Vector3f position;
m_library.alGetSourcefv(m_sourceId, AL_POSITION, &position.x); device.alGetSourcefv(m_sourceId, AL_POSITION, &position.x);
return position; return position;
} }
UInt32 OpenALSource::GetSampleOffset() const UInt32 OpenALSource::GetSampleOffset() const
{ {
GetDevice().MakeContextCurrent(); const OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
ALint samples = 0; ALint samples = 0;
m_library.alGetSourcei(m_sourceId, AL_SAMPLE_OFFSET, &samples); device.alGetSourcei(m_sourceId, AL_SAMPLE_OFFSET, &samples);
return SafeCast<UInt32>(samples); return SafeCast<UInt32>(samples);
} }
@ -111,10 +123,11 @@ namespace Nz
#ifdef AL_SOFT_source_latency #ifdef AL_SOFT_source_latency
if (GetDevice().IsExtensionSupported(OpenALExtension::SourceLatency)) if (GetDevice().IsExtensionSupported(OpenALExtension::SourceLatency))
{ {
GetDevice().MakeContextCurrent(); const OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
std::array<ALint64SOFT, 2> values; std::array<ALint64SOFT, 2> values;
m_library.alGetSourcei64vSOFT(m_sourceId, AL_SAMPLE_OFFSET_LATENCY_SOFT, values.data()); device.alGetSourcei64vSOFT(m_sourceId, AL_SAMPLE_OFFSET_LATENCY_SOFT, values.data());
offsetWithLatency.sampleOffset = ((values[0] & 0xFFFFFFFF00000000) >> 32) * 1'000; offsetWithLatency.sampleOffset = ((values[0] & 0xFFFFFFFF00000000) >> 32) * 1'000;
offsetWithLatency.sourceLatency = Time::Nanoseconds(values[1] / 1'000); offsetWithLatency.sourceLatency = Time::Nanoseconds(values[1] / 1'000);
@ -132,20 +145,22 @@ namespace Nz
Vector3f OpenALSource::GetVelocity() const Vector3f OpenALSource::GetVelocity() const
{ {
GetDevice().MakeContextCurrent(); const OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
Vector3f velocity; Vector3f velocity;
m_library.alGetSourcefv(m_sourceId, AL_VELOCITY, &velocity.x); device.alGetSourcefv(m_sourceId, AL_VELOCITY, &velocity.x);
return velocity; return velocity;
} }
SoundStatus OpenALSource::GetStatus() const SoundStatus OpenALSource::GetStatus() const
{ {
GetDevice().MakeContextCurrent(); const OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
ALint state; ALint state;
m_library.alGetSourcei(m_sourceId, AL_SOURCE_STATE, &state); device.alGetSourcei(m_sourceId, AL_SOURCE_STATE, &state);
switch (state) switch (state)
{ {
@ -168,30 +183,33 @@ namespace Nz
float OpenALSource::GetVolume() const float OpenALSource::GetVolume() const
{ {
GetDevice().MakeContextCurrent(); const OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
ALfloat volume; ALfloat volume;
m_library.alGetSourcefv(m_sourceId, AL_GAIN, &volume); device.alGetSourcefv(m_sourceId, AL_GAIN, &volume);
return volume; return volume;
} }
bool OpenALSource::IsLooping() const bool OpenALSource::IsLooping() const
{ {
GetDevice().MakeContextCurrent(); const OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
ALint looping; ALint looping;
m_library.alGetSourcei(m_sourceId, AL_LOOPING, &looping); device.alGetSourcei(m_sourceId, AL_LOOPING, &looping);
return looping == AL_TRUE; return looping == AL_TRUE;
} }
bool OpenALSource::IsSpatializationEnabled() const bool OpenALSource::IsSpatializationEnabled() const
{ {
GetDevice().MakeContextCurrent(); const OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
ALint relative; ALint relative;
m_library.alGetSourcei(m_sourceId, AL_SOURCE_RELATIVE, &relative); device.alGetSourcei(m_sourceId, AL_SOURCE_RELATIVE, &relative);
return relative == AL_FALSE; return relative == AL_FALSE;
} }
@ -203,33 +221,38 @@ namespace Nz
std::shared_ptr<OpenALBuffer> newBuffer = std::static_pointer_cast<OpenALBuffer>(std::move(audioBuffer)); std::shared_ptr<OpenALBuffer> newBuffer = std::static_pointer_cast<OpenALBuffer>(std::move(audioBuffer));
GetDevice().MakeContextCurrent(); OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
ALuint bufferId = newBuffer->GetBufferId(); ALuint bufferId = newBuffer->GetBufferId();
m_library.alSourceQueueBuffers(m_sourceId, 1, &bufferId); device.alSourceQueueBuffers(m_sourceId, 1, &bufferId);
m_queuedBuffers.emplace_back(std::move(newBuffer)); m_queuedBuffers.emplace_back(std::move(newBuffer));
} }
void OpenALSource::Pause() void OpenALSource::Pause()
{ {
GetDevice().MakeContextCurrent(); OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
m_library.alSourcePause(m_sourceId); device.alSourcePause(m_sourceId);
} }
void OpenALSource::Play() void OpenALSource::Play()
{ {
GetDevice().MakeContextCurrent(); OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
m_library.alSourcePlay(m_sourceId); device.alSourcePlay(m_sourceId);
} }
void OpenALSource::SetAttenuation(float attenuation) void OpenALSource::SetAttenuation(float attenuation)
{ {
GetDevice().MakeContextCurrent(); OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
m_library.alSourcef(m_sourceId, AL_ROLLOFF_FACTOR, attenuation); device.alSourcef(m_sourceId, AL_ROLLOFF_FACTOR, attenuation);
} }
void OpenALSource::SetBuffer(std::shared_ptr<AudioBuffer> audioBuffer) void OpenALSource::SetBuffer(std::shared_ptr<AudioBuffer> audioBuffer)
@ -238,90 +261,100 @@ namespace Nz
std::shared_ptr<OpenALBuffer> newBuffer = std::static_pointer_cast<OpenALBuffer>(std::move(audioBuffer)); std::shared_ptr<OpenALBuffer> newBuffer = std::static_pointer_cast<OpenALBuffer>(std::move(audioBuffer));
GetDevice().MakeContextCurrent(); OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
if (newBuffer) if (newBuffer)
m_library.alSourcei(m_sourceId, AL_BUFFER, newBuffer->GetBufferId()); device.alSourcei(m_sourceId, AL_BUFFER, newBuffer->GetBufferId());
else else
m_library.alSourcei(m_sourceId, AL_BUFFER, AL_NONE); device.alSourcei(m_sourceId, AL_BUFFER, AL_NONE);
m_currentBuffer = std::move(newBuffer); m_currentBuffer = std::move(newBuffer);
} }
void OpenALSource::SetMinDistance(float minDistance) void OpenALSource::SetMinDistance(float minDistance)
{ {
GetDevice().MakeContextCurrent(); OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
m_library.alSourcef(m_sourceId, AL_REFERENCE_DISTANCE, minDistance); device.alSourcef(m_sourceId, AL_REFERENCE_DISTANCE, minDistance);
} }
void OpenALSource::SetPitch(float pitch) void OpenALSource::SetPitch(float pitch)
{ {
GetDevice().MakeContextCurrent(); OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
m_library.alSourcef(m_sourceId, AL_PITCH, pitch); device.alSourcef(m_sourceId, AL_PITCH, pitch);
} }
void OpenALSource::SetPlayingOffset(Time offset) void OpenALSource::SetPlayingOffset(Time offset)
{ {
GetDevice().MakeContextCurrent(); OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
#ifdef AL_SOFT_source_latency #ifdef AL_SOFT_source_latency
if (GetDevice().IsExtensionSupported(OpenALExtension::SourceLatency)) if (GetDevice().IsExtensionSupported(OpenALExtension::SourceLatency))
// alGetSourcedvSOFT has extra precision thanks to double // alGetSourcedvSOFT has extra precision thanks to double
m_library.alSourcedSOFT(m_sourceId, AL_SEC_OFFSET, offset.AsSeconds<ALdouble>()); device.alSourcedSOFT(m_sourceId, AL_SEC_OFFSET, offset.AsSeconds<ALdouble>());
else else
#endif #endif
m_library.alSourcef(m_sourceId, AL_SEC_OFFSET, offset.AsSeconds<ALfloat>()); device.alSourcef(m_sourceId, AL_SEC_OFFSET, offset.AsSeconds<ALfloat>());
} }
void OpenALSource::SetPosition(const Vector3f& position) void OpenALSource::SetPosition(const Vector3f& position)
{ {
GetDevice().MakeContextCurrent(); OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
m_library.alSource3f(m_sourceId, AL_POSITION, position.x, position.y, position.z); device.alSource3f(m_sourceId, AL_POSITION, position.x, position.y, position.z);
} }
void OpenALSource::SetSampleOffset(UInt32 offset) void OpenALSource::SetSampleOffset(UInt32 offset)
{ {
GetDevice().MakeContextCurrent(); OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
m_library.alSourcei(m_sourceId, AL_SAMPLE_OFFSET, offset); device.alSourcei(m_sourceId, AL_SAMPLE_OFFSET, offset);
} }
void OpenALSource::SetVelocity(const Vector3f& velocity) void OpenALSource::SetVelocity(const Vector3f& velocity)
{ {
GetDevice().MakeContextCurrent(); OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
m_library.alSource3f(m_sourceId, AL_VELOCITY, velocity.x, velocity.y, velocity.z); device.alSource3f(m_sourceId, AL_VELOCITY, velocity.x, velocity.y, velocity.z);
} }
void OpenALSource::SetVolume(float volume) void OpenALSource::SetVolume(float volume)
{ {
GetDevice().MakeContextCurrent(); OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
m_library.alSourcef(m_sourceId, AL_GAIN, volume); device.alSourcef(m_sourceId, AL_GAIN, volume);
} }
void OpenALSource::Stop() void OpenALSource::Stop()
{ {
GetDevice().MakeContextCurrent(); OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
m_library.alSourceStop(m_sourceId); device.alSourceStop(m_sourceId);
} }
std::shared_ptr<AudioBuffer> OpenALSource::TryUnqueueProcessedBuffer() std::shared_ptr<AudioBuffer> OpenALSource::TryUnqueueProcessedBuffer()
{ {
GetDevice().MakeContextCurrent(); OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
ALint processedCount = 0; ALint processedCount = 0;
m_library.alGetSourcei(m_sourceId, AL_BUFFERS_PROCESSED, &processedCount); device.alGetSourcei(m_sourceId, AL_BUFFERS_PROCESSED, &processedCount);
if (processedCount == 0) if (processedCount == 0)
return {}; return {};
ALuint bufferId; ALuint bufferId;
m_library.alSourceUnqueueBuffers(m_sourceId, 1, &bufferId); device.alSourceUnqueueBuffers(m_sourceId, 1, &bufferId);
auto it = std::find_if(m_queuedBuffers.begin(), m_queuedBuffers.end(), [=](const std::shared_ptr<OpenALBuffer>& alBuffer) auto it = std::find_if(m_queuedBuffers.begin(), m_queuedBuffers.end(), [=](const std::shared_ptr<OpenALBuffer>& alBuffer)
{ {
@ -337,13 +370,14 @@ namespace Nz
void OpenALSource::UnqueueAllBuffers() void OpenALSource::UnqueueAllBuffers()
{ {
GetDevice().MakeContextCurrent(); OpenALDevice& device = GetDevice();
device.MakeContextCurrent();
ALint queuedBufferCount = 0; ALint queuedBufferCount = 0;
m_library.alGetSourcei(m_sourceId, AL_BUFFERS_QUEUED, &queuedBufferCount); device.alGetSourcei(m_sourceId, AL_BUFFERS_QUEUED, &queuedBufferCount);
StackArray<ALuint> buffers = NazaraStackArrayNoInit(ALuint, queuedBufferCount); StackArray<ALuint> buffers = NazaraStackArrayNoInit(ALuint, queuedBufferCount);
m_library.alSourceUnqueueBuffers(m_sourceId, queuedBufferCount, buffers.data()); device.alSourceUnqueueBuffers(m_sourceId, queuedBufferCount, buffers.data());
m_queuedBuffers.clear(); m_queuedBuffers.clear();
} }