aboutsummaryrefslogtreecommitdiffstats
path: root/al/debug.cpp
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2023-05-01 19:11:26 -0700
committerChris Robinson <[email protected]>2023-05-01 19:11:26 -0700
commite1b573284b649c6fef42ab5b6ca51978c4a1329a (patch)
tree2bd2c30bebf142c969560a069417ceba57d4a953 /al/debug.cpp
parentbb08a416f1b0e31292b896f2f8845e365daee6b1 (diff)
Implement pushing/popping debug groups
Diffstat (limited to 'al/debug.cpp')
-rw-r--r--al/debug.cpp145
1 files changed, 141 insertions, 4 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