diff options
author | Chris Robinson <[email protected]> | 2023-04-30 17:46:18 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2023-04-30 17:46:18 -0700 |
commit | 22077687cf4b9fdfd29d78debc2daf044deee81d (patch) | |
tree | fc9aab402ea9e33f7cec2e1ef1dfa98203665578 | |
parent | f2a0df87916de7b9fa8b65a52814c9a09fc6bee9 (diff) |
Implement debug log storage
-rw-r--r-- | al/debug.cpp | 93 | ||||
-rw-r--r-- | al/debug.h | 9 | ||||
-rw-r--r-- | al/state.cpp | 61 | ||||
-rw-r--r-- | alc/alc.cpp | 5 | ||||
-rw-r--r-- | alc/context.cpp | 29 | ||||
-rw-r--r-- | alc/context.h | 19 | ||||
-rw-r--r-- | alc/inprogext.h | 6 |
7 files changed, 220 insertions, 2 deletions
diff --git a/al/debug.cpp b/al/debug.cpp index 2694d7b4..ab81f5a8 100644 --- a/al/debug.cpp +++ b/al/debug.cpp @@ -71,6 +71,46 @@ constexpr al::optional<DebugSeverity> GetDebugSeverity(ALenum severity) noexcept } // namespace +ALenum GetDebugSourceEnum(DebugSource source) +{ + switch(source) + { + case DebugSource::API: return AL_DEBUG_SOURCE_API_SOFT; + case DebugSource::System: return AL_DEBUG_SOURCE_AUDIO_SYSTEM_SOFT; + case DebugSource::ThirdParty: return AL_DEBUG_SOURCE_THIRD_PARTY_SOFT; + case DebugSource::Application: return AL_DEBUG_SOURCE_APPLICATION_SOFT; + case DebugSource::Other: return AL_DEBUG_SOURCE_OTHER_SOFT; + } + throw std::runtime_error{"Unexpected debug source value "+std::to_string(al::to_underlying(source))}; +} + +ALenum GetDebugTypeEnum(DebugType type) +{ + switch(type) + { + case DebugType::Error: return AL_DEBUG_TYPE_ERROR_SOFT; + case DebugType::DeprecatedBehavior: return AL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_SOFT; + case DebugType::UndefinedBehavior: return AL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_SOFT; + case DebugType::Portability: return AL_DEBUG_TYPE_PORTABILITY_SOFT; + case DebugType::Performance: return AL_DEBUG_TYPE_PERFORMANCE_SOFT; + case DebugType::Marker: return AL_DEBUG_TYPE_MARKER_SOFT; + case DebugType::Other: return AL_DEBUG_TYPE_OTHER_SOFT; + } + throw std::runtime_error{"Unexpected debug type value "+std::to_string(al::to_underlying(type))}; +} + +ALenum GetDebugSeverityEnum(DebugSeverity severity) +{ + switch(severity) + { + case DebugSeverity::High: return AL_DEBUG_SEVERITY_HIGH_SOFT; + case DebugSeverity::Medium: return AL_DEBUG_SEVERITY_MEDIUM_SOFT; + case DebugSeverity::Low: return AL_DEBUG_SEVERITY_LOW_SOFT; + case DebugSeverity::Notification: return AL_DEBUG_SEVERITY_NOTIFICATION_SOFT; + } + throw std::runtime_error{"Unexpected debug severity value "+std::to_string(al::to_underlying(severity))}; +} + FORCE_ALIGN void AL_APIENTRY alDebugMessageCallbackSOFT(ALDEBUGPROCSOFT callback, void *userParam) noexcept { @@ -91,6 +131,18 @@ FORCE_ALIGN void AL_APIENTRY alDebugMessageInsertSOFT(ALenum source, ALenum type if(!message) return context->setError(AL_INVALID_VALUE, "Null message pointer"); + if(length < 0) + { + size_t newlen{std::strlen(message)}; + if(newlen > MaxDebugMessageLength) UNLIKELY + return context->setError(AL_INVALID_VALUE, "Debug message too long (%zu > %d)", newlen, + MaxDebugMessageLength); + length = static_cast<ALsizei>(newlen); + } + else if(length > MaxDebugMessageLength) UNLIKELY + return context->setError(AL_INVALID_VALUE, "Debug message too long (%d > %d)", length, + MaxDebugMessageLength); + auto dsource = GetDebugSource(source); if(!dsource) return context->setError(AL_INVALID_ENUM, "Invalid debug source 0x%04x", source); @@ -189,3 +241,44 @@ FORCE_ALIGN void AL_APIENTRY alDebugMessageControlSOFT(ALenum source, ALenum typ std::for_each(srcIndices.cbegin(), srcIndices.cend(), [apply_type](const uint idx){ apply_type(1<<idx); }); } + + +FORCE_ALIGN ALuint AL_APIENTRY alGetDebugMessageLogSOFT(ALuint count, ALsizei logBufSize, + ALenum *sources, ALenum *types, ALuint *ids, ALenum *severities, ALsizei *lengths, + ALchar *logBuf) noexcept +{ + ContextRef context{GetContextRef()}; + if(!context) UNLIKELY return 0; + + if(logBufSize < 0) + { + context->setError(AL_INVALID_VALUE, "Negative debug log buffer size"); + return 0; + } + + std::lock_guard<std::mutex> _{context->mDebugCbLock}; + ALsizei logBufWritten{0}; + for(ALuint i{0};i < count;++i) + { + if(context->mDebugLog.empty()) + return i; + + auto &entry = context->mDebugLog.front(); + const size_t tocopy{entry.mMessage.size() + 1}; + const size_t avail{static_cast<ALuint>(logBufSize - logBufWritten)}; + if(avail < tocopy) + return i; + + if(sources) sources[i] = GetDebugSourceEnum(entry.mSource); + if(types) types[i] = GetDebugTypeEnum(entry.mType); + if(ids) ids[i] = entry.mId; + if(severities) severities[i] = GetDebugSeverityEnum(entry.mSeverity); + if(lengths) lengths[i] = static_cast<ALsizei>(tocopy); + if(logBuf) std::copy_n(entry.mMessage.data(), tocopy, logBuf+logBufWritten); + + logBufWritten += static_cast<ALsizei>(tocopy); + context->mDebugLog.pop_front(); + } + + return count; +} @@ -1,4 +1,13 @@ #ifndef AL_DEBUG_H #define AL_DEBUG_H +#include <stdint.h> + + +/* Somewhat arbitrary. Avoid letting it get out of control if the app enables + * logging but never reads it. + */ +constexpr uint8_t MaxDebugLoggedMessages{64}; +constexpr uint16_t MaxDebugMessageLength{1024}; + #endif /* AL_DEBUG_H */ diff --git a/al/state.cpp b/al/state.cpp index 7b7377f7..1e1a0085 100644 --- a/al/state.cpp +++ b/al/state.cpp @@ -33,6 +33,7 @@ #include "AL/alc.h" #include "AL/alext.h" +#include "al/debug.h" #include "alc/alu.h" #include "alc/context.h" #include "alc/inprogext.h" @@ -259,6 +260,10 @@ START_API_FUNC case AL_DISTANCE_MODEL: case AL_NUM_RESAMPLERS_SOFT: case AL_DEFAULT_RESAMPLER_SOFT: + case AL_DEBUG_LOGGED_MESSAGES_SOFT: + case AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_SOFT: + case AL_MAX_DEBUG_MESSAGE_LENGTH_SOFT: + case AL_MAX_DEBUG_LOGGED_MESSAGES_SOFT: return alGetInteger(pname) != 0; } @@ -299,6 +304,10 @@ START_API_FUNC case AL_DISTANCE_MODEL: case AL_NUM_RESAMPLERS_SOFT: case AL_DEFAULT_RESAMPLER_SOFT: + case AL_DEBUG_LOGGED_MESSAGES_SOFT: + case AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_SOFT: + case AL_MAX_DEBUG_MESSAGE_LENGTH_SOFT: + case AL_MAX_DEBUG_LOGGED_MESSAGES_SOFT: return alGetInteger(pname); } @@ -325,8 +334,11 @@ START_API_FUNC case AL_DISTANCE_MODEL: case AL_NUM_RESAMPLERS_SOFT: case AL_DEFAULT_RESAMPLER_SOFT: + case AL_DEBUG_LOGGED_MESSAGES_SOFT: + case AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_SOFT: + case AL_MAX_DEBUG_MESSAGE_LENGTH_SOFT: + case AL_MAX_DEBUG_LOGGED_MESSAGES_SOFT: return static_cast<ALfloat>(alGetInteger(pname)); - break; case AL_DEFERRED_UPDATES_SOFT: return alGetBoolean(pname) ? 1.0f : 0.0f; @@ -401,6 +413,29 @@ START_API_FUNC value = al::to_underlying(ResamplerDefault); break; + case AL_DEBUG_LOGGED_MESSAGES_SOFT: + { + std::lock_guard<std::mutex> __{context->mDebugCbLock}; + value = static_cast<ALint>(context->mDebugLog.size()); + break; + } + + case AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_SOFT: + { + std::lock_guard<std::mutex> __{context->mDebugCbLock}; + value = context->mDebugLog.empty() ? 0 + : static_cast<ALint>(context->mDebugLog.front().mMessage.size()+1); + break; + } + + case AL_MAX_DEBUG_MESSAGE_LENGTH_SOFT: + value = MaxDebugMessageLength; + break; + + case AL_MAX_DEBUG_LOGGED_MESSAGES_SOFT: + value = MaxDebugLoggedMessages; + break; + #ifdef ALSOFT_EAX #define EAX_ERROR "[alGetInteger] EAX not enabled." @@ -452,6 +487,10 @@ START_API_FUNC case AL_DISTANCE_MODEL: case AL_NUM_RESAMPLERS_SOFT: case AL_DEFAULT_RESAMPLER_SOFT: + case AL_DEBUG_LOGGED_MESSAGES_SOFT: + case AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_SOFT: + case AL_MAX_DEBUG_MESSAGE_LENGTH_SOFT: + case AL_MAX_DEBUG_LOGGED_MESSAGES_SOFT: return alGetInteger(pname); } @@ -519,6 +558,10 @@ START_API_FUNC case AL_GAIN_LIMIT_SOFT: case AL_NUM_RESAMPLERS_SOFT: case AL_DEFAULT_RESAMPLER_SOFT: + case AL_DEBUG_LOGGED_MESSAGES_SOFT: + case AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_SOFT: + case AL_MAX_DEBUG_MESSAGE_LENGTH_SOFT: + case AL_MAX_DEBUG_LOGGED_MESSAGES_SOFT: values[0] = alGetBoolean(pname); return; } @@ -552,6 +595,10 @@ START_API_FUNC case AL_GAIN_LIMIT_SOFT: case AL_NUM_RESAMPLERS_SOFT: case AL_DEFAULT_RESAMPLER_SOFT: + case AL_DEBUG_LOGGED_MESSAGES_SOFT: + case AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_SOFT: + case AL_MAX_DEBUG_MESSAGE_LENGTH_SOFT: + case AL_MAX_DEBUG_LOGGED_MESSAGES_SOFT: values[0] = alGetDouble(pname); return; } @@ -585,6 +632,10 @@ START_API_FUNC case AL_GAIN_LIMIT_SOFT: case AL_NUM_RESAMPLERS_SOFT: case AL_DEFAULT_RESAMPLER_SOFT: + case AL_DEBUG_LOGGED_MESSAGES_SOFT: + case AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_SOFT: + case AL_MAX_DEBUG_MESSAGE_LENGTH_SOFT: + case AL_MAX_DEBUG_LOGGED_MESSAGES_SOFT: values[0] = alGetFloat(pname); return; } @@ -618,6 +669,10 @@ START_API_FUNC case AL_GAIN_LIMIT_SOFT: case AL_NUM_RESAMPLERS_SOFT: case AL_DEFAULT_RESAMPLER_SOFT: + case AL_DEBUG_LOGGED_MESSAGES_SOFT: + case AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_SOFT: + case AL_MAX_DEBUG_MESSAGE_LENGTH_SOFT: + case AL_MAX_DEBUG_LOGGED_MESSAGES_SOFT: values[0] = alGetInteger(pname); return; } @@ -651,6 +706,10 @@ START_API_FUNC case AL_GAIN_LIMIT_SOFT: case AL_NUM_RESAMPLERS_SOFT: case AL_DEFAULT_RESAMPLER_SOFT: + case AL_DEBUG_LOGGED_MESSAGES_SOFT: + case AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_SOFT: + case AL_MAX_DEBUG_MESSAGE_LENGTH_SOFT: + case AL_MAX_DEBUG_LOGGED_MESSAGES_SOFT: values[0] = alGetInteger64SOFT(pname); return; } diff --git a/alc/alc.cpp b/alc/alc.cpp index b6dc111d..504737ec 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -463,6 +463,7 @@ const struct { DECL(alDebugMessageCallbackSOFT), DECL(alDebugMessageInsertSOFT), DECL(alDebugMessageControlSOFT), + DECL(alGetDebugMessageLogSOFT), #ifdef ALSOFT_EAX }, eaxFunctions[] = { DECL(EAXGet), @@ -939,6 +940,10 @@ constexpr struct { DECL(AL_DEBUG_SEVERITY_MEDIUM_SOFT), DECL(AL_DEBUG_SEVERITY_LOW_SOFT), DECL(AL_DEBUG_SEVERITY_NOTIFICATION_SOFT), + DECL(AL_DEBUG_LOGGED_MESSAGES_SOFT), + DECL(AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_SOFT), + DECL(AL_MAX_DEBUG_MESSAGE_LENGTH_SOFT), + DECL(AL_MAX_DEBUG_LOGGED_MESSAGES_SOFT), DECL(AL_STOP_SOURCES_ON_DISCONNECT_SOFT), diff --git a/alc/context.cpp b/alc/context.cpp index 4e5a3ab6..a07e5412 100644 --- a/alc/context.cpp +++ b/alc/context.cpp @@ -15,6 +15,7 @@ #include "AL/efx.h" #include "al/auxeffectslot.h" +#include "al/debug.h" #include "al/source.h" #include "al/effect.h" #include "al/event.h" @@ -342,6 +343,22 @@ void ALCcontext::sendDebugMessage(DebugSource source, DebugType type, ALuint id, throw std::runtime_error{"Unexpected debug severity value "+std::to_string(al::to_underlying(severity))}; }; + if(length < 0) + { + size_t newlen{std::strlen(message)}; + if(newlen > MaxDebugMessageLength) UNLIKELY + { + ERR("Debug message too long (%zu > %d)\n", newlen, MaxDebugMessageLength); + return; + } + length = static_cast<ALsizei>(newlen); + } + else if(length > MaxDebugMessageLength) UNLIKELY + { + ERR("Debug message too long (%d > %d)\n", length, MaxDebugMessageLength); + return; + } + std::unique_lock<std::mutex> debuglock{mDebugCbLock}; if(!mDebugEnabled.load()) UNLIKELY return; @@ -364,7 +381,17 @@ void ALCcontext::sendDebugMessage(DebugSource source, DebugType type, ALuint id, } else { - /* TODO: Store in a log. */ + if(mDebugLog.size() < MaxDebugLoggedMessages) + mDebugLog.emplace_back(source, type, id, severity, message); + else UNLIKELY + ERR("Debug message log overflow. Lost message:\n" + " Source: 0x%04x\n" + " Type: 0x%04x\n" + " ID: %u\n" + " Severity: 0x%04x\n" + " Message: \"%s\"\n", + get_source_enum(source), get_type_enum(type), id, get_severity_enum(severity), + message); } } diff --git a/alc/context.h b/alc/context.h index b5ee440b..031e061e 100644 --- a/alc/context.h +++ b/alc/context.h @@ -2,6 +2,7 @@ #define ALC_CONTEXT_H #include <atomic> +#include <deque> #include <memory> #include <mutex> #include <stdint.h> @@ -66,6 +67,23 @@ enum class DebugSeverity : uint8_t { }; constexpr uint DebugSeverityCount{4}; +struct LogEntry { + const DebugSource mSource; + const DebugType mType; + const DebugSeverity mSeverity; + const uint mId; + + std::string mMessage; + + template<typename T> + LogEntry(DebugSource source, DebugType type, uint id, DebugSeverity severity, T&& message) + : mSource{source}, mType{type}, mSeverity{severity}, mId{id} + , mMessage{std::forward<T>(message)} + { } + LogEntry(const LogEntry&) = default; + LogEntry(LogEntry&&) = default; +}; + struct SourceSubList { uint64_t FreeMask{~0_u64}; @@ -127,6 +145,7 @@ struct ALCcontext : public al::intrusive_ref<ALCcontext>, ContextBase { ALDEBUGPROCSOFT mDebugCb{}; void *mDebugParam{nullptr}; std::vector<uint> mDebugFilters; + std::deque<LogEntry> mDebugLog; ALlistener mListener{}; diff --git a/alc/inprogext.h b/alc/inprogext.h index a4e2c353..f73963cb 100644 --- a/alc/inprogext.h +++ b/alc/inprogext.h @@ -76,15 +76,21 @@ AL_API void AL_APIENTRY alAuxiliaryEffectSlotStopvSOFT(ALsizei n, const ALuint * #define AL_DEBUG_SEVERITY_MEDIUM_SOFT 0x19C2 #define AL_DEBUG_SEVERITY_LOW_SOFT 0x19C3 #define AL_DEBUG_SEVERITY_NOTIFICATION_SOFT 0x19C4 +#define AL_DEBUG_LOGGED_MESSAGES_SOFT 0x19C5 +#define AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_SOFT 0x19C6 +#define AL_MAX_DEBUG_MESSAGE_LENGTH_SOFT 0x19C7 +#define AL_MAX_DEBUG_LOGGED_MESSAGES_SOFT 0x19C8 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); typedef void (AL_APIENTRY*LPALDEBUGMESSAGECONTROLSOFT)(ALenum source, ALenum type, ALenum severity, ALsizei count, const ALuint *ids, ALboolean enable); +typedef ALuint (AL_APIENTRY*LPALGETDEBUGMESSAGELOGSOFT)(ALuint count, ALsizei logBufSize, ALenum *sources, ALenum *types, ALuint *ids, ALenum *severities, ALsizei *lengths, ALchar *logBuf); #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; void AL_APIENTRY alDebugMessageControlSOFT(ALenum source, ALenum type, ALenum severity, ALsizei count, const ALuint *ids, ALboolean enable) noexcept; +ALuint AL_APIENTRY alGetDebugMessageLogSOFT(ALuint count, ALsizei logBufSize, ALenum *sources, ALenum *types, ALuint *ids, ALenum *severities, ALsizei *lengths, ALchar *logBuf) noexcept; #endif #endif |