aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2023-04-29 19:18:06 -0700
committerChris Robinson <[email protected]>2023-04-29 19:18:06 -0700
commita35211e2c1dc53e47c4a300366d22a27fb046a8c (patch)
treea0313f8d37a2193f1cdf07d37f8be4ba53ece8a1
parent234174c62123c5d2f57d649722b5ca53b0de9d2d (diff)
Start a debug API extension
-rw-r--r--al/error.cpp11
-rw-r--r--al/state.cpp38
-rw-r--r--alc/alc.cpp4
-rw-r--r--alc/context.cpp78
-rw-r--r--alc/context.h41
-rw-r--r--alc/inprogext.h31
6 files changed, 196 insertions, 7 deletions
diff --git a/al/error.cpp b/al/error.cpp
index afa7019a..70081a2e 100644
--- a/al/error.cpp
+++ b/al/error.cpp
@@ -61,8 +61,13 @@ void ALCcontext::setError(ALenum errorCode, const char *msg, ...)
va_end(args2);
va_end(args);
- if(msglen >= 0) msg = message.data();
- else msg = "<internal error constructing message>";
+ if(msglen >= 0)
+ msg = message.data();
+ else
+ {
+ msg = "<internal error constructing message>";
+ msglen = static_cast<int>(strlen(msg));
+ }
WARN("Error generated on context %p, code 0x%04x, \"%s\"\n",
decltype(std::declval<void*>()){this}, errorCode, msg);
@@ -79,6 +84,8 @@ void ALCcontext::setError(ALenum errorCode, const char *msg, ...)
ALenum curerr{AL_NO_ERROR};
mLastError.compare_exchange_strong(curerr, errorCode);
+
+ debugMessage(DebugSource::API, DebugType::Error, 0, DebugSeverity::High, msglen, msg);
}
AL_API ALenum AL_APIENTRY alGetError(void)
diff --git a/al/state.cpp b/al/state.cpp
index 86d81b13..fc9acb25 100644
--- a/al/state.cpp
+++ b/al/state.cpp
@@ -170,6 +170,10 @@ START_API_FUNC
}
break;
+ case AL_DEBUG_OUTPUT_SOFT:
+ context->mDebugEnabled = true;
+ break;
+
case AL_STOP_SOURCES_ON_DISCONNECT_SOFT:
context->setError(AL_INVALID_OPERATION, "Re-enabling AL_STOP_SOURCES_ON_DISCONNECT_SOFT not yet supported");
break;
@@ -196,6 +200,10 @@ START_API_FUNC
}
break;
+ case AL_DEBUG_OUTPUT_SOFT:
+ context->mDebugEnabled = false;
+ break;
+
case AL_STOP_SOURCES_ON_DISCONNECT_SOFT:
context->mStopVoicesOnDisconnect = false;
break;
@@ -220,6 +228,10 @@ START_API_FUNC
value = context->mSourceDistanceModel ? AL_TRUE : AL_FALSE;
break;
+ case AL_DEBUG_OUTPUT_SOFT:
+ value = context->mDebugEnabled ? AL_TRUE : AL_FALSE;
+ break;
+
case AL_STOP_SOURCES_ON_DISCONNECT_SOFT:
value = context->mStopVoicesOnDisconnect ? AL_TRUE : AL_FALSE;
break;
@@ -546,6 +558,14 @@ START_API_FUNC
value = context->mEventParam;
break;
+ case AL_DEBUG_CALLBACK_FUNCTION_SOFT:
+ value = reinterpret_cast<void*>(context->mDebugCb);
+ break;
+
+ case AL_DEBUG_CALLBACK_USER_PARAM_SOFT:
+ value = context->mDebugParam;
+ break;
+
default:
context->setError(AL_INVALID_VALUE, "Invalid pointer property 0x%04x", pname);
}
@@ -726,10 +746,12 @@ START_API_FUNC
{
switch(pname)
{
- case AL_EVENT_CALLBACK_FUNCTION_SOFT:
- case AL_EVENT_CALLBACK_USER_PARAM_SOFT:
- values[0] = alGetPointerSOFT(pname);
- return;
+ case AL_EVENT_CALLBACK_FUNCTION_SOFT:
+ case AL_EVENT_CALLBACK_USER_PARAM_SOFT:
+ case AL_DEBUG_CALLBACK_FUNCTION_SOFT:
+ case AL_DEBUG_CALLBACK_USER_PARAM_SOFT:
+ values[0] = alGetPointerSOFT(pname);
+ return;
}
}
@@ -825,6 +847,14 @@ START_API_FUNC
ContextRef context{GetContextRef()};
if(!context) UNLIKELY return;
+ if(context->mDebugEnabled.load(std::memory_order_relaxed))
+ {
+ static constexpr char deprecatedMessage[] = "alDopplerVelocity is deprecated in AL 1.1";
+ context->sendDebugMessage(DebugSource::API, DebugType::DeprecatedBehavior, 0,
+ DebugSeverity::Medium, static_cast<int>(std::strlen(deprecatedMessage)),
+ deprecatedMessage);
+ }
+
if(!(value >= 0.0f && std::isfinite(value)))
context->setError(AL_INVALID_VALUE, "Doppler velocity %f out of range", value);
else
diff --git a/alc/alc.cpp b/alc/alc.cpp
index af8ff55d..0ed0ae58 100644
--- a/alc/alc.cpp
+++ b/alc/alc.cpp
@@ -459,6 +459,8 @@ const struct {
DECL(alBufferSubDataSOFT),
DECL(alBufferDataStatic),
+
+ DECL(alDebugMessageCallbackSOFT),
#ifdef ALSOFT_EAX
}, eaxFunctions[] = {
DECL(EAXGet),
@@ -915,6 +917,8 @@ constexpr struct {
DECL(AL_FORMAT_UHJ4CHN_MULAW_SOFT),
DECL(AL_FORMAT_UHJ4CHN_ALAW_SOFT),
+ DECL(AL_DEBUG_OUTPUT_SOFT),
+
DECL(AL_STOP_SOURCES_ON_DISCONNECT_SOFT),
#ifdef ALSOFT_EAX
diff --git a/alc/context.cpp b/alc/context.cpp
index 008c2bf4..e2a2e2d2 100644
--- a/alc/context.cpp
+++ b/alc/context.cpp
@@ -113,7 +113,7 @@ void ALCcontext::setThreadContext(ALCcontext *context) noexcept
#endif
ALCcontext::ALCcontext(al::intrusive_ptr<ALCdevice> device)
- : ContextBase{device.get()}, mALDevice{std::move(device)}
+ : ContextBase{device.get()}, mALDevice{std::move(device)}
{
}
@@ -295,6 +295,82 @@ void ALCcontext::applyAllUpdates()
mHoldUpdates.store(false, std::memory_order_release);
}
+void ALCcontext::sendDebugMessage(DebugSource source, DebugType type, ALuint id,
+ DebugSeverity severity, ALsizei length, const char *message)
+{
+ std::lock_guard<std::mutex> _{mDebugCbLock};
+ if(!mDebugEnabled.load())
+ return;
+
+ if(mDebugCb)
+ mDebugCb(al::to_underlying(source), al::to_underlying(type), id,
+ al::to_underlying(severity), length, message, mDebugParam);
+ else
+ {
+ /* TODO: Store in a log. */
+ }
+}
+
+FORCE_ALIGN void AL_APIENTRY alDebugMessageCallbackSOFT(ALDEBUGPROCSOFT callback, void *userParam) noexcept
+{
+ ContextRef context{GetContextRef()};
+ if(!context) UNLIKELY return;
+
+ std::lock_guard<std::mutex> _{context->mDebugCbLock};
+ context->mDebugCb = callback;
+ context->mDebugParam = userParam;
+}
+
+FORCE_ALIGN void AL_APIENTRY alDebugMessageInsertSOFT(ALenum source, ALenum type, ALuint id,
+ ALenum severity, ALsizei length, const ALchar *message) noexcept
+{
+ ContextRef context{GetContextRef()};
+ if(!context) UNLIKELY return;
+
+ if(!message)
+ return context->setError(AL_INVALID_VALUE, "Null message pointer");
+
+ DebugSource dsource{};
+ switch(source)
+ {
+ case AL_DEBUG_SOURCE_THIRD_PARTY_SOFT: dsource = DebugSource::ThirdParty; break;
+ case AL_DEBUG_SOURCE_APPLICATION_SOFT: dsource = DebugSource::Application; break;
+ case AL_DEBUG_SOURCE_API_SOFT:
+ case AL_DEBUG_SOURCE_AUDIO_SYSTEM_SOFT:
+ case AL_DEBUG_SOURCE_OTHER_SOFT:
+ return context->setError(AL_INVALID_ENUM, "Debug source enum 0x%04x not allowed", source);
+ default:
+ return context->setError(AL_INVALID_ENUM, "Invalid debug source enum 0x%04x", source);
+ }
+
+ DebugType dtype{};
+ switch(type)
+ {
+ case AL_DEBUG_TYPE_ERROR_SOFT: dtype = DebugType::Error; break;
+ case AL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_SOFT: dtype = DebugType::DeprecatedBehavior; break;
+ case AL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_SOFT: dtype = DebugType::UndefinedBehavior; break;
+ case AL_DEBUG_TYPE_PORTABILITY_SOFT: dtype = DebugType::Portability; break;
+ case AL_DEBUG_TYPE_PERFORMANCE_SOFT: dtype = DebugType::Performance; break;
+ case AL_DEBUG_TYPE_MARKER_SOFT: dtype = DebugType::Marker; break;
+ case AL_DEBUG_TYPE_OTHER_SOFT: dtype = DebugType::Other; break;
+ default:
+ return context->setError(AL_INVALID_ENUM, "Invalid debug type 0x%04x", type);
+ }
+
+ DebugSeverity dseverity{};
+ switch(severity)
+ {
+ case AL_DEBUG_SEVERITY_HIGH_SOFT: dseverity = DebugSeverity::High; break;
+ case AL_DEBUG_SEVERITY_MEDIUM_SOFT: dseverity = DebugSeverity::Medium; break;
+ case AL_DEBUG_SEVERITY_LOW_SOFT: dseverity = DebugSeverity::Low; break;
+ case AL_DEBUG_SEVERITY_NOTIFICATION_SOFT: dseverity = DebugSeverity::Notification; break;
+ default:
+ return context->setError(AL_INVALID_ENUM, "Invalid debug severity 0x%04x", severity);
+ }
+
+ context->debugMessage(dsource, dtype, id, dseverity, length, message);
+}
+
#ifdef ALSOFT_EAX
namespace {
diff --git a/alc/context.h b/alc/context.h
index e8efdbf1..697ecfe9 100644
--- a/alc/context.h
+++ b/alc/context.h
@@ -34,6 +34,30 @@ struct ALsource;
using uint = unsigned int;
+enum class DebugSource : ALenum {
+ API = AL_DEBUG_SOURCE_API_SOFT,
+ System = AL_DEBUG_SOURCE_AUDIO_SYSTEM_SOFT,
+ ThirdParty = AL_DEBUG_SOURCE_THIRD_PARTY_SOFT,
+ Application = AL_DEBUG_SOURCE_APPLICATION_SOFT,
+ Other = AL_DEBUG_SOURCE_OTHER_SOFT,
+};
+enum class DebugType : ALenum {
+ Error = AL_DEBUG_TYPE_ERROR_SOFT,
+ DeprecatedBehavior = AL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_SOFT,
+ UndefinedBehavior = AL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_SOFT,
+ Portability = AL_DEBUG_TYPE_PORTABILITY_SOFT,
+ Performance = AL_DEBUG_TYPE_PERFORMANCE_SOFT,
+ Marker = AL_DEBUG_TYPE_MARKER_SOFT,
+ Other = AL_DEBUG_TYPE_OTHER_SOFT,
+};
+enum class DebugSeverity : ALenum {
+ High = AL_DEBUG_SEVERITY_HIGH_SOFT,
+ Medium = AL_DEBUG_SEVERITY_MEDIUM_SOFT,
+ Low = AL_DEBUG_SEVERITY_LOW_SOFT,
+ Notification = AL_DEBUG_SEVERITY_NOTIFICATION_SOFT,
+};
+
+
struct SourceSubList {
uint64_t FreeMask{~0_u64};
ALsource *Sources{nullptr}; /* 64 */
@@ -76,6 +100,8 @@ struct ALCcontext : public al::intrusive_ref<ALCcontext>, ContextBase {
std::atomic<ALenum> mLastError{AL_NO_ERROR};
+ std::atomic<bool> mDebugEnabled{false};
+
DistanceModel mDistanceModel{DistanceModel::Default};
bool mSourceDistanceModel{false};
@@ -88,6 +114,10 @@ struct ALCcontext : public al::intrusive_ref<ALCcontext>, ContextBase {
ALEVENTPROCSOFT mEventCb{};
void *mEventParam{nullptr};
+ std::mutex mDebugCbLock;
+ ALDEBUGPROCSOFT mDebugCb{};
+ void *mDebugParam{nullptr};
+
ALlistener mListener{};
al::vector<SourceSubList> mSourceList;
@@ -149,6 +179,17 @@ struct ALCcontext : public al::intrusive_ref<ALCcontext>, ContextBase {
#endif
void setError(ALenum errorCode, const char *msg, ...);
+ void sendDebugMessage(DebugSource source, DebugType type, ALuint id, DebugSeverity severity,
+ ALsizei length, const char *message);
+
+ void debugMessage(DebugSource source, DebugType type, ALuint id, DebugSeverity severity,
+ ALsizei length, const char *message)
+ {
+ if(!mDebugEnabled.load(std::memory_order_relaxed)) LIKELY
+ return;
+ sendDebugMessage(source, type, id, severity, length, message);
+ }
+
/* Process-wide current context */
static std::atomic<bool> sGlobalContextLock;
static std::atomic<ALCcontext*> sGlobalContext;
diff --git a/alc/inprogext.h b/alc/inprogext.h
index ccb9a4be..53dc9f0c 100644
--- a/alc/inprogext.h
+++ b/alc/inprogext.h
@@ -54,6 +54,37 @@ AL_API void AL_APIENTRY alAuxiliaryEffectSlotStopvSOFT(ALsizei n, const ALuint *
#define AL_STOP_SOURCES_ON_DISCONNECT_SOFT 0x19AB
#endif
+#ifndef AL_SOFT_debug
+#define AL_SOFT_debug
+#define AL_DEBUG_OUTPUT_SOFT 0x19B2
+#define AL_DEBUG_CALLBACK_FUNCTION_SOFT 0x19B3
+#define AL_DEBUG_CALLBACK_USER_PARAM_SOFT 0x19B4
+#define AL_DEBUG_SOURCE_API_SOFT 0x19B5
+#define AL_DEBUG_SOURCE_AUDIO_SYSTEM_SOFT 0x19B6
+#define AL_DEBUG_SOURCE_THIRD_PARTY_SOFT 0x19B7
+#define AL_DEBUG_SOURCE_APPLICATION_SOFT 0x19B8
+#define AL_DEBUG_SOURCE_OTHER_SOFT 0x19B9
+#define AL_DEBUG_TYPE_ERROR_SOFT 0x19BA
+#define AL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_SOFT 0x19BB
+#define AL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_SOFT 0x19BC
+#define AL_DEBUG_TYPE_PORTABILITY_SOFT 0x19BD
+#define AL_DEBUG_TYPE_PERFORMANCE_SOFT 0x19BE
+#define AL_DEBUG_TYPE_MARKER_SOFT 0x19BF
+#define AL_DEBUG_TYPE_OTHER_SOFT 0x19C0
+#define AL_DEBUG_SEVERITY_HIGH_SOFT 0x19C1
+#define AL_DEBUG_SEVERITY_MEDIUM_SOFT 0x19C2
+#define AL_DEBUG_SEVERITY_LOW_SOFT 0x19C3
+#define AL_DEBUG_SEVERITY_NOTIFICATION_SOFT 0x19C4
+
+typedef void (AL_APIENTRY*ALDEBUGPROCSOFT)(ALenum source, ALenum type, ALuint id, ALenum severity, ALsizei length, const ALchar *message, void *userParam);
+typedef void (AL_APIENTRY*LPALDEBUGMESSAGECALLBACKSOFT)(ALDEBUGPROCSOFT callback, void *userParam);
+typedef void (AL_APIENTRY*LPALDEBUGMESSAGEINSERTSOFT)(ALenum source, ALenum type, ALuint id, ALenum severity, ALsizei length, const ALchar *message);
+#ifdef AL_ALEXT_PROTOTYPES
+void AL_APIENTRY alDebugMessageCallbackSOFT(ALDEBUGPROCSOFT callback, void *userParam) noexcept;
+void AL_APIENTRY alDebugMessageInsertSOFT(ALenum source, ALenum type, ALuint id, ALenum severity, ALsizei length, const ALchar *message) noexcept;
+#endif
+#endif
+
/* Non-standard export. Not part of any extension. */
AL_API const ALchar* AL_APIENTRY alsoft_get_version(void);