QOpenGLDebugLogger 类

The QOpenGLDebugLogger enables logging of OpenGL debugging messages. 更多信息...

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

公共类型

枚举LoggingMode { AsynchronousLogging, SynchronousLogging }

属性

公共函数

QOpenGLDebugLogger(QObject *parent = nullptr)
virtual~QOpenGLDebugLogger()
voiddisableMessages(QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType, QOpenGLDebugMessage::Severities severities = QOpenGLDebugMessage::AnySeverity)
voiddisableMessages(const QList<GLuint> &ids, QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType)
voidenableMessages(QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType, QOpenGLDebugMessage::Severities severities = QOpenGLDebugMessage::AnySeverity)
voidenableMessages(const QList<GLuint> &ids, QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType)
boolinitialize()
boolisLogging() const
QList<QOpenGLDebugMessage>loggedMessages() const
QOpenGLDebugLogger::LoggingModeloggingMode() const
qint64maximumMessageLength() const
voidpopGroup()
voidpushGroup(const QString &name, GLuint id = 0, QOpenGLDebugMessage::Source source = QOpenGLDebugMessage::ApplicationSource)

公共槽

voidlogMessage(const QOpenGLDebugMessage &debugMessage)
voidstartLogging(QOpenGLDebugLogger::LoggingMode loggingMode = AsynchronousLogging)
voidstopLogging()

信号

voidmessageLogged(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::AsynchronousLogging0OpenGL服务器消息异步记录。这意味着可以在触发相关OpenGL操作的相应OpenGL动作之后一段时间内记录消息,甚至可能以乱序方式接收它们,这取决于OpenGL的实现。由于OpenGL实现高度线程化且异步,此模式具有非常低的性能损失。
QOpenGLDebugLogger::SynchronousLogging1OpenGL服务器的消息是同步且依次记录的。这给性能带来了严重影响,因为OpenGL实施本质上是异步的;但这对调试OpenGL问题非常有用,因为OpenGL保证由OpenGL命令生成的消息在相应命令执行返回之前被记录。因此,您可以在messageLogged()信号上安装断点,并查看堆栈跟踪,以确定哪个OpenGL命令导致它;唯一的缺点是,如果您从多个线程使用OpenGL,则可能需要在连接到messageLogged()信号时强制直接连接。

属性文档

[只读] loggingMode : const LoggingMode

该属性包含传递给startLogging()的记录模式。

注意,必须已开始记录,否则此属性值将无意义。

访问函数

QOpenGLDebugLogger::LoggingModeloggingMode() 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::ApplicationSourceQOpenGLDebugMessage::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::ApplicationSourceQOpenGLDebugMessage::ThirdPartySource,否则组将不会被推送。

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

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

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

开始从OpenGL服务器记录消息。当接收到新消息时,将发出信号messageLogged(),该信号携带已记录的消息作为参数。

loggingMode指定是否必须异步记录(默认)或同步。

QOpenGLDebugLogger将在开始记录时记录GL_DEBUG_OUTPUTGL_DEBUG_OUTPUT_SYNCHRONOUS的值,并在停止记录时恢复它们。此外,在调用此函数时安装的任何由用户定义的OpenGL调试回调将在停止记录时恢复;QOpenGLDebugLogger将确保在记录时调用现有的回调。

注意:无法在不停止并重新开始日志记录的情况下更改日志记录模式。这可能在Qt的将来版本中更改。

注意:对象必须在记录发生之前初始化。

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

[slot] void QOpenGLDebugLogger::stopLogging()

停止从OpenGL服务器记录消息。

另请参阅startLogging

© 2024 Qt公司。此处包含的文档贡献是各自所有者的版权。此文档是在自由软件基金会发布的GNU自由文档许可证版本1.3的条款下提供的。Qt及其相关标志是芬兰和/或世界上其他国家的Qt公司的商标。所有其他商标是各自所有者的财产。