QOpenGLDebugLogger 类
The QOpenGLDebugLogger enables logging of OpenGL debugging messages. 更多信息...
头文件 | #include <QOpenGLDebugLogger> |
CMake | find_package(Qt6 REQUIRED COMPONENTS OpenGL) target_link_libraries(mytarget PRIVATE Qt6::OpenGL) |
qmake | QT += opengl |
继承 | QObject |
- 包含所有成员的列表,包括继承的成员
- QOpenGLDebugLogger 是 3D 渲染的一部分。3D 渲染.
公共类型
枚举 | LoggingMode { AsynchronousLogging, SynchronousLogging } |
属性
- loggingMode : const LoggingMode
公共函数
QOpenGLDebugLogger(QObject *parent = nullptr) | |
virtual | ~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实现的唯一方法是,在每次调用API之后都使用glGetError
进行检查。此外,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格式选项设置在用于创建QOpenGLContext对象的QSurfaceFormat上。
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();
请注意,请求3.2OpenGL核心配置文件只是为了示例目的;此类不与任何特定的OpenGL或OpenGL ES版本绑定,因为它依赖于GL_KHR_debug
扩展(下面将说明)。
创建和初始化QOpenGLDebugLogger
QOpenGLDebugLogger是一个简单的QObject-派生类。就像所有QObject子类一样,你创建一个实例(可以指定父对象),并且正如Qt中的其他OpenGL函数,你必须在使用前调用initialize()来初始化它。
QOpenGLContext *ctx = QOpenGLContext::currentContext(); QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this); logger->initialize(); // initializes in the current context, i.e. ctx
请注意,要访问OpenGL记录的消息,上下文中必须GL_KHR_debug
扩展必须可用。你可以通过调用它们的存在来检查这个扩展
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上下文绑定的相同线程。
这意味着,在进行同步模式日志记录时,您将能够将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)
- id、源和类型(包括所选的所有严重性)
请注意,特定消息的“启用”状态是(id,源,类型,严重性)元组的属性;消息属性 不 形成一个任何类型的层级结构。应该小心调用 enableMessages() 和 disableMessages() 的顺序,因为它将改变哪些消息被启用/禁用。
无法根据消息文本来进行过滤;应用程序必须自行完成(在连接到 messageLogged() 信号的槽中,或在通过 loggedMessages() 获取内部调试日志后)。
为了简化启用/禁用状态的管理的复杂性,QOpenGLDebugMessage 也支持 调试组
的概念。调试组包含调试消息的启用/禁用配置组。此外,调试组是按堆栈组织的;可以通过调用 pushGroup() 和 popGroup() 分别压栈和出栈组。(当创建OpenGL上下文时,堆栈中已有组)。
函数 enableMessages() 和 disableMessages() 将修改当前调试组的配置,即调试组堆栈顶部的那个。
当新的组被压入调试组堆栈时,它将继承堆栈顶部之前组的配置。反之,出栈调试组将恢复成为新堆栈顶部的调试组的配置。
压入(分别出栈)调试组也将自动生成类型为 QOpenGLDebugMessage::GroupPushType(分别 GroupPopType)的调试信息。
另请参阅 QOpenGLDebugMessage。
成员类型文档
enum QOpenGLDebugLogger::LoggingMode
LoggingMode 枚举定义了日志记录器的日志模式。
常量 | 值 | 描述 |
---|---|---|
QOpenGLDebugLogger::AsynchronousLogging | 0 | OpenGL服务器消息异步记录。这意味着可以在触发相关OpenGL操作的相应OpenGL动作之后一段时间内记录消息,甚至可能以乱序方式接收它们,这取决于OpenGL的实现。由于OpenGL实现高度线程化且异步,此模式具有非常低的性能损失。 |
QOpenGLDebugLogger::SynchronousLogging | 1 | OpenGL服务器的消息是同步且依次记录的。这给性能带来了严重影响,因为OpenGL实施本质上是异步的;但这对调试OpenGL问题非常有用,因为OpenGL保证由OpenGL命令生成的消息在相应命令执行返回之前被记录。因此,您可以在messageLogged()信号上安装断点,并查看堆栈跟踪,以确定哪个OpenGL命令导致它;唯一的缺点是,如果您从多个线程使用OpenGL,则可能需要在连接到messageLogged()信号时强制直接连接。 |
属性文档
[只读]
loggingMode : const LoggingMode
该属性包含传递给startLogging()的记录模式。
注意,必须已开始记录,否则此属性值将无意义。
访问函数
QOpenGLDebugLogger::LoggingMode | loggingMode() const |
另请参阅 startLogging() 和 isLogging()。
成员函数文档
[显式]
QOpenGLDebugLogger::QOpenGLDebugLogger(QObject *parent = nullptr)
构造了一个具有指定parent的新日志记录器对象。
注意:对象必须在记录发生之前初始化。
另请参阅 initialize()。
[虚 noexcept]
QOpenGLDebugLogger::~QOpenGLDebugLogger()
销毁日志记录器对象。
void QOpenGLDebugLogger::disableMessages(QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType, QOpenGLDebugMessage::Severities severities = QOpenGLDebugMessage::AnySeverity)
禁用具有给定、给定和给定以及任何消息ID的消息的记录。
记录将在当前控制组中禁用。
另请参阅 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)
启用给定来源、给定类型和给定严重程度以及任何消息ID的消息日志记录。
日志记录将在当前控制组中启用。
另请参阅disableMessages()、pushGroup()和popGroup()。
void QOpenGLDebugLogger::enableMessages(const QList<GLuint> &ids, QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType)
启用给定ID、给定来源和给定类型以及任何严重程度的消息的日志记录。
日志记录将在当前控制组中启用。
另请参阅disableMessages()、pushGroup()和popGroup()。
bool QOpenGLDebugLogger::initialize()
在当前OpenGL上下文中初始化对象。要成功初始化,上下文必须支持GL_KHR_debug
扩展。必须先初始化对象才能进行任何日志记录。
可以从同一上下文多次安全地调用此函数。
此函数还可以用于更改先前已初始化的对象的上下文;注意,在这种情况下,调用此函数时对象不得正在记录。
如果日志记录器成功初始化,则返回true
;否则返回false
。
另请参阅QOpenGLContext。
bool QOpenGLDebugLogger::isLogging() const
如果此对象当前正在记录,则返回true
;否则返回false
。
另请参阅startLogging。
[slot]
void QOpenGLDebugLogger::logMessage(const QOpenGLDebugMessage &debugMessage)
将消息debugMessage插入OpenGL调试日志中。这为应用程序或库提供了插入有助于简化OpenGL应用程序调试的定制消息的方法。
注意:debugMessage必须具有QOpenGLDebugMessage::ApplicationSource或QOpenGLDebugMessage::ThirdPartySource作为其来源,并且有效的类型和严重程度,否则它将不会插入到日志中。
注意:对象必须在记录发生之前初始化。
另请参阅 initialize()。
QList<QOpenGLDebugMessage> QOpenGLDebugLogger::loggedMessages() const
读取OpenGL内部调试日志中所有可用的消息并将它们返回。此外,此函数还将清除内部调试日志,因此后续调用将不会返回之前已返回的消息。
另请参阅startLogging。
QOpenGLDebugLogger::LoggingMode QOpenGLDebugLogger::loggingMode() const
返回对象的消息记录模式。
注意:获取属性loggingMode的get函数。
另请参阅startLogging。
qint64 QOpenGLDebugLogger::maximumMessageLength() const
返回传递给logMessage()的消息文本的最大支持长度,单位为字节。这也是调试组名的最大长度,因为推送或弹出组会自动记录一个消息,消息文本为调试组名。
如果消息文本过长,它将由QOpenGLDebugLogger自动截断。
注意:当消息传递给OpenGL时,消息文本将使用UTF-8编码,因此其大小(以字节为单位)通常不匹配返回的UTF-16代码单元数,例如,由QString::length()返回的数量。(如果消息仅包含7位ASCII数据,则为典型调试消息,则为匹配。)
[信号]
void QOpenGLDebugLogger::messageLogged(const QOpenGLDebugMessage &debugMessage)
当从OpenGL服务器记录调试消息(由debugMessage参数包装)时,发出此信号。
根据OpenGL实现,此信号可以由接收器所在之外的其他线程发出,甚至可以由初始化此对象的QOpenGLContext所在的线程发出。此外,该信号可能同时由多个线程发出。这通常不是问题,因为Qt将为跨线程信号发射利用队列连接,但如果有力量将连接类型强制为直接连接,则必须意识到连接到此信号槽的潜在竞态条件。
如果日志已经在SynchronousLogging模式下开始,OpenGL保证此信号将从绑定到QOpenGLContext的同一线程发出,并且不会发生并发调用。
注意:必须开始记录,否则不会发出此信号。
另请参阅startLogging。
void QOpenGLDebugLogger::popGroup()
从调试组堆栈中弹出最顶层调试组。如果成功弹出组,OpenGL将自动记录一个与弹出组的消息、id和源匹配的消息,类型为QOpenGLDebugMessage::GroupPopType和严重性QOpenGLDebugMessage::NotificationSeverity。
弹出调试组将恢复成为调试组堆栈顶部的组的消息过滤设置。
注意:在管理调试组之前必须初始化此对象。
另请参阅pushGroup()。
void QOpenGLDebugLogger::pushGroup(const QString &name, GLuint id = 0, QOpenGLDebugMessage::Source source = QOpenGLDebugMessage::ApplicationSource)
将名称为name、id为id和来源为source的调试组推送到调试组堆栈上。如果组成功推送,OpenGL将自动记录带有消息、id、来源、类型为QOpenGLDebugMessage::GroupPushType和严重性为QOpenGLDebugMessage::NotificationSeverity的消息。
新推送的组将继承堆栈顶部组的相同过滤设置;也就是说,推送新的组不会更改过滤设置。
注意: 源必须是QOpenGLDebugMessage::ApplicationSource或QOpenGLDebugMessage::ThirdPartySource,否则组将不会被推送。
注意:在管理调试组之前必须初始化此对象。
另请参阅 popGroup(),enableMessages(),和disableMessages()。
[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。
© 2024 Qt公司。此处包含的文档贡献是各自所有者的版权。此文档是在自由软件基金会发布的GNU自由文档许可证版本1.3的条款下提供的。Qt及其相关标志是芬兰和/或世界上其他国家的Qt公司的商标。所有其他商标是各自所有者的财产。