QOpenGLDebugLogger Class

QOpenGLDebugLogger 可记录 OpenGL 调试信息。更多

头文件: #include <QOpenGLDebugLogger>
CMake: find_package(Qt6 REQUIRED COMPONENTS OpenGL)
target_link_libraries(mytarget PRIVATE Qt6::OpenGL)
qmake: QT += opengl
继承: QObject

公共类型

enum LoggingMode { AsynchronousLogging, SynchronousLogging }

属性

公共职能

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 XML 创建调试上下文,必须在用于创建QOpenGLContext 对象的QSurfaceFormat 上设置QSurfaceFormat::DebugContext 格式选项:

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.2 OpenGL Core Profile 仅用于示例目的;该类与任何特定的 OpenGL 或 OpenGL ES 版本无关,因为它依赖于GL_KHR_debug 扩展(见下文)的可用性。

创建和初始化 QOpenGLDebugLogger

QOpenGLDebugLogger 是一个简单的QObject 派生类。与所有QObject 子类一样,您需要创建一个实例(可选择指定一个父对象),并且与 Qt XML 中的其他 OpenGL 函数一样,您必须在使用前通过调用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() 函数检索日志中存储的信息:

常量QList<QOpenGLDebugMessage>messages=  logger->loggedMessages();for(constQOpenGLDebugMessage&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 命令,从而能够识别来自这些命令的最终信息。

为此,可以调用createApplicationMessage() 或createThirdPartyMessage() 创建QOpenGLDebugMessage 对象,然后调用logMessage() 将其插入日志:

QOpenGLDebugMessage message =
    QOpenGLDebugMessage::createApplicationMessage(QStringLiteral("Custom message"));

logger->logMessage(message);

请注意,OpenGL 实现对可插入调试日志的信息长度有特定于供应商的限制。您可以通过调用maximumMessageLength() 方法获取该长度;长度超过限制的信息将自动被截断。

控制调试输出

QOpenGLDebugMessage 调试程序还可以对调试信息进行过滤,从而限制记录的信息量。你可以分别调用 () 和 () 来启用或禁用信息记录。默认情况下,所有信息都会被记录。enableMessages disableMessages

可以通过以下方式启用或禁用信息记录

  • 来源、类型和严重性(包括选择中的所有 id);
  • id、来源和类型(包括选择中的所有严重性)。

请注意,给定邮件的 "启用 "状态是(id、来源、类型、严重性)元组的属性;邮件属性构成任何层次结构。调用enableMessages() 和disableMessages() 时应注意调用顺序,因为这将改变哪些消息将被启用/禁用。

无法根据消息文本本身进行过滤;应用程序必须自行过滤(在连接到messageLogged() 信号的插槽中,或通过loggedMessages() 在内部调试日志中获取消息后)。

为了简化启用/禁用状态的管理,QOpenGLDebugMessage 还支持debug groups 的概念。一个调试组包含一组启用/禁用的调试信息配置。此外,调试组以堆栈形式组织:可以通过调用pushGroup() 和popGroup() 分别推入和弹出调试组。(创建 OpenGL 上下文时,堆栈中已经有一个组)。

enableMessages() 和disableMessages() 函数将修改当前调试组的配置,即调试组堆栈顶部的调试组。

当一个新组被推入调试组栈时,它将继承之前位于栈顶的组的配置。反之亦然,弹出调试组将恢复成为新顶部的调试组的配置。

推送(分别弹出)调试组还会自动生成QOpenGLDebugMessage::GroupPushType (分别为GroupPopType )类型的调试信息。

另请参阅 QOpenGLDebugMessage

成员类型文档

enum QOpenGLDebugLogger::LoggingMode

LoggingMode 枚举定义了日志记录器对象的日志记录模式。

常数说明
QOpenGLDebugLogger::AsynchronousLogging0来自 OpenGL 服务器的消息以异步方式记录。这意味着,根据 OpenGL 实现的不同,信息可能会在引起这些信息的相应 OpenGL 操作发生一段时间后才被记录,甚至会以非顺序的方式接收。这种模式对性能的影响非常小,因为 OpenGL 实现本质上是重线程和异步的。
QOpenGLDebugLogger::SynchronousLogging1来自 OpenGL 服务器的信息会按顺序同步记录。由于 OpenGL 实现本质上是非常异步的,因此这种模式会对性能造成严重影响;但它对调试 OpenGL 问题非常有用,因为 OpenGL 保证,在相应命令执行返回之前,OpenGL 命令生成的信息就会被记录下来。因此,您可以在messageLogged() 信号上安装断点,并在回溯中查看是哪条 OpenGL 命令导致了断点;唯一需要注意的是,如果您在多个线程中使用 OpenGL,则可能需要在连接到messageLogged() 信号时强制直接连接。

属性文档

[read-only] loggingMode : const LoggingMode

该属性用于保存传递给startLogging() 的日志记录模式。

请注意,日志记录必须已启动,否则该属性的值将毫无意义。

访问功能:

QOpenGLDebugLogger::LoggingMode loggingMode() const

另请参阅 startLogging() 和isLogging()。

成员函数文档

[explicit] QOpenGLDebugLogger::QOpenGLDebugLogger(QObject *parent = nullptr)

使用给定的parent 构建一个新的日志记录器对象。

注意: 必须先初始化该对象,然后才能进行日志记录。

另请参阅 initialize().

[virtual noexcept] QOpenGLDebugLogger::~QOpenGLDebugLogger()

销毁日志记录器对象。

void QOpenGLDebugLogger::disableMessages(QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType, QOpenGLDebugMessage::Severities severities = QOpenGLDebugMessage::AnySeverity)

禁用带有给定sources 、给定types 和给定severities 以及任何邮件 ID 的邮件记录。

当前控制组中的日志记录将被禁用。

另请参阅 enableMessages()、pushGroup() 和popGroup()。

void QOpenGLDebugLogger::disableMessages(const QList<GLuint> &ids, QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType)

禁止记录带有给定ids 、来自给定sources 和属于给定types 以及任何严重程度的消息。

日志记录将在当前控制组中禁用。

另请参阅 enableMessages()、pushGroup() 和popGroup()。

void QOpenGLDebugLogger::enableMessages(QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType, QOpenGLDebugMessage::Severities severities = QOpenGLDebugMessage::AnySeverity)

启用记录来自给定sources 、给定types 和给定severities 以及任何信息 ID 的信息。

日志记录将在当前控制组中启用。

另请参阅 disableMessages()、pushGroup() 和popGroup()。

void QOpenGLDebugLogger::enableMessages(const QList<GLuint> &ids, QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType)

启用记录带有给定ids 、来自给定sources 和属于给定types 以及任何严重程度的消息。

日志记录将在当前控制组中启用。

另请参阅 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::ApplicationSourceQOpenGLDebugMessage::ThirdPartySource ,且类型和严重性有效,否则不会插入日志。

注: 必须在日志记录之前初始化该对象。

另请参阅 initialize().

QList<QOpenGLDebugMessage> QOpenGLDebugLogger::loggedMessages() const

读取 OpenGL 内部调试日志中的所有可用信息并返回。此外,该函数还将清除内部调试日志,因此后续调用将不会返回已返回的信息。

另请参见 startLogging()。

QOpenGLDebugLogger::LoggingMode QOpenGLDebugLogger::loggingMode() const

返回对象的日志记录模式。

注: 属性 loggingMode 的获取函数。

另请参阅 startLogging().

qint64 QOpenGLDebugLogger::maximumMessageLength() const

返回传给logMessage() 的消息文本的最大支持长度(字节)。这也是调试组名称的最大长度,因为推送或弹出组将自动记录一条以调试组名称作为信息文本的信息。

如果消息文本过长,QOpenGLDebugLogger 会自动截断。

注意: 信息文本在传递给 OpenGL 时是以 UTF-8 编码的,因此其字节大小通常与 UTF-16 代码单位的大小不一致,例如,QString::length() 所返回的大小。(如果信息只包含 7 位 ASCII 数据,即调试信息的典型数据,则与之一致)。

[signal] 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 将自动记录一条信息,信息内容为name, idid, sourcesource, typeQOpenGLDebugMessage::GroupPushType, severityQOpenGLDebugMessage::NotificationSeverity

新推送的组将继承堆栈顶层组的相同过滤设置;也就是说,过滤设置不会因推送新组而改变。

注意: source 必须是QOpenGLDebugMessage::ApplicationSourceQOpenGLDebugMessage::ThirdPartySource ,否则组将不会被推送。

注意: 在管理调试组之前,必须先初始化该对象。

另请参阅 popGroup()、enableMessages() 和disableMessages()。

[slot] void QOpenGLDebugLogger::startLogging(QOpenGLDebugLogger::LoggingMode loggingMode = AsynchronousLogging)

开始记录来自 OpenGL 服务器的信息。收到新消息时,会发出messageLogged() 信号,并将记录的消息作为参数。

loggingMode 指定日志记录必须是异步(默认)还是同步。

QOpenGLDebugLogger 当日志记录开始时,将记录 和 的值,并在日志记录停止时将其设回。此外,在调用此函数时安装的任何用户定义的 OpenGL 调试回调都将在停止日志记录时恢复; 将确保在日志记录时仍然调用预先存在的回调。GL_DEBUG_OUTPUT GL_DEBUG_OUTPUT_SYNCHRONOUS QOpenGLDebugLogger

注意: 在不停止并重新启动日志记录的情况下,无法更改日志记录模式。这可能会在未来的 Qt 版本中有所改变。

注意: 必须先初始化对象,然后才能记录日志。

另请参阅 stopLogging() 和initialize()。

[slot] void QOpenGLDebugLogger::stopLogging()

停止记录来自 OpenGL 服务器的信息。

另请参阅 startLogging().

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.