diff options
Diffstat (limited to '')
-rw-r--r-- | gfx/angle/checkout/src/libANGLE/Debug.cpp | 507 |
1 files changed, 507 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/libANGLE/Debug.cpp b/gfx/angle/checkout/src/libANGLE/Debug.cpp new file mode 100644 index 0000000000..da97ae9d9e --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/Debug.cpp @@ -0,0 +1,507 @@ +// +// Copyright 2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Debug.cpp: Defines debug state used for GL_KHR_debug + +#include "libANGLE/Debug.h" + +#include "common/debug.h" + +#include <algorithm> +#include <tuple> + +namespace +{ +const char *GLSeverityToString(GLenum severity) +{ + switch (severity) + { + case GL_DEBUG_SEVERITY_HIGH: + return "HIGH"; + case GL_DEBUG_SEVERITY_MEDIUM: + return "MEDIUM"; + case GL_DEBUG_SEVERITY_LOW: + return "LOW"; + case GL_DEBUG_SEVERITY_NOTIFICATION: + default: + return "NOTIFICATION"; + } +} + +const char *EGLMessageTypeToString(egl::MessageType messageType) +{ + switch (messageType) + { + case egl::MessageType::Critical: + return "CRITICAL"; + case egl::MessageType::Error: + return "ERROR"; + case egl::MessageType::Warn: + return "WARNING"; + case egl::MessageType::Info: + default: + return "INFO"; + } +} + +const char *GLMessageTypeToString(GLenum type) +{ + switch (type) + { + case GL_DEBUG_TYPE_ERROR: + return "error"; + case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: + return "deprecated behavior"; + case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: + return "undefined behavior"; + case GL_DEBUG_TYPE_PORTABILITY: + return "portability"; + case GL_DEBUG_TYPE_PERFORMANCE: + return "performance"; + case GL_DEBUG_TYPE_MARKER: + return "marker"; + case GL_DEBUG_TYPE_PUSH_GROUP: + return "start of group"; + case GL_DEBUG_TYPE_POP_GROUP: + return "end of group"; + case GL_DEBUG_TYPE_OTHER: + default: + return "other message"; + } +} +} // namespace + +namespace gl +{ + +Debug::Control::Control() {} + +Debug::Control::~Control() {} + +Debug::Control::Control(const Control &other) = default; + +Debug::Group::Group() {} + +Debug::Group::~Group() {} + +Debug::Group::Group(const Group &other) = default; + +Debug::Debug(bool initialDebugState) + : mOutputEnabled(initialDebugState), + mCallbackFunction(nullptr), + mCallbackUserParam(nullptr), + mMessages(), + mMaxLoggedMessages(0), + mOutputSynchronous(false), + mGroups() +{ + pushDefaultGroup(); +} + +Debug::~Debug() {} + +void Debug::setMaxLoggedMessages(GLuint maxLoggedMessages) +{ + mMaxLoggedMessages = maxLoggedMessages; +} + +void Debug::setOutputEnabled(bool enabled) +{ + mOutputEnabled = enabled; +} + +bool Debug::isOutputEnabled() const +{ + return mOutputEnabled; +} + +void Debug::setOutputSynchronous(bool synchronous) +{ + mOutputSynchronous = synchronous; +} + +bool Debug::isOutputSynchronous() const +{ + return mOutputSynchronous; +} + +void Debug::setCallback(GLDEBUGPROCKHR callback, const void *userParam) +{ + mCallbackFunction = callback; + mCallbackUserParam = userParam; +} + +GLDEBUGPROCKHR Debug::getCallback() const +{ + return mCallbackFunction; +} + +const void *Debug::getUserParam() const +{ + return mCallbackUserParam; +} + +void Debug::insertMessage(GLenum source, + GLenum type, + GLuint id, + GLenum severity, + const std::string &message, + gl::LogSeverity logSeverity, + angle::EntryPoint entryPoint) const +{ + std::string messageCopy(message); + insertMessage(source, type, id, severity, std::move(messageCopy), logSeverity, entryPoint); +} + +void Debug::insertMessage(GLenum source, + GLenum type, + GLuint id, + GLenum severity, + std::string &&message, + gl::LogSeverity logSeverity, + angle::EntryPoint entryPoint) const +{ + { + // output all messages to the debug log + const char *messageTypeString = GLMessageTypeToString(type); + const char *severityString = GLSeverityToString(severity); + std::ostringstream messageStream; + if (entryPoint != angle::EntryPoint::GLInvalid) + { + messageStream << GetEntryPointName(entryPoint) << ": "; + } + messageStream << "GL " << messageTypeString << ": " << severityString << ": " << message; + switch (logSeverity) + { + case gl::LOG_FATAL: + FATAL() << messageStream.str(); + break; + case gl::LOG_ERR: + ERR() << messageStream.str(); + break; + case gl::LOG_WARN: + WARN() << messageStream.str(); + break; + case gl::LOG_INFO: + INFO() << messageStream.str(); + break; + case gl::LOG_EVENT: + ANGLE_LOG(EVENT) << messageStream.str(); + break; + } + } + + if (!isMessageEnabled(source, type, id, severity)) + { + return; + } + + if (mCallbackFunction != nullptr) + { + // TODO(geofflang) Check the synchronous flag and potentially flush messages from another + // thread. + mCallbackFunction(source, type, id, severity, static_cast<GLsizei>(message.length()), + message.c_str(), mCallbackUserParam); + } + else + { + if (mMessages.size() >= mMaxLoggedMessages) + { + // Drop messages over the limit + return; + } + + Message m; + m.source = source; + m.type = type; + m.id = id; + m.severity = severity; + m.message = std::move(message); + + mMessages.push_back(std::move(m)); + } +} + +size_t Debug::getMessages(GLuint count, + GLsizei bufSize, + GLenum *sources, + GLenum *types, + GLuint *ids, + GLenum *severities, + GLsizei *lengths, + GLchar *messageLog) +{ + size_t messageCount = 0; + size_t messageStringIndex = 0; + while (messageCount <= count && !mMessages.empty()) + { + const Message &m = mMessages.front(); + + if (messageLog != nullptr) + { + // Check that this message can fit in the message buffer + if (messageStringIndex + m.message.length() + 1 > static_cast<size_t>(bufSize)) + { + break; + } + + std::copy(m.message.begin(), m.message.end(), messageLog + messageStringIndex); + messageStringIndex += m.message.length(); + + messageLog[messageStringIndex] = '\0'; + messageStringIndex += 1; + } + + if (sources != nullptr) + { + sources[messageCount] = m.source; + } + + if (types != nullptr) + { + types[messageCount] = m.type; + } + + if (ids != nullptr) + { + ids[messageCount] = m.id; + } + + if (severities != nullptr) + { + severities[messageCount] = m.severity; + } + + if (lengths != nullptr) + { + lengths[messageCount] = static_cast<GLsizei>(m.message.length()) + 1; + } + + mMessages.pop_front(); + + messageCount++; + } + + return messageCount; +} + +size_t Debug::getNextMessageLength() const +{ + return mMessages.empty() ? 0 : mMessages.front().message.length() + 1; +} + +size_t Debug::getMessageCount() const +{ + return mMessages.size(); +} + +void Debug::setMessageControl(GLenum source, + GLenum type, + GLenum severity, + std::vector<GLuint> &&ids, + bool enabled) +{ + Control c; + c.source = source; + c.type = type; + c.severity = severity; + c.ids = std::move(ids); + c.enabled = enabled; + + auto &controls = mGroups.back().controls; + controls.push_back(std::move(c)); +} + +void Debug::pushGroup(GLenum source, GLuint id, std::string &&message) +{ + insertMessage(source, GL_DEBUG_TYPE_PUSH_GROUP, id, GL_DEBUG_SEVERITY_NOTIFICATION, + std::string(message), gl::LOG_INFO, angle::EntryPoint::GLPushDebugGroup); + + Group g; + g.source = source; + g.id = id; + g.message = std::move(message); + mGroups.push_back(std::move(g)); +} + +void Debug::popGroup() +{ + // Make sure the default group is not about to be popped + ASSERT(mGroups.size() > 1); + + Group g = mGroups.back(); + mGroups.pop_back(); + + insertMessage(g.source, GL_DEBUG_TYPE_POP_GROUP, g.id, GL_DEBUG_SEVERITY_NOTIFICATION, + g.message, gl::LOG_INFO, angle::EntryPoint::GLPopDebugGroup); +} + +size_t Debug::getGroupStackDepth() const +{ + return mGroups.size(); +} + +void Debug::insertPerfWarning(GLenum severity, const char *message, uint32_t *repeatCount) const +{ + bool repeatLast; + + { + constexpr uint32_t kMaxRepeat = 4; + std::lock_guard<std::mutex> lock(GetDebugMutex()); + + if (*repeatCount >= kMaxRepeat) + { + return; + } + + ++*repeatCount; + repeatLast = (*repeatCount == kMaxRepeat); + } + + std::string msg = message; + if (repeatLast) + { + msg += " (this message will no longer repeat)"; + } + + // Release the lock before we call insertMessage. It will re-acquire the lock. + insertMessage(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_PERFORMANCE, 0, severity, std::move(msg), + gl::LOG_INFO, angle::EntryPoint::GLInvalid); +} + +bool Debug::isMessageEnabled(GLenum source, GLenum type, GLuint id, GLenum severity) const +{ + if (!mOutputEnabled) + { + return false; + } + + for (auto groupIter = mGroups.rbegin(); groupIter != mGroups.rend(); groupIter++) + { + const auto &controls = groupIter->controls; + for (auto controlIter = controls.rbegin(); controlIter != controls.rend(); controlIter++) + { + const auto &control = *controlIter; + + if (control.source != GL_DONT_CARE && control.source != source) + { + continue; + } + + if (control.type != GL_DONT_CARE && control.type != type) + { + continue; + } + + if (control.severity != GL_DONT_CARE && control.severity != severity) + { + continue; + } + + if (!control.ids.empty() && + std::find(control.ids.begin(), control.ids.end(), id) == control.ids.end()) + { + continue; + } + + return control.enabled; + } + } + + return true; +} + +void Debug::pushDefaultGroup() +{ + Group g; + g.source = GL_NONE; + g.id = 0; + g.message = ""; + + Control c0; + c0.source = GL_DONT_CARE; + c0.type = GL_DONT_CARE; + c0.severity = GL_DONT_CARE; + c0.enabled = true; + g.controls.push_back(std::move(c0)); + + Control c1; + c1.source = GL_DONT_CARE; + c1.type = GL_DONT_CARE; + c1.severity = GL_DEBUG_SEVERITY_LOW; + c1.enabled = false; + g.controls.push_back(std::move(c1)); + + mGroups.push_back(std::move(g)); +} +} // namespace gl + +namespace egl +{ + +namespace +{ +angle::PackedEnumBitSet<MessageType> GetDefaultMessageTypeBits() +{ + angle::PackedEnumBitSet<MessageType> result; + result.set(MessageType::Critical); + result.set(MessageType::Error); + return result; +} +} // anonymous namespace + +Debug::Debug() : mCallback(nullptr), mEnabledMessageTypes(GetDefaultMessageTypeBits()) {} + +void Debug::setCallback(EGLDEBUGPROCKHR callback, const AttributeMap &attribs) +{ + mCallback = callback; + + const angle::PackedEnumBitSet<MessageType> defaultMessageTypes = GetDefaultMessageTypeBits(); + if (mCallback != nullptr) + { + for (MessageType messageType : angle::AllEnums<MessageType>()) + { + mEnabledMessageTypes[messageType] = + (attribs.getAsInt(egl::ToEGLenum(messageType), defaultMessageTypes[messageType]) == + EGL_TRUE); + } + } +} + +EGLDEBUGPROCKHR Debug::getCallback() const +{ + return mCallback; +} + +bool Debug::isMessageTypeEnabled(MessageType type) const +{ + return mEnabledMessageTypes[type]; +} + +void Debug::insertMessage(EGLenum error, + const char *command, + MessageType messageType, + EGLLabelKHR threadLabel, + EGLLabelKHR objectLabel, + const std::string &message) const +{ + { + // output all messages to the debug log + const char *messageTypeString = EGLMessageTypeToString(messageType); + std::ostringstream messageStream; + messageStream << "EGL " << messageTypeString << ": " << command << ": " << message; + INFO() << messageStream.str(); + } + + // TODO(geofflang): Lock before checking the callback. http://anglebug.com/2464 + if (mCallback && isMessageTypeEnabled(messageType)) + { + mCallback(error, command, egl::ToEGLenum(messageType), threadLabel, objectLabel, + message.c_str()); + } +} + +} // namespace egl |