tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Debug.cpp (13268B)


      1 //
      2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
      3 // Use of this source code is governed by a BSD-style license that can be
      4 // found in the LICENSE file.
      5 //
      6 
      7 // Debug.cpp: Defines debug state used for GL_KHR_debug
      8 
      9 #include "libANGLE/Debug.h"
     10 
     11 #include "common/debug.h"
     12 
     13 #include <algorithm>
     14 #include <tuple>
     15 
     16 namespace
     17 {
     18 const char *GLSeverityToString(GLenum severity)
     19 {
     20    switch (severity)
     21    {
     22        case GL_DEBUG_SEVERITY_HIGH:
     23            return "HIGH";
     24        case GL_DEBUG_SEVERITY_MEDIUM:
     25            return "MEDIUM";
     26        case GL_DEBUG_SEVERITY_LOW:
     27            return "LOW";
     28        case GL_DEBUG_SEVERITY_NOTIFICATION:
     29        default:
     30            return "NOTIFICATION";
     31    }
     32 }
     33 
     34 const char *EGLMessageTypeToString(egl::MessageType messageType)
     35 {
     36    switch (messageType)
     37    {
     38        case egl::MessageType::Critical:
     39            return "CRITICAL";
     40        case egl::MessageType::Error:
     41            return "ERROR";
     42        case egl::MessageType::Warn:
     43            return "WARNING";
     44        case egl::MessageType::Info:
     45        default:
     46            return "INFO";
     47    }
     48 }
     49 
     50 const char *GLMessageTypeToString(GLenum type)
     51 {
     52    switch (type)
     53    {
     54        case GL_DEBUG_TYPE_ERROR:
     55            return "error";
     56        case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
     57            return "deprecated behavior";
     58        case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
     59            return "undefined behavior";
     60        case GL_DEBUG_TYPE_PORTABILITY:
     61            return "portability";
     62        case GL_DEBUG_TYPE_PERFORMANCE:
     63            return "performance";
     64        case GL_DEBUG_TYPE_MARKER:
     65            return "marker";
     66        case GL_DEBUG_TYPE_PUSH_GROUP:
     67            return "start of group";
     68        case GL_DEBUG_TYPE_POP_GROUP:
     69            return "end of group";
     70        case GL_DEBUG_TYPE_OTHER:
     71        default:
     72            return "other message";
     73    }
     74 }
     75 }  // namespace
     76 
     77 namespace gl
     78 {
     79 
     80 Debug::Control::Control() {}
     81 
     82 Debug::Control::~Control() {}
     83 
     84 Debug::Control::Control(const Control &other) = default;
     85 
     86 Debug::Group::Group() {}
     87 
     88 Debug::Group::~Group() {}
     89 
     90 Debug::Group::Group(const Group &other) = default;
     91 
     92 Debug::Debug(bool initialDebugState)
     93    : mOutputEnabled(initialDebugState),
     94      mCallbackFunction(nullptr),
     95      mCallbackUserParam(nullptr),
     96      mMessages(),
     97      mMaxLoggedMessages(0),
     98      mOutputSynchronous(false),
     99      mGroups()
    100 {
    101    pushDefaultGroup();
    102 }
    103 
    104 Debug::~Debug() {}
    105 
    106 void Debug::setMaxLoggedMessages(GLuint maxLoggedMessages)
    107 {
    108    mMaxLoggedMessages = maxLoggedMessages;
    109 }
    110 
    111 void Debug::setOutputEnabled(bool enabled)
    112 {
    113    mOutputEnabled = enabled;
    114 }
    115 
    116 bool Debug::isOutputEnabled() const
    117 {
    118    return mOutputEnabled;
    119 }
    120 
    121 void Debug::setOutputSynchronous(bool synchronous)
    122 {
    123    mOutputSynchronous = synchronous;
    124 }
    125 
    126 bool Debug::isOutputSynchronous() const
    127 {
    128    return mOutputSynchronous;
    129 }
    130 
    131 void Debug::setCallback(GLDEBUGPROCKHR callback, const void *userParam)
    132 {
    133    mCallbackFunction  = callback;
    134    mCallbackUserParam = userParam;
    135 }
    136 
    137 GLDEBUGPROCKHR Debug::getCallback() const
    138 {
    139    return mCallbackFunction;
    140 }
    141 
    142 const void *Debug::getUserParam() const
    143 {
    144    return mCallbackUserParam;
    145 }
    146 
    147 void Debug::insertMessage(GLenum source,
    148                          GLenum type,
    149                          GLuint id,
    150                          GLenum severity,
    151                          const std::string &message,
    152                          gl::LogSeverity logSeverity,
    153                          angle::EntryPoint entryPoint) const
    154 {
    155    std::string messageCopy(message);
    156    insertMessage(source, type, id, severity, std::move(messageCopy), logSeverity, entryPoint);
    157 }
    158 
    159 void Debug::insertMessage(GLenum source,
    160                          GLenum type,
    161                          GLuint id,
    162                          GLenum severity,
    163                          std::string &&message,
    164                          gl::LogSeverity logSeverity,
    165                          angle::EntryPoint entryPoint) const
    166 {
    167    {
    168        // output all messages to the debug log
    169        const char *messageTypeString = GLMessageTypeToString(type);
    170        const char *severityString    = GLSeverityToString(severity);
    171        std::ostringstream messageStream;
    172        if (entryPoint != angle::EntryPoint::GLInvalid)
    173        {
    174            messageStream << GetEntryPointName(entryPoint) << ": ";
    175        }
    176        messageStream << "GL " << messageTypeString << ": " << severityString << ": " << message;
    177        switch (logSeverity)
    178        {
    179            case gl::LOG_FATAL:
    180                FATAL() << messageStream.str();
    181                break;
    182            case gl::LOG_ERR:
    183                ERR() << messageStream.str();
    184                break;
    185            case gl::LOG_WARN:
    186                WARN() << messageStream.str();
    187                break;
    188            case gl::LOG_INFO:
    189                INFO() << messageStream.str();
    190                break;
    191            case gl::LOG_EVENT:
    192                ANGLE_LOG(EVENT) << messageStream.str();
    193                break;
    194        }
    195    }
    196 
    197    if (!isMessageEnabled(source, type, id, severity))
    198    {
    199        return;
    200    }
    201 
    202    if (mCallbackFunction != nullptr)
    203    {
    204        // TODO(geofflang) Check the synchronous flag and potentially flush messages from another
    205        // thread.
    206        mCallbackFunction(source, type, id, severity, static_cast<GLsizei>(message.length()),
    207                          message.c_str(), mCallbackUserParam);
    208    }
    209    else
    210    {
    211        if (mMessages.size() >= mMaxLoggedMessages)
    212        {
    213            // Drop messages over the limit
    214            return;
    215        }
    216 
    217        Message m;
    218        m.source   = source;
    219        m.type     = type;
    220        m.id       = id;
    221        m.severity = severity;
    222        m.message  = std::move(message);
    223 
    224        mMessages.push_back(std::move(m));
    225    }
    226 }
    227 
    228 size_t Debug::getMessages(GLuint count,
    229                          GLsizei bufSize,
    230                          GLenum *sources,
    231                          GLenum *types,
    232                          GLuint *ids,
    233                          GLenum *severities,
    234                          GLsizei *lengths,
    235                          GLchar *messageLog)
    236 {
    237    size_t messageCount       = 0;
    238    size_t messageStringIndex = 0;
    239    while (messageCount <= count && !mMessages.empty())
    240    {
    241        const Message &m = mMessages.front();
    242 
    243        if (messageLog != nullptr)
    244        {
    245            // Check that this message can fit in the message buffer
    246            if (messageStringIndex + m.message.length() + 1 > static_cast<size_t>(bufSize))
    247            {
    248                break;
    249            }
    250 
    251            std::copy(m.message.begin(), m.message.end(), messageLog + messageStringIndex);
    252            messageStringIndex += m.message.length();
    253 
    254            messageLog[messageStringIndex] = '\0';
    255            messageStringIndex += 1;
    256        }
    257 
    258        if (sources != nullptr)
    259        {
    260            sources[messageCount] = m.source;
    261        }
    262 
    263        if (types != nullptr)
    264        {
    265            types[messageCount] = m.type;
    266        }
    267 
    268        if (ids != nullptr)
    269        {
    270            ids[messageCount] = m.id;
    271        }
    272 
    273        if (severities != nullptr)
    274        {
    275            severities[messageCount] = m.severity;
    276        }
    277 
    278        if (lengths != nullptr)
    279        {
    280            lengths[messageCount] = static_cast<GLsizei>(m.message.length()) + 1;
    281        }
    282 
    283        mMessages.pop_front();
    284 
    285        messageCount++;
    286    }
    287 
    288    return messageCount;
    289 }
    290 
    291 size_t Debug::getNextMessageLength() const
    292 {
    293    return mMessages.empty() ? 0 : mMessages.front().message.length() + 1;
    294 }
    295 
    296 size_t Debug::getMessageCount() const
    297 {
    298    return mMessages.size();
    299 }
    300 
    301 void Debug::setMessageControl(GLenum source,
    302                              GLenum type,
    303                              GLenum severity,
    304                              std::vector<GLuint> &&ids,
    305                              bool enabled)
    306 {
    307    Control c;
    308    c.source   = source;
    309    c.type     = type;
    310    c.severity = severity;
    311    c.ids      = std::move(ids);
    312    c.enabled  = enabled;
    313 
    314    auto &controls = mGroups.back().controls;
    315    controls.push_back(std::move(c));
    316 }
    317 
    318 void Debug::pushGroup(GLenum source, GLuint id, std::string &&message)
    319 {
    320    insertMessage(source, GL_DEBUG_TYPE_PUSH_GROUP, id, GL_DEBUG_SEVERITY_NOTIFICATION,
    321                  std::string(message), gl::LOG_INFO, angle::EntryPoint::GLPushDebugGroup);
    322 
    323    Group g;
    324    g.source  = source;
    325    g.id      = id;
    326    g.message = std::move(message);
    327    mGroups.push_back(std::move(g));
    328 }
    329 
    330 void Debug::popGroup()
    331 {
    332    // Make sure the default group is not about to be popped
    333    ASSERT(mGroups.size() > 1);
    334 
    335    Group g = mGroups.back();
    336    mGroups.pop_back();
    337 
    338    insertMessage(g.source, GL_DEBUG_TYPE_POP_GROUP, g.id, GL_DEBUG_SEVERITY_NOTIFICATION,
    339                  g.message, gl::LOG_INFO, angle::EntryPoint::GLPopDebugGroup);
    340 }
    341 
    342 size_t Debug::getGroupStackDepth() const
    343 {
    344    return mGroups.size();
    345 }
    346 
    347 void Debug::insertPerfWarning(GLenum severity, const char *message, uint32_t *repeatCount) const
    348 {
    349    bool repeatLast;
    350 
    351    {
    352        constexpr uint32_t kMaxRepeat = 4;
    353        std::lock_guard<std::mutex> lock(GetDebugMutex());
    354 
    355        if (*repeatCount >= kMaxRepeat)
    356        {
    357            return;
    358        }
    359 
    360        ++*repeatCount;
    361        repeatLast = (*repeatCount == kMaxRepeat);
    362    }
    363 
    364    std::string msg = message;
    365    if (repeatLast)
    366    {
    367        msg += " (this message will no longer repeat)";
    368    }
    369 
    370    // Release the lock before we call insertMessage. It will re-acquire the lock.
    371    insertMessage(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_PERFORMANCE, 0, severity, std::move(msg),
    372                  gl::LOG_INFO, angle::EntryPoint::GLInvalid);
    373 }
    374 
    375 bool Debug::isMessageEnabled(GLenum source, GLenum type, GLuint id, GLenum severity) const
    376 {
    377    if (!mOutputEnabled)
    378    {
    379        return false;
    380    }
    381 
    382    for (auto groupIter = mGroups.rbegin(); groupIter != mGroups.rend(); groupIter++)
    383    {
    384        const auto &controls = groupIter->controls;
    385        for (auto controlIter = controls.rbegin(); controlIter != controls.rend(); controlIter++)
    386        {
    387            const auto &control = *controlIter;
    388 
    389            if (control.source != GL_DONT_CARE && control.source != source)
    390            {
    391                continue;
    392            }
    393 
    394            if (control.type != GL_DONT_CARE && control.type != type)
    395            {
    396                continue;
    397            }
    398 
    399            if (control.severity != GL_DONT_CARE && control.severity != severity)
    400            {
    401                continue;
    402            }
    403 
    404            if (!control.ids.empty() &&
    405                std::find(control.ids.begin(), control.ids.end(), id) == control.ids.end())
    406            {
    407                continue;
    408            }
    409 
    410            return control.enabled;
    411        }
    412    }
    413 
    414    return true;
    415 }
    416 
    417 void Debug::pushDefaultGroup()
    418 {
    419    Group g;
    420    g.source  = GL_NONE;
    421    g.id      = 0;
    422    g.message = "";
    423 
    424    Control c0;
    425    c0.source   = GL_DONT_CARE;
    426    c0.type     = GL_DONT_CARE;
    427    c0.severity = GL_DONT_CARE;
    428    c0.enabled  = true;
    429    g.controls.push_back(std::move(c0));
    430 
    431    Control c1;
    432    c1.source   = GL_DONT_CARE;
    433    c1.type     = GL_DONT_CARE;
    434    c1.severity = GL_DEBUG_SEVERITY_LOW;
    435    c1.enabled  = false;
    436    g.controls.push_back(std::move(c1));
    437 
    438    mGroups.push_back(std::move(g));
    439 }
    440 }  // namespace gl
    441 
    442 namespace egl
    443 {
    444 
    445 namespace
    446 {
    447 angle::PackedEnumBitSet<MessageType> GetDefaultMessageTypeBits()
    448 {
    449    angle::PackedEnumBitSet<MessageType> result;
    450    result.set(MessageType::Critical);
    451    result.set(MessageType::Error);
    452    return result;
    453 }
    454 }  // anonymous namespace
    455 
    456 Debug::Debug() : mCallback(nullptr), mEnabledMessageTypes(GetDefaultMessageTypeBits()) {}
    457 
    458 void Debug::setCallback(EGLDEBUGPROCKHR callback, const AttributeMap &attribs)
    459 {
    460    mCallback = callback;
    461 
    462    const angle::PackedEnumBitSet<MessageType> defaultMessageTypes = GetDefaultMessageTypeBits();
    463    if (mCallback != nullptr)
    464    {
    465        for (MessageType messageType : angle::AllEnums<MessageType>())
    466        {
    467            mEnabledMessageTypes[messageType] =
    468                (attribs.getAsInt(egl::ToEGLenum(messageType), defaultMessageTypes[messageType]) ==
    469                 EGL_TRUE);
    470        }
    471    }
    472 }
    473 
    474 EGLDEBUGPROCKHR Debug::getCallback() const
    475 {
    476    return mCallback;
    477 }
    478 
    479 bool Debug::isMessageTypeEnabled(MessageType type) const
    480 {
    481    return mEnabledMessageTypes[type];
    482 }
    483 
    484 void Debug::insertMessage(EGLenum error,
    485                          const char *command,
    486                          MessageType messageType,
    487                          EGLLabelKHR threadLabel,
    488                          EGLLabelKHR objectLabel,
    489                          const std::string &message) const
    490 {
    491    {
    492        // output all messages to the debug log
    493        const char *messageTypeString = EGLMessageTypeToString(messageType);
    494        std::ostringstream messageStream;
    495        messageStream << "EGL " << messageTypeString << ": " << command << ": " << message;
    496        INFO() << messageStream.str();
    497    }
    498 
    499    // TODO(geofflang): Lock before checking the callback. http://anglebug.com/2464
    500    if (mCallback && isMessageTypeEnabled(messageType))
    501    {
    502        mCallback(error, command, egl::ToEGLenum(messageType), threadLabel, objectLabel,
    503                  message.c_str());
    504    }
    505 }
    506 
    507 }  // namespace egl