Класс 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 будет использовать очередь для эмиссии сигналов через потоки, но если вы принудительно устанавливаете тип соединения в прямой, то вы должны быть осведомлены о потенциальных гонках в слотах, подключенных к этому сигналу.
Если регистрация была начата в режиме 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)
Отключает ведение журнала сообщений с заданными sources, types и severities и любым идентификатором сообщения.
Ведение журнала будет отключено в текущей группе управления.
См. также enableMessages(), pushGroup() и popGroup().
void QOpenGLDebugLogger::disableMessages(const QList<GLuint> &ids, QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType)
Отключает ведение журнала сообщений с заданными ids, sources и types и любой severity.
Ведение журнала будет отключено в текущей группе управления.
См. также enableMessages(), pushGroup() и popGroup().
void QOpenGLDebugLogger::enableMessages(QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType, QOpenGLDebugMessage::Severities severities = QOpenGLDebugMessage::AnySeverity)
Включает ведение журнала сообщений из заданных sources, types и severities и любого идентификатора сообщения.
Ведение журнала будет включено в текущей группе управления.
См. также disableMessages(), pushGroup() и popGroup().
void QOpenGLDebugLogger::enableMessages(const QList<GLuint> &ids, QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType)
Включает ведение журнала сообщений с заданными ids, sources и types и любой severity.
Ведение журнала будет включено в текущей группе управления.
См. также 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 и severity 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 и severity 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.1/qopengldebuglogger.html