PySide6.QtOpenGL.QOpenGLDebugLogger

class QOpenGLDebugLogger

QOpenGLDebugLogger 启用了OpenGL调试消息的日志记录。更多

PySide6.QtOpenGL.QOpenGLDebugLogger 的继承图

概要

属性

方法

插槽

信号

注意

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

详细描述

警告

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

介绍

OpenGL编程可能非常容易出错。大多数情况下,对OpenGL的单个失败调用可能导致应用程序的整个部分停止工作,屏幕上没有任何内容被绘制。

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

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核心配置文件仅用于示例目的;此类不绑定到任何特定的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

请注意,GL_KHR_debug扩展必须在上下文中可用,以便访问由OpenGL记录的消息。您可以通过调用以下函数来检查此扩展是否存在:

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命令,从而能够识别来自它们的最终消息。

为了做到这一点,你可以通过调用createApplicationMessage()createThirdPartyMessage()来创建一个QOpenGLDebugMessage对象,然后通过调用logMessage()将其插入日志中:

message =
    QOpenGLDebugMessage.createApplicationMessage("Custom message")
logger.logMessage(message)

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

控制调试输出

QOpenGLDebugMessage 也能够对调试消息应用过滤器,从而限制记录的消息数量。您可以通过分别调用 enableMessages()disableMessages() 来启用或禁用消息记录。默认情况下,所有消息都会被记录。

可以通过以下方式启用或禁用消息:

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

  • id、source和type(并在选择中包括所有严重性)。

请注意,给定消息的“启用”状态是 (id, source, type, severity) 元组的属性;消息属性形成任何类型的层次结构。你应该注意调用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时,属性可以直接使用,否则通过访问器函数使用。

property loggingModeᅟ: QOpenGLDebugLogger.LoggingMode

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

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

Access functions:
__init__([parent=None])
Parameters:

父对象QObject

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

注意

对象必须在日志记录发生之前进行初始化。

另请参阅

initialize()

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

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

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

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

  • sourcesSource 的组合

  • typesType 的组合

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

启用从给定的sources、给定的types和给定的severities以及任何消息ID记录消息。

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

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

  • sourcesSource 的组合

  • typesType 的组合

initialize()
Return type:

布尔

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

从同一上下文中多次调用此函数是安全的。

此函数也可用于更改先前初始化对象的上下文;请注意,在这种情况下,调用此函数时对象不得处于日志记录状态。

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

另请参阅

QOpenGLContext

isLogging()
Return type:

布尔

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

另请参阅

startLogging()

logMessage(debugMessage)
Parameters:

debugMessageQOpenGLDebugMessage

将消息 debugMessage 插入到 OpenGL 调试日志中。这为应用程序或库提供了一种插入自定义消息的方式,可以简化 OpenGL 应用程序的调试。

注意

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

注意

对象必须在日志记录发生之前进行初始化。

另请参阅

initialize()

loggedMessages()
Return type:

QOpenGLDebugMessage的列表

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

另请参阅

startLogging()

loggingMode()
Return type:

LoggingMode

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

另请参阅

startLogging()

属性 loggingModeᅟ 的获取器。

maximumMessageLength()
Return type:

整数

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

如果消息文本过长,它将被QOpenGLDebugLogger自动截断。

注意

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

messageLogged(debugMessage)
Parameters:

debugMessageQOpenGLDebugMessage

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

根据OpenGL的实现,这个信号可以从接收者所在的线程以外的其他线程发出,甚至与初始化此对象的QOpenGLContext所在的线程不同。此外,信号可能同时从多个线程发出。这通常不是问题,因为Qt会为跨线程信号发射使用队列连接,但如果你强制连接类型为Direct,那么你必须意识到连接到这个信号的槽中潜在的竞争条件。

如果日志记录已在SynchronousLogging模式下启动,OpenGL保证此信号将从QOpenGLContext绑定到的同一线程发出,并且不会发生并发调用。

注意

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

另请参阅

startLogging()

popGroup()

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

弹出一个调试组将恢复成为调试组堆栈顶部的组的消息过滤设置。

注意

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

另请参阅

pushGroup()

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

  • id – int

  • sourceSource

将一个名为 name,id 为 id,源为 source 的调试组推入调试组堆栈。如果组成功推入,OpenGL 将自动记录一条消息,消息内容为 name,id 为 id,源为 source,类型为 GroupPushType,严重程度为 NotificationSeverity

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

注意

source 必须是 ApplicationSourceThirdPartySource,否则组将不会被推送。

注意

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

startLogging([loggingMode=QOpenGLDebugLogger.LoggingMode.AsynchronousLogging])
Parameters:

loggingModeLoggingMode

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

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

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

注意

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

注意

对象必须在日志记录发生之前进行初始化。

stopLogging()

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

另请参阅

startLogging()