PySide6.QtOpenGL.QOpenGLDebugLogger¶
- class QOpenGLDebugLogger¶
QOpenGLDebugLogger启用了OpenGL调试消息的日志记录。更多…概要¶
属性¶
loggingModeᅟ- 传递给startLogging()的日志记录模式
方法¶
def
__init__()def
enableMessages()def
initialize()def
isLogging()def
loggedMessages()def
loggingMode()def
popGroup()def
pushGroup()
插槽¶
def
logMessage()def
startLogging()def
stopLogging()
信号¶
def
messageLogged()
注意
本文档可能包含从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)的调试消息。另请参阅
- 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:
使用给定的
parent构造一个新的日志记录器对象。- disableMessages([sources=QOpenGLDebugMessage.AnySource[, types=QOpenGLDebugMessage.AnyType[, severities=QOpenGLDebugMessage.AnySeverity]]])¶
禁用具有给定
sources、给定types和给定severities以及任何消息ID的消息的日志记录。日志记录将在当前控制组中被禁用。
- disableMessages(ids[, sources=QOpenGLDebugMessage.AnySource[, types=QOpenGLDebugMessage.AnyType]])
- enableMessages([sources=QOpenGLDebugMessage.AnySource[, types=QOpenGLDebugMessage.AnyType[, severities=QOpenGLDebugMessage.AnySeverity]]])¶
启用从给定的
sources、给定的types和给定的severities以及任何消息ID记录消息。日志记录将在当前控制组中启用。
- enableMessages(ids[, sources=QOpenGLDebugMessage.AnySource[, types=QOpenGLDebugMessage.AnyType]])
- initialize()¶
- Return type:
布尔
在当前OpenGL上下文中初始化对象。上下文必须支持
GL_KHR_debug扩展才能成功初始化。在记录任何日志之前,必须初始化对象。从同一上下文中多次调用此函数是安全的。
此函数也可用于更改先前初始化对象的上下文;请注意,在这种情况下,调用此函数时对象不得处于日志记录状态。
如果记录器成功初始化,则返回
true;否则返回false。另请参阅
- isLogging()¶
- Return type:
布尔
如果此对象当前正在记录日志,则返回
true,否则返回 false。另请参阅
- logMessage(debugMessage)¶
- Parameters:
debugMessage –
QOpenGLDebugMessage
将消息
debugMessage插入到 OpenGL 调试日志中。这为应用程序或库提供了一种插入自定义消息的方式,可以简化 OpenGL 应用程序的调试。注意
debugMessage必须具有ApplicationSource或ThirdPartySource作为其来源,并且具有有效的类型和严重性,否则它将不会被插入到日志中。- loggedMessages()¶
- Return type:
读取OpenGL内部调试日志中的所有可用消息并返回它们。此外,此函数将清除内部调试日志,以便后续调用不会返回已经返回的消息。
另请参阅
- loggingMode()¶
- Return type:
返回对象的日志记录模式。
另请参阅
属性
loggingModeᅟ的获取器。- maximumMessageLength()¶
- Return type:
整数
返回传递给
logMessage()的消息文本的最大支持长度,以字节为单位。这也是调试组名称的最大长度,因为推送或弹出组将自动记录一条消息,调试组名称作为消息文本。如果消息文本过长,它将被
QOpenGLDebugLogger自动截断。注意
消息文本在传递给OpenGL时以UTF-8编码,因此它们的字节大小通常与UTF-16代码单元的数量不匹配,例如由QString::length()返回的数量。(如果消息仅包含7位ASCII数据,则匹配,这在调试消息中是典型的。)
- messageLogged(debugMessage)¶
- Parameters:
debugMessage –
QOpenGLDebugMessage
当从OpenGL服务器记录调试消息(由
debugMessage参数包装)时,会发出此信号。根据OpenGL的实现,这个信号可以从接收者所在的线程以外的其他线程发出,甚至与初始化此对象的QOpenGLContext所在的线程不同。此外,信号可能同时从多个线程发出。这通常不是问题,因为Qt会为跨线程信号发射使用队列连接,但如果你强制连接类型为Direct,那么你必须意识到连接到这个信号的槽中潜在的竞争条件。
如果日志记录已在
SynchronousLogging模式下启动,OpenGL保证此信号将从QOpenGLContext绑定到的同一线程发出,并且不会发生并发调用。- popGroup()¶
从调试组堆栈中弹出最顶层的调试组。如果组成功弹出,OpenGL 将自动记录一条消息,消息、id 和源与弹出的组匹配,类型为
GroupPopType,严重性为NotificationSeverity。弹出一个调试组将恢复成为调试组堆栈顶部的组的消息过滤设置。
- pushGroup(name[, id=0[, source=QOpenGLDebugMessage.ApplicationSource]])¶
- Parameters:
name – str
id – int
source –
Source
将一个名为
name,id 为id,源为source的调试组推入调试组堆栈。如果组成功推入,OpenGL 将自动记录一条消息,消息内容为name,id 为id,源为source,类型为GroupPushType,严重程度为NotificationSeverity。新推送的组将继承堆栈顶部组的相同过滤设置;也就是说,推送新组不会改变过滤设置。
注意
source必须是ApplicationSource或ThirdPartySource,否则组将不会被推送。- startLogging([loggingMode=QOpenGLDebugLogger.LoggingMode.AsynchronousLogging])¶
- Parameters:
loggingMode –
LoggingMode
开始记录来自OpenGL服务器的消息。当接收到新消息时,会发出信号
messageLogged(),并将记录的消息作为参数传递。loggingMode指定日志记录必须是异步的(默认)还是同步的。QOpenGLDebugLogger将在日志记录开始时记录GL_DEBUG_OUTPUT和GL_DEBUG_OUTPUT_SYNCHRONOUS的值,并在日志记录停止时将它们恢复。此外,当调用此函数时安装的任何用户定义的 OpenGL 调试回调将在日志记录停止时恢复;QOpenGLDebugLogger将确保在日志记录时仍然调用预先存在的回调。注意
在不停止并重新启动日志记录的情况下,无法更改日志记录模式。这可能会在未来的Qt版本中有所改变。
- stopLogging()¶
停止记录来自OpenGL服务器的消息。
另请参阅