QOpenGLDebugLogger#

QOpenGLDebugLogger 允许记录 OpenGL 调试消息。 更多信息

Inheritance diagram of PySide6.QtOpenGL.QOpenGLDebugLogger

摘要#

属性#

方法#

#

信号#

注意

本文档可能包含从 C++ 自动翻译到 Python 的代码段。我们始终欢迎对代码段的翻译做出贡献。如果您发现翻译存在问题,也可以通过在https:/bugreports.qt.io/projects/PYSIDE创建工单的方式告诉我们。

详细描述#

警告

本节包含从 C++ 自动翻译到 Python 的代码段,可能包含错误。

介绍#

OpenGL 编程可能会非常容易出现错误。大多数情况下,对一个 OpenGL API 的单一失败调用可能导致整个应用程序的一个部分停止工作,屏幕上什么都不会绘制。

要确保 OpenGL 实现未返回错误,唯一的办法是在每次 API 调用后都使用 glGetError 进行检查。此外,OpenGL 错误会累积,因此应该始终像这样在循环中使用 glGetError

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 日志中,或者在生成时实时传递给监听器。

QOpenGLDebugLogger 支持这两种操作模式。请参阅以下章节了解它们之间的区别。

创建 OpenGL 调试上下文#

出于效率考虑,OpenGL 实现允许不生成任何调试输出,除非 OpenGL 上下文是调试上下文。要从 Qt 创建一个调试上下文,你必须将 QSurfaceFormat::DebugContext 格式选项设置在用于创建 QOpenGLContext 对象的 QSurfaceFormat 上

format = QSurfaceFormat()
# 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)
context = QOpenGLContext()
context.setFormat(format)
context.create()

请注意,这里请求的 3.2 OpenGL Core Profile 只是为了示例目的;此类与任何特定的 OpenGL 或 OpenGL ES 版本无关,因为它依赖于 GL_KHR_debug 扩展的有效性(如下文所述)。

创建和初始化 QOpenGLDebugLogger#

QOpenGLDebugLogger 是一个简单的 QObject 派生类。就像所有 QObject 子类一样,你创建一个实例(可选择指定父对象),并像 Qt 中的其他 OpenGL 函数一样,在使用前必须通过调用 initialize() 来初始化,只要存在当前的 OpenGL 上下文。

ctx = QOpenGLContext.currentContext()
logger = QOpenGLDebugLogger(self)
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() 函数检索存储在此日志中的消息。

messages = logger.loggedMessages()
for message in messages:
    print(message)

内部日志的大小有限;当它填满时,较旧的消息将被丢弃以为新传入的消息腾出空间。当你调用 loggedMessages() 时,内部日志也将被清空。

如果您想确保不丢失任何调试信息,您必须使用实时日志记录而不是调用此函数。但是,即使在实时日志记录激活之前或禁用时,可能仍然会在创建上下文和激活实时日志记录之间(或通常情况下)生成调试信息。

消息的实时日志记录#

您还可以从实现中以创建时的方式实时接收OpenGL服务器的调试消息流。为此,您需要将合适的槽连接到messageLogged()信号,并通过调用startLogging()来启动日志记录。

logger.messageLogged.connect(receiver.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()方法将其插入日志。

message =
    QOpenGLDebugMessage.createApplicationMessage("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() 函数将修改当前调试组中的配置,即调试组栈顶的配置。

当将新组推送到调试组堆栈时,它将继承堆栈顶部组(先前位于堆栈顶部的组)的配置。相反,弹出调试组将恢复成为新顶部的新组配置。

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

另请参阅

QOpenGLDebugMessage

class LoggingMode#

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

常量

描述

QOpenGLDebugLogger.AsynchronousLogging

OpenGL服务器的消息异步记录。这意味着消息可以在导致它们的相应OpenGL操作之后记录,甚至可能会以非顺序的方式进行接收,具体取决于OpenGL实现。这种模式具有非常低的性能影响,因为OpenGL实现是线程化的并具有异步性质。

QOpenGLDebugLogger.SynchronousLogging

OpenGL服务器的消息同步且顺序地记录。这会严重影响性能,因为OpenGL实现本质上是异步的;但它对调试OpenGL问题非常有用,因为OpenGL保证OpenGL命令生成的消息将在相应命令执行返回之前记录。因此,您可以在messageLogged()信号上设置断点,以查看导致该信号的OpenGL命令;唯一的缺点是,如果您在多个线程中使用OpenGL,您可能需要在连接到messageLogged()信号时强制直接连接。

注意

可以当使用 from __feature__ import true_property 时直接使用属性,或者否则使用访问器函数。

属性 loggingMode: QOpenGLDebugLogger.LoggingMode#

此属性保存传递给 startLogging() 方法的日志模式...

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

访问函数
__init__([parent=None])#
参数:

parentQObject

使用指定的 parent 构造新的日志对象。

注意

在开始日志记录之前,必须初始化对象。

另请参阅

initialize()

disableMessages([sources=QOpenGLDebugMessage.AnySource[, types=QOpenGLDebugMessage.AnyType[, severities=QOpenGLDebugMessage.AnySeverity]]])#
参数:

禁用具有给定 sources、给定 types 和给定 severities 的消息记录以及任何消息 ID 的日志。

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

disableMessages(ids[, sources=QOpenGLDebugMessage.AnySource[, types=QOpenGLDebugMessage.AnyType]])
参数:
  • ids – 无符号整数的列表

  • sourcesSource 的组合

  • typesType 的组合

enableMessages([sources=QOpenGLDebugMessage.AnySource[, types=QOpenGLDebugMessage.AnyType[, severities=QOpenGLDebugMessage.AnySeverity]]])#
参数:

启用来自给定 sources、指定 typesseverities 以及任何消息 ID 的消息的日志记录。

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

enableMessages(ids[, sources=QOpenGLDebugMessage.AnySource[, types=QOpenGLDebugMessage.AnyType]])
参数:
  • ids – 无符号整数的列表

  • sourcesSource 的组合

  • typesType 的组合

initialize()#
返回类型::

bool

初始化当前 OpenGL 上下文中的对象。初始化成功之前,上下文必须支持 GL_KHR_debug 扩展。对象必须在任何日志记录发生之前进行初始化。

可以从同一上下文中多次安全地调用此函数。

此函数还可以用于更改先前已初始化的对象的上下文;注意,在这种情况下,在调用此函数时对象不能正在记录。

如果日志记录器成功初始化,则返回 true;否则返回 false。

另请参阅

QOpenGLContext

isLogging()#
返回类型::

bool

如果此对象目前正在进行日志记录,则返回 true;否则返回 false。

另请参阅

startLogging()

logMessage(debugMessage)#
参数:

debugMessageQOpenGLDebugMessage

将消息 debugMessage 插入到 OpenGL 调试日志中。这为应用程序或库提供了插入自定义消息的方法,有助于简化 OpenGL 应用程序的调试。

注意

debugMessage必须具有其源为ApplicationSourceThirdPartySource,并且具有有效的类型和严重性,否则它将不会被插入到日志中。

注意

在开始日志记录之前,必须初始化对象。

另请参阅

initialize()

loggedMessages()#
返回类型::

.QOpenGLDebugMessage的列表

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

另请参阅

startLogging()

loggingMode()#
返回类型::

日志模式

返回对象的活动日志模式。

另请参阅

startLogging()

loggingMode的获取器。

maximumMessageLength()#
返回类型::

int

返回传递给logMessage的文本的最大支持长度(以字节为单位)。这也是调试组名的最大长度,因为压入或弹出组将自动以调试组名作为消息文本记录消息。

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

注意

消息文本在传递给OpenGL时以UTF-8编码,因此其字节大小通常与QString::length()返回的UTF-16代码单元数量不匹配。 (如果消息包含只有7位ASCII数据,则这些通常会返回,这是调试消息的典型情况。)

messageLogged(debugMessage)#
参数:

debugMessageQOpenGLDebugMessage

当从OpenGL服务器记录调试消息(由debugMessage参数包装)时,发出此信号。

根据OpenGL实现,此信号可以由除了接收者所在线程之外的线程发出,甚至可以由初始化此对象的QOpenGLContext所在的线程之外的线程发出。此外,信号可能由多个线程同时发出。这通常不是问题,因为Qt将利用队列连接利用跨线程信号发射,但如果您强制连接类型为直接,则必须了解此信号槽可能发生的潜在竞争条件。

如果已经在 同步日志 模式下开始了日志记录,OpenGL 保证这个信号将从 QOpenGLContext 绑定的同一线程发出,并且不会发生并发调用。

注意

必须已经开始记录日志,否则此信号不会发出。

另请参阅

startLogging()

popGroup(

从调试组堆栈中移除最顶层调试组。如果成功移除,OpenGL 将自动记录一个消息,该消息的消息、ID 和源与被移除组的消息匹配,类型为 GroupPopType 和严重性 NotificationSeverity

移除调试组将恢复成为调试组堆栈顶部的组的消息过滤设置。

注意

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

另请参阅

pushGroup()

pushGroup(name[, id=0[, source=QOpenGLDebugMessage.ApplicationSource]])
参数:
  • name – str

  • id – int

  • source

将名称为 name、ID 为 id 和源为 source 的调试组推入调试组堆栈。如果组成功推入,OpenGL 将自动记录一个消息,消息包含 name、ID id、源 source、类型 GroupPushType 和严重性 NotificationSeverity

新推入的组将继承位于栈顶的组的相同过滤设置;换句话说,通过推入新的组不会更改过滤。

注意

源必须为 ApplicationSourceThirdPartySource,否则组不会推入。

注意

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

startLogging([loggingMode=QOpenGLDebugLogger.LoggingMode.AsynchronousLogging])#
参数:

loggingModeLoggingMode

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

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

当请求开始日志记录时,QOpenGLDebugLogger将记录GL_DEBUG_OUTPUTGL_DEBUG_OUTPUT_SYNCHRONOUS的值,并在停止日志记录时恢复它们。此外,当调用此函数时安装的任何用户定义的OpenGL调试回调在停止日志记录时将被恢复;QOpenGLDebugLogger将确保在日志记录时仍然调用预存在的回调。

注意

不停止再次开始日志记录,无法更改日志记录模式。这可能在Qt的将来版本中发生变化。

注意

在开始日志记录之前,必须初始化对象。

stopLogging()#

停止记录OpenGL服务器发出的消息。

另请参阅

startLogging()