Класс QOpenGLDebugLogger
Класс QOpenGLDebugLogger позволяет регистрировать сообщения об отладке OpenGL. Подробнее...
| Заголовок: | #include <QOpenGLDebugLogger> |
| CMake: | find_package(Qt6 COMPONENTS OpenGL REQUIRED) target_link_libraries(mytarget PRIVATE Qt6::OpenGL) |
| qmake: | QT += opengl |
| С момента: | Qt 5.1 |
| Наследует: | QObject |
Типы публичного интерфейса
| Перечисление | LoggingMode { AsynchronousLogging, SynchronousLogging } |
Свойства
- loggingMode : const LoggingMode
Открытые функции
| QOpenGLDebugLogger(QObject *parent = nullptr) | |
| виртуальный | ~QOpenGLDebugLogger() |
| void | disableMessages(QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType, QOpenGLDebugMessage::Severities severities = QOpenGLDebugMessage::AnySeverity) |
| void | disableMessages(const QList<GLuint> &ids, QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType) |
| void | enableMessages(QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType, QOpenGLDebugMessage::Severities severities = QOpenGLDebugMessage::AnySeverity) |
| void | enableMessages(const QList<GLuint> &ids, QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType) |
| bool | initialize() |
| bool | isLogging() const |
| QList<QOpenGLDebugMessage> | loggedMessages() const |
| QOpenGLDebugLogger::LoggingMode | loggingMode() const |
| qint64 | maximumMessageLength() const |
| void | popGroup() |
| void | pushGroup(const QString &name, GLuint id = 0, QOpenGLDebugMessage::Source source = QOpenGLDebugMessage::ApplicationSource) |
Открытые слоты
| void | logMessage(const QOpenGLDebugMessage &debugMessage) |
| void | startLogging(QOpenGLDebugLogger::LoggingMode loggingMode = AsynchronousLogging) |
| void | stopLogging() |
Сигналы
| void | messageLogged(const QOpenGLDebugMessage &debugMessage) |
Подробное описание
Введение
Программирование OpenGL может быть очень подвержено ошибкам. Часто одно ошибочное обращение к OpenGL может привести к остановке всего участка приложения без отображения чего-либо на экране.
Единственный способ гарантировать отсутствие ошибок от реализации OpenGL — проверка с glGetError после каждого вызова API. Более того, ошибки OpenGL накапливаются, поэтому glGetError всегда следует использовать в цикле такого типа:
GLenum error = GL_NO_ERROR;
do {
error = glGetError();
if (error != GL_NO_ERROR) {
// handle the error
}
} while (error != GL_NO_ERROR); Если вы пытаетесь очистить стек ошибок, убедитесь, что вы не просто продолжаете, пока не вернется GL_NO_ERROR, но также прерываете на GL_CONTEXT_LOST, так как это значение ошибки будет повторяться.
Существует также много другой информации, которая нас интересует (как разработчиков приложений), например, проблемы с производительностью или предупреждения об использовании устаревших API. Такие сообщения не сообщаются через обычные механизмы отслеживания ошибок OpenGL.
QOpenGLDebugLogger призван решить эти проблемы, предоставив доступ к журналу отладки OpenGL. Если ваша реализация OpenGL поддерживает это (путем экспонирования GL_KHR_debug расширения), сообщения от сервера OpenGL будут либо записаны во внутренний журнал OpenGL, либо переданы «в реальном времени» слушателям по мере их генерации из OpenGL.
QOpenGLDebugLogger поддерживает оба этих режима работы. Обратитесь к следующим разделам, чтобы узнать различия между ними.
Создание контекста OpenGL для отладки
По причинам эффективности реализациям OpenGL разрешается не создавать никакого отладочного вывода, если контекст OpenGL не является контекстом отладки. Чтобы создать контекст отладки из Qt, необходимо установить параметр QSurfaceFormat::DebugContext в формате QSurfaceFormat, используемом для создания объекта QOpenGLContext:
QSurfaceFormat format; // asks for a OpenGL 3.2 debug context using the Core profile format.setMajorVersion(3); format.setMinorVersion(2); format.setProfile(QSurfaceFormat::CoreProfile); format.setOption(QSurfaceFormat::DebugContext); QOpenGLContext *context = new QOpenGLContext; context->setFormat(format); context->create();
Обратите внимание, что запрос профиля OpenGL Core 3.2 используется только для примера; этот класс не привязан к какой-либо конкретной версии OpenGL или OpenGL ES, так как он полагается на доступность GL_KHR_debug расширения (см. ниже).
Создание и инициализация QOpenGLDebugLogger
QOpenGLDebugLogger — это простой класс, производный от QObject. Как и все подклассы QObject, вы создаёте экземпляр (и необязательно указываете родительский объект), и, как и другие функции OpenGL в Qt, вы обязательно должны его инициализировать, вызвав initialize() в то время, когда существует текущий контекст OpenGL:
QOpenGLContext *ctx = QOpenGLContext::currentContext(); QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this); logger->initialize(); // initializes in the current context, i.e. ctx
Обратите внимание, что GL_KHR_debug расширение должно быть доступно в контексте для доступа к сообщениям, зарегистрированным OpenGL. Вы можете проверить наличие этого расширения, вызвав:
ctx->hasExtension(QByteArrayLiteral("GL_KHR_debug")); где ctx является допустимым QOpenGLContext. Если расширение недоступно, initialize() вернёт false.
Чтение внутреннего журнала отладки OpenGL
Реализации OpenGL сохраняют внутренний журнал сообщений об отладке. Сообщения, хранящиеся в этом журнале, могут быть получены с помощью функции loggedMessages():
const QList<QOpenGLDebugMessage> messages = logger->loggedMessages();
for (const QOpenGLDebugMessage &message : messages)
qDebug() << message; Внутренний журнал имеет ограниченный размер; при заполнении более старые сообщения будут удалены, чтобы освободить место для новых входящих сообщений. Когда вы вызываете loggedMessages(), внутренний журнал также будет очищен.
Если вы хотите убедиться, что не потеряете ни одного сообщения об отладке, вам необходимо использовать протоколирование в реальном времени вместо вызова этой функции. Однако сообщения об отладке всё ещё могут генерироваться в промежутке времени между созданием контекста и активацией протоколирования в реальном времени (или, в общем случае, когда протоколирование в реальном времени отключено).
Протоколирование сообщений в реальном времени
Также можно получать поток сообщений об отладке с сервера OpenGL по мере их генерации реализацией. Для этого вам необходимо подключить соответствующий слот к сигналу messageLogged() и начать протоколирование, вызвав startLogging():
connect(logger, &QOpenGLDebugLogger::messageLogged, receiver, &LogHandler::handleLoggedMessage); logger->startLogging();
Аналогично, протоколирование можно отключить в любое время, вызвав функцию stopLogging().
Протоколирование в реальном времени может быть асинхронным или синхронным в зависимости от параметра, передаваемого в startLogging(). При протоколировании в асинхронном режиме (по умолчанию, так как имеет очень небольшую нагрузку) реализация OpenGL может генерировать сообщения в любое время и/или в порядке, отличном от порядка команд OpenGL, вызвавших эти сообщения. Сообщения также могут генерироваться из потока, отличного от потока, к которому в данный момент привязан контекст. Это связано с тем, что реализации OpenGL обычно высокопоточные и асинхронные, и поэтому никаких гарантий относительно относительного порядка и временных характеристик сообщений об отладке не предоставляется.
С другой стороны, протоколирование в синхронном режиме имеет высокую нагрузку, но реализация OpenGL гарантирует, что все сообщения, вызванные определённой командой, получены в порядке, до возврата команды и из того же потока, к которому привязан контекст OpenGL.
END_OF_DOCUMENT_MARKERЭто означает, что при входе в синхронном режиме вы сможете запустить свое приложение OpenGL в отладчике, установить контрольную точку на слот, подключенный к сигналу messageLogged(), и увидеть в стеке вызовов точное вызов, который вызвал зарегистрированное сообщение. Это может быть чрезвычайно полезно для отладки проблемы с OpenGL. Обратите внимание, что если отрисовка OpenGL происходит в другом потоке, вы должны принудительно установить тип подключения сигнала/слота на Qt::DirectConnection, чтобы увидеть фактический стек вызовов.
Дополнительную информацию о режимах регистрации см. в документации по перечислению LoggingMode.
Примечание: При включении регистрации в реальном времени сообщения об отладке не будут вставляться в внутренний журнал отладки OpenGL; сообщения, уже присутствующие во внутреннем журнале, не будут удалены, а также не будут отправлены через сигнал messageLogged(). Поскольку некоторые сообщения могут быть сгенерированы до начала регистрации в реальном времени (и поэтому будут сохранены во внутреннем журнале OpenGL), важно всегда проверять, содержит ли он какие-либо сообщения после вызова startLogging().
Вставка сообщений в журнал отладки
Приложения и библиотеки могут вставлять пользовательские сообщения в журнал отладки, например, для маркировки группы связанных команд OpenGL и, следовательно, для возможности идентификации возможных сообщений, исходящих от них.
Для этого вы можете создать объект QOpenGLDebugMessage, вызвав createApplicationMessage() или createThirdPartyMessage(), а затем вставить его в журнал, вызвав logMessage():
QOpenGLDebugMessage message =
QOpenGLDebugMessage::createApplicationMessage(QStringLiteral("Custom message"));
logger->logMessage(message); Обратите внимание, что у реализаций OpenGL есть зависящая от поставщика ограничение на длину сообщений, которые можно вставить в журнал отладки. Вы можете получить эту длину, вызвав метод maximumMessageLength(); сообщения, длиннее ограничения, автоматически усекаются.
Управление выводом отладки
QOpenGLDebugMessage также может применять фильтры к сообщениям об отладке и, следовательно, ограничивать количество регистрируемых сообщений. Вы можете включить или отключить регистрацию сообщений, вызвав соответственно enableMessages() и disableMessages(). По умолчанию все сообщения регистрируются.
Включить или отключить сообщения можно, выбрав их по:
- источнику, типу и степени серьезности (и включив все идентификаторы в выбор);
- идентификатору, источнику и типу (и включив все степени серьезности в выбор).
Обратите внимание, что состояние «включено» для данного сообщения является свойством кортежа (id, источник, тип, степень серьезности); атрибуты сообщения не образуют иерархии какого-либо вида. Вы должны быть внимательны к порядку вызовов enableMessages() и disableMessages(), поскольку это изменит, какие сообщения будут включены/отключены.
Отфильтровать по самому тексту сообщения нельзя; приложения должны это делать самостоятельно (в слотах, подключенных к сигналу messageLogged(), или после извлечения сообщений из внутреннего журнала отладки с помощью loggedMessages() ).
Для упрощения управления включенными/выключенными состояниями QOpenGLDebugMessage также поддерживает концепцию debug groups. Группа отладки содержит группу включенных/выключенных конфигураций сообщений об отладке. Кроме того, группы отладки организованы в стеке: можно добавить и удалить группы, вызвав соответственно pushGroup() и popGroup(). (При создании контекста OpenGL в стеке уже есть группа).
Функции enableMessages() и disableMessages() изменят конфигурацию в текущей группе отладки, то есть в той, которая находится вверху стека групп отладки.
Когда новая группа добавляется в стек групп отладки, она наследует конфигурацию группы, которая ранее находилась на вершине стека. Аналогично, удаление группы отладки восстановит конфигурацию группы отладки, которая станет новой верхней.
Добавление (соответственно удаление) групп отладки также автоматически генерирует сообщение об отладке типа QOpenGLDebugMessage::GroupPushType (соответственно GroupPopType).
См. также QOpenGLDebugMessage.
Документация по типам членов
перечисление QOpenGLDebugLogger::LoggingMode
Перечисление LoggingMode определяет режим регистрации объекта-регистратора.
| Константа | Значение | Описание |
|---|---|---|
QOpenGLDebugLogger::AsynchronousLogging |
0 |
Сообщения от сервера OpenGL регистрируются асинхронно. Это означает, что сообщения могут регистрироваться некоторое время после соответствующих действий OpenGL, которые их вызвали, и даже быть получены в произвольном порядке, в зависимости от реализации OpenGL. Этот режим имеет очень небольшую нагрузку на производительность, так как реализации OpenGL по своей природе сильно многопоточны и асинхронны. |
QOpenGLDebugLogger::SynchronousLogging |
1 |
Сообщения от сервера OpenGL регистрируются синхронно и последовательно. Это приводит к значительному снижению производительности, так как реализации OpenGL по своей природе очень асинхронны; но это очень полезно для отладки проблем OpenGL, так как OpenGL гарантирует, что сообщения, сгенерированные командой OpenGL, будут зарегистрированы до того, как вернется выполнение соответствующей команды. Таким образом, вы можете установить контрольную точку на сигнал messageLogged() и увидеть в стеке вызовов, какая команда OpenGL ее вызвала; единственное предостережение заключается в том, что если вы используете OpenGL из нескольких потоков, вам может потребоваться принудительное прямое соединение при подключении к сигналу messageLogged(). |
Документация по свойствам
[read-only] loggingMode : const LoggingMode
Это свойство содержит режим регистрации, переданный в startLogging().
Обратите внимание, что регистрация должна быть начата, иначе значение этого свойства не будет иметь смысла.
Функции доступа:
| QOpenGLDebugLogger::LoggingMode | loggingMode() const |
См. также startLogging() и isLogging().
Документация по функциям членов
QOpenGLDebugLogger::QOpenGLDebugLogger(QObject *parent = nullptr)
Создает новый объект-регистратор с заданным parent.
Примечание: Объект должен быть инициализирован, прежде чем сможет произойти регистрация.
См. также initialize().
[slot] void QOpenGLDebugLogger::logMessage(const QOpenGLDebugMessage &debugMessage)
Вставляет сообщение debugMessage в журнал отладки OpenGL. Это предоставляет способ для приложений или библиотек вставлять пользовательские сообщения, которые могут облегчить отладку приложений OpenGL.
Примечание: debugMessage должен иметь QOpenGLDebugMessage::ApplicationSource или QOpenGLDebugMessage::ThirdPartySource в качестве источника и действительный тип и степень серьезности, иначе он не будет вставлен в журнал.
Примечание: Объект должен быть инициализирован, прежде чем сможет произойти регистрация.
См. также initialize().
[signal] void QOpenGLDebugLogger::messageLogged(const QOpenGLDebugMessage &debugMessage)
Этот сигнал генерируется, когда сообщение об отладке (охваченное аргументом debugMessage) регистрируется с сервера OpenGL.
В зависимости от реализации OpenGL этот сигнал может испускаться из других потоков, помимо того, в котором (или которых) находится (находятся) получатель(и), а также отличаться от потока, в котором находится QOpenGLContext, в котором был инициализирован этот объект. Более того, сигнал может генерироваться из нескольких потоков одновременно. Обычно это не проблема, так как Qt будет использовать очереди для перекрестных сигналов потоков, но если вы принудительно зададите тип соединения как Direct, то вы должны быть осведомлены о потенциальных гонках в слотах, подключенных к этому сигналу.
Если регистрация была начата в режиме SynchronousLogging, OpenGL гарантирует, что этот сигнал будет испущен из того же потока, к которому привязан QOpenGLContext, и одновременные вызовы никогда не будут происходить.
Примечание: Регистрация должна быть начата, иначе этот сигнал не будет генерироваться.
См. также startLogging().
[slot] void QOpenGLDebugLogger::startLogging(QOpenGLDebugLogger::LoggingMode loggingMode = AsynchronousLogging)
Начинает регистрацию сообщений, поступающих от сервера OpenGL. При получении нового сообщения генерируется сигнал messageLogged(), несущий зарегистрированное сообщение в качестве аргумента.
loggingMode определяет, должна ли регистрация быть асинхронной (по умолчанию) или синхронной.
QOpenGLDebugLogger будет записывать значения GL_DEBUG_OUTPUT и GL_DEBUG_OUTPUT_SYNCHRONOUS при запуске регистрации, и возвращать их при остановке регистрации. Кроме того, любой пользовательский обратный вызов отладки OpenGL, установленный при вызове этой функции, будет восстановлен при остановке регистрации; QOpenGLDebugLogger гарантирует, что предварительно существовавший обратный вызов по-прежнему будет вызван при регистрации.
Примечание: Невозможно изменить режим регистрации без остановки и повторного запуска регистрации. Это может измениться в будущей версии Qt.
Примечание: Объект должен быть инициализирован перед началом регистрации.
См. также stopLogging() и initialize().
[slot] void QOpenGLDebugLogger::stopLogging()
Останавливает регистрацию сообщений с сервера OpenGL.
См. также startLogging().
[virtual] QOpenGLDebugLogger::~QOpenGLDebugLogger()
Удаляет объект логгера.
void QOpenGLDebugLogger::disableMessages(QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType, QOpenGLDebugMessage::Severities severities = QOpenGLDebugMessage::AnySeverity)
Отключает регистрацию сообщений с заданными источниками, типами и степенями серьезности и любым идентификатором сообщения.
Регистрация будет отключена в текущей группе управления.
См. также enableMessages(), pushGroup() и popGroup().
void QOpenGLDebugLogger::disableMessages(const QList<GLuint> &ids, QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType)
Отключает регистрацию сообщений с заданными идентификаторами, источниками и типами и любой степенью серьезности.
Регистрация будет отключена в текущей группе управления.
См. также enableMessages(), pushGroup() и popGroup().
void QOpenGLDebugLogger::enableMessages(QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType, QOpenGLDebugMessage::Severities severities = QOpenGLDebugMessage::AnySeverity)
Включает регистрацию сообщений из указанных источников, типов и степеней серьезности и любого идентификатора сообщения.
Регистрация будет включена в текущей группе управления.
См. также disableMessages(), pushGroup() и popGroup().
void QOpenGLDebugLogger::enableMessages(const QList<GLuint> &ids, QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType)
Включает регистрацию сообщений с указанными идентификаторами, источниками и типами и любой степенью серьезности.
Регистрация будет включена в текущей группе управления.
См. также disableMessages(), pushGroup() и popGroup().
bool QOpenGLDebugLogger::initialize()
Инициализирует объект в текущем контексте OpenGL. Контекст должен поддерживать расширение GL_KHR_debug для успешной инициализации. Объект должен быть инициализирован перед любой регистрацией.
Безопасно вызывать эту функцию несколько раз из одного контекста.
Также можно использовать эту функцию для изменения контекста ранее инициализированного объекта; обратите внимание, что в этом случае объект не должен регистрироваться при вызове этой функции.
Возвращает true если логгер успешно инициализирован; в противном случае — false.
См. также QOpenGLContext.
bool QOpenGLDebugLogger::isLogging() const
Возвращает true если этот объект в настоящее время регистрирует, в противном случае — false.
См. также startLogging().
QList<QOpenGLDebugMessage> QOpenGLDebugLogger::loggedMessages() const
Считывает все доступные сообщения в внутреннем журнале отладки OpenGL и возвращает их. Кроме того, эта функция очистит внутренний журнал отладки, так что последующие вызовы не будут возвращать сообщения, которые уже были возвращены.
См. также startLogging().
QOpenGLDebugLogger::LoggingMode QOpenGLDebugLogger::loggingMode() const
Возвращает режим регистрации объекта.
Примечание: Функция-получатель для свойства loggingMode.
См. также startLogging().
qint64 QOpenGLDebugLogger::maximumMessageLength() const
Возвращает максимальную поддерживаемую длину в байтах для текста сообщений, передаваемых в logMessage(). Это также максимальная длина имени группы отладки, так как добавление или удаление групп автоматически приведет к регистрации сообщения с именем группы отладки в качестве текста сообщения.
Если текст сообщения слишком длинный, он будет автоматически усечен классом QOpenGLDebugLogger.
Примечание: Тексты сообщений кодируются в UTF-8 при передаче в OpenGL, поэтому их размер в байтах обычно не совпадает с количеством единиц UTF-16, возвращаемых, например, функцией QString::length(). (Это так, если сообщение содержит только данные 7-битного ASCII, что типично для сообщений отладки.)
void QOpenGLDebugLogger::popGroup()
Удаляет верхнюю группу отладки из стека групп отладки. Если группа успешно удалена, OpenGL автоматически запишет сообщение с идентификатором и источником, соответствующими удаленной группе, типом QOpenGLDebugMessage::GroupPopType и степенью серьезности QOpenGLDebugMessage::NotificationSeverity.
Удаление группы отладки восстановит настройки фильтрации сообщений для группы, которая становится верхней в стеке групп отладки.
Примечание: Объект должен быть инициализирован перед управлением группами отладки.
См. также pushGroup().
void QOpenGLDebugLogger::pushGroup(const QString &name, GLuint id = 0, QOpenGLDebugMessage::Source source = QOpenGLDebugMessage::ApplicationSource)
Добавляет группу отладки с именем name, идентификатором id и источником source в стек групп отладки. Если группа успешно добавлена, OpenGL автоматически запишет сообщение с именем name, идентификатором id, источником source, типом QOpenGLDebugMessage::GroupPushType и степенью серьезности QOpenGLDebugMessage::NotificationSeverity.
Новая добавленная группа унаследует те же настройки фильтрации, что и группа, которая находилась на вершине стека; то есть, добавление новой группы не изменит фильтрацию.
Примечание: source должен быть либо QOpenGLDebugMessage::ApplicationSource, либо QOpenGLDebugMessage::ThirdPartySource, в противном случае группа не будет добавлена.
Примечание: Объект должен быть инициализирован перед управлением группами отладки.
См. также popGroup(), enableMessages() и disableMessages().
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-6.2/qopengldebuglogger.html