diff options
Diffstat (limited to 'al')
-rw-r--r-- | al/debug.cpp | 145 | ||||
-rw-r--r-- | al/debug.h | 5 | ||||
-rw-r--r-- | al/state.cpp | 23 |
3 files changed, 168 insertions, 5 deletions
diff --git a/al/debug.cpp b/al/debug.cpp index fc893490..2dd0e7c7 100644 --- a/al/debug.cpp +++ b/al/debug.cpp @@ -17,12 +17,15 @@ #include "alc/inprogext.h" #include "aloptional.h" #include "alspan.h" +#include "core/logging.h" #include "opthelpers.h" #include "threads.h" namespace { +static_assert(DebugSeverityBase+DebugSeverityCount <= 32, "Too many debug bits"); + template<typename T, T ...Vals> constexpr auto make_array(std::integer_sequence<T, Vals...>) { return std::array<T,sizeof...(Vals)>{Vals...}; } @@ -55,6 +58,8 @@ constexpr al::optional<DebugType> GetDebugType(ALenum type) noexcept case AL_DEBUG_TYPE_PORTABILITY_SOFT: return DebugType::Portability; case AL_DEBUG_TYPE_PERFORMANCE_SOFT: return DebugType::Performance; case AL_DEBUG_TYPE_MARKER_SOFT: return DebugType::Marker; + case AL_DEBUG_TYPE_PUSH_GROUP_SOFT: return DebugType::PushGroup; + case AL_DEBUG_TYPE_POP_GROUP_SOFT: return DebugType::PopGroup; case AL_DEBUG_TYPE_OTHER_SOFT: return DebugType::Other; } return al::nullopt; @@ -72,7 +77,6 @@ constexpr al::optional<DebugSeverity> GetDebugSeverity(ALenum severity) noexcept return al::nullopt; } -} // namespace ALenum GetDebugSourceEnum(DebugSource source) { @@ -97,6 +101,8 @@ ALenum GetDebugTypeEnum(DebugType type) 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::PushGroup: return AL_DEBUG_TYPE_PUSH_GROUP_SOFT; + case DebugType::PopGroup: return AL_DEBUG_TYPE_POP_GROUP_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))}; @@ -114,6 +120,74 @@ ALenum GetDebugSeverityEnum(DebugSeverity severity) throw std::runtime_error{"Unexpected debug severity value "+std::to_string(al::to_underlying(severity))}; } +} // namespace + + +void ALCcontext::sendDebugMessage(std::unique_lock<std::mutex> &debuglock, DebugSource source, + DebugType type, ALuint id, DebugSeverity severity, ALsizei length, const char *message) +{ + if(!mDebugEnabled.load()) UNLIKELY + return; + + /* MaxDebugMessageLength is the size including the null terminator, + * <length> does not include the null terminator. + */ + 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; + } + + DebugGroup &debug = mDebugGroups.back(); + + const uint64_t idfilter{(1_u64 << (DebugSourceBase+al::to_underlying(source))) + | (1_u64 << (DebugTypeBase+al::to_underlying(type))) + | (uint64_t{id} << 32)}; + auto iditer = std::lower_bound(debug.mIdFilters.cbegin(), debug.mIdFilters.cend(), idfilter); + if(iditer != debug.mIdFilters.cend() && *iditer == idfilter) + return; + + const uint filter{(1u << (DebugSourceBase+al::to_underlying(source))) + | (1u << (DebugTypeBase+al::to_underlying(type))) + | (1u << (DebugSeverityBase+al::to_underlying(severity)))}; + auto iter = std::lower_bound(debug.mFilters.cbegin(), debug.mFilters.cend(), filter); + if(iter != debug.mFilters.cend() && *iter == filter) + return; + + if(mDebugCb) + { + auto callback = mDebugCb; + auto param = mDebugParam; + debuglock.unlock(); + callback(GetDebugSourceEnum(source), GetDebugTypeEnum(type), id, + GetDebugSeverityEnum(severity), length, message, param); + } + else + { + 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", + GetDebugSourceEnum(source), GetDebugTypeEnum(type), id, + GetDebugSeverityEnum(severity), message); + } +} + FORCE_ALIGN void AL_APIENTRY alDebugMessageCallbackSOFT(ALDEBUGPROCSOFT callback, void *userParam) noexcept { @@ -134,9 +208,6 @@ FORCE_ALIGN void AL_APIENTRY alDebugMessageInsertSOFT(ALenum source, ALenum type if(!message) return context->setError(AL_INVALID_VALUE, "Null message pointer"); - /* MaxDebugMessageLength is the size including the null terminator, - * <length> does not include the null terminator. - */ if(length < 0) { size_t newlen{std::strlen(message)}; @@ -265,6 +336,72 @@ FORCE_ALIGN void AL_APIENTRY alDebugMessageControlSOFT(ALenum source, ALenum typ } +FORCE_ALIGN void AL_APIENTRY alPushDebugGroupSOFT(ALenum source, ALuint id, ALsizei length, const ALchar *message) noexcept +{ + ContextRef context{GetContextRef()}; + if(!context) UNLIKELY return; + + 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); + if(*dsource != DebugSource::ThirdParty && *dsource != DebugSource::Application) + return context->setError(AL_INVALID_ENUM, "Debug source 0x%04x not allowed", source); + + std::unique_lock<std::mutex> debuglock{context->mDebugCbLock}; + if(context->mDebugGroups.size() >= MaxDebugGroupDepth) + { + debuglock.unlock(); + return context->setError(AL_STACK_OVERFLOW_SOFT, "Pushing too many debug groups"); + } + + context->mDebugGroups.emplace_back(*dsource, id, message); + auto &oldback = *(context->mDebugGroups.end()-2); + auto &newback = context->mDebugGroups.back(); + + newback.mFilters = oldback.mFilters; + newback.mIdFilters = oldback.mIdFilters; + + context->sendDebugMessage(debuglock, newback.mSource, DebugType::PushGroup, newback.mId, + DebugSeverity::Notification, static_cast<ALsizei>(newback.mMessage.size()), + newback.mMessage.data()); +} + +FORCE_ALIGN void AL_APIENTRY alPopDebugGroupSOFT(void) noexcept +{ + ContextRef context{GetContextRef()}; + if(!context) UNLIKELY return; + + std::unique_lock<std::mutex> debuglock{context->mDebugCbLock}; + if(context->mDebugGroups.size() <= 1) + { + debuglock.unlock(); + return context->setError(AL_STACK_UNDERFLOW_SOFT, + "Attempting to pop the default debug group"); + } + + DebugGroup &debug = context->mDebugGroups.back(); + const auto source = debug.mSource; + const auto id = debug.mId; + std::string message{std::move(debug.mMessage)}; + + context->mDebugGroups.pop_back(); + context->sendDebugMessage(debuglock, source, DebugType::PopGroup, id, + DebugSeverity::Notification, static_cast<ALsizei>(message.size()), message.data()); +} + + FORCE_ALIGN ALuint AL_APIENTRY alGetDebugMessageLogSOFT(ALuint count, ALsizei logBufSize, ALenum *sources, ALenum *types, ALuint *ids, ALenum *severities, ALsizei *lengths, ALchar *logBuf) noexcept @@ -13,6 +13,7 @@ using uint = unsigned int; */ constexpr uint8_t MaxDebugLoggedMessages{64}; constexpr uint16_t MaxDebugMessageLength{1024}; +constexpr uint8_t MaxDebugGroupDepth{64}; constexpr uint DebugSourceBase{0}; @@ -33,9 +34,11 @@ enum class DebugType : uint8_t { Portability, Performance, Marker, + PushGroup, + PopGroup, Other, }; -constexpr uint DebugTypeCount{7}; +constexpr uint DebugTypeCount{9}; constexpr uint DebugSeverityBase{DebugTypeBase + DebugTypeCount}; enum class DebugSeverity : uint8_t { diff --git a/al/state.cpp b/al/state.cpp index 1e1a0085..2a350646 100644 --- a/al/state.cpp +++ b/al/state.cpp @@ -69,6 +69,8 @@ constexpr ALchar alErrInvalidEnum[] = "Invalid Enum"; constexpr ALchar alErrInvalidValue[] = "Invalid Value"; constexpr ALchar alErrInvalidOp[] = "Invalid Operation"; constexpr ALchar alErrOutOfMemory[] = "Out of Memory"; +constexpr ALchar alStackOverflow[] = "Stack Overflow"; +constexpr ALchar alStackUnderflow[] = "Stack Underflow"; /* Resampler strings */ template<Resampler rtype> struct ResamplerName { }; @@ -264,6 +266,7 @@ START_API_FUNC case AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_SOFT: case AL_MAX_DEBUG_MESSAGE_LENGTH_SOFT: case AL_MAX_DEBUG_LOGGED_MESSAGES_SOFT: + case AL_MAX_DEBUG_GROUP_STACK_DEPTH_SOFT: return alGetInteger(pname) != 0; } @@ -308,6 +311,7 @@ START_API_FUNC case AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_SOFT: case AL_MAX_DEBUG_MESSAGE_LENGTH_SOFT: case AL_MAX_DEBUG_LOGGED_MESSAGES_SOFT: + case AL_MAX_DEBUG_GROUP_STACK_DEPTH_SOFT: return alGetInteger(pname); } @@ -338,6 +342,7 @@ START_API_FUNC case AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_SOFT: case AL_MAX_DEBUG_MESSAGE_LENGTH_SOFT: case AL_MAX_DEBUG_LOGGED_MESSAGES_SOFT: + case AL_MAX_DEBUG_GROUP_STACK_DEPTH_SOFT: return static_cast<ALfloat>(alGetInteger(pname)); case AL_DEFERRED_UPDATES_SOFT: @@ -436,6 +441,10 @@ START_API_FUNC value = MaxDebugLoggedMessages; break; + case AL_MAX_DEBUG_GROUP_STACK_DEPTH_SOFT: + value = MaxDebugGroupDepth; + break; + #ifdef ALSOFT_EAX #define EAX_ERROR "[alGetInteger] EAX not enabled." @@ -491,6 +500,7 @@ START_API_FUNC case AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_SOFT: case AL_MAX_DEBUG_MESSAGE_LENGTH_SOFT: case AL_MAX_DEBUG_LOGGED_MESSAGES_SOFT: + case AL_MAX_DEBUG_GROUP_STACK_DEPTH_SOFT: return alGetInteger(pname); } @@ -562,6 +572,7 @@ START_API_FUNC case AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_SOFT: case AL_MAX_DEBUG_MESSAGE_LENGTH_SOFT: case AL_MAX_DEBUG_LOGGED_MESSAGES_SOFT: + case AL_MAX_DEBUG_GROUP_STACK_DEPTH_SOFT: values[0] = alGetBoolean(pname); return; } @@ -599,6 +610,7 @@ START_API_FUNC case AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_SOFT: case AL_MAX_DEBUG_MESSAGE_LENGTH_SOFT: case AL_MAX_DEBUG_LOGGED_MESSAGES_SOFT: + case AL_MAX_DEBUG_GROUP_STACK_DEPTH_SOFT: values[0] = alGetDouble(pname); return; } @@ -636,6 +648,7 @@ START_API_FUNC case AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_SOFT: case AL_MAX_DEBUG_MESSAGE_LENGTH_SOFT: case AL_MAX_DEBUG_LOGGED_MESSAGES_SOFT: + case AL_MAX_DEBUG_GROUP_STACK_DEPTH_SOFT: values[0] = alGetFloat(pname); return; } @@ -673,6 +686,7 @@ START_API_FUNC case AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_SOFT: case AL_MAX_DEBUG_MESSAGE_LENGTH_SOFT: case AL_MAX_DEBUG_LOGGED_MESSAGES_SOFT: + case AL_MAX_DEBUG_GROUP_STACK_DEPTH_SOFT: values[0] = alGetInteger(pname); return; } @@ -710,6 +724,7 @@ START_API_FUNC case AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_SOFT: case AL_MAX_DEBUG_MESSAGE_LENGTH_SOFT: case AL_MAX_DEBUG_LOGGED_MESSAGES_SOFT: + case AL_MAX_DEBUG_GROUP_STACK_DEPTH_SOFT: values[0] = alGetInteger64SOFT(pname); return; } @@ -806,6 +821,14 @@ START_API_FUNC value = alErrOutOfMemory; break; + case AL_STACK_OVERFLOW_SOFT: + value = alStackOverflow; + break; + + case AL_STACK_UNDERFLOW_SOFT: + value = alStackUnderflow; + break; + default: context->setError(AL_INVALID_VALUE, "Invalid string property 0x%04x", pname); } |