Qt Quick 场景图¶
Qt Quick中的场景图¶
Qt Quick 2 使用了一个专用的场景图,然后通过图形 API(如 OpenGL ES、OpenGL、Vulkan、Metal 或 Direct 3D)进行遍历和渲染。使用场景图进行图形处理,而不是传统的命令式绘画系统(QPainter 及类似系统),意味着要渲染的场景可以在帧之间保留,并且在渲染开始之前就知道要渲染的完整图元集。这为许多优化打开了大门,例如批量渲染以最小化状态变化和丢弃被遮挡的图元。
例如,假设一个用户界面包含一个包含十个项目的列表,每个项目都有一个背景颜色、一个图标和一个文本。使用传统的绘图技术,这将导致30次绘制调用和类似数量的状态更改。另一方面,场景图可以重新组织图元以进行渲染,使得所有背景在一次调用中绘制,然后所有图标,最后所有文本,将总的绘制调用次数减少到仅3次。像这样的批处理和状态更改减少可以大大提高某些硬件的性能。
场景图与Qt Quick 2.0紧密相关,不能单独使用。场景图由QQuickWindow类管理和渲染,自定义的Item类型可以通过调用updatePaintNode()将其图形原语添加到场景图中。
场景图是项目场景的图形表示,它是一个独立的结构,包含足够的信息来渲染所有项目。一旦设置完成,它可以独立于项目的状态进行操作和渲染。在许多平台上,场景图甚至会在GUI线程准备下一帧状态的同时,在专用的渲染线程上进行渲染。
注意
本页列出的大部分信息特定于Qt Quick场景图的内置默认行为。当使用替代的场景图适配时,例如software适配,并非所有概念都适用。有关不同场景图适配的更多信息,请参见Scene Graph Adaptations。
Qt Quick 场景图结构¶
场景图由许多预定义的节点类型组成,每种类型都有其特定的用途。虽然我们称之为场景图,但更准确的定义是节点树。这棵树是由QML场景中的QQuickItem类型构建的,然后场景由渲染器处理,渲染器负责绘制场景。节点本身不包含任何活动的绘图代码,也没有虚拟的paint()函数。
尽管节点树主要由现有的Qt Quick QML类型在内部构建,但用户也可以添加包含自己内容的完整子树,包括表示3D模型的子树。
节点¶
对于用户来说,最重要的节点是QSGGeometryNode。它通过定义其几何形状和材质来定义自定义图形。几何形状使用QSGGeometry定义,并描述图形基元的形状或网格。它可以是一条线、一个矩形、一个多边形、许多不相连的矩形或复杂的3D网格。材质定义了如何填充此形状中的像素。
一个节点可以有任意数量的子节点,几何节点将被渲染,以便它们按照子节点的顺序显示,父节点位于子节点之后。
注意
这并没有说明渲染器中的实际渲染顺序。只有视觉输出是有保证的。
可用的节点有:
QSGNode 类是场景图中所有节点的基类。
QSGGeometryNode 类用于场景图中所有渲染的内容。
QSGClipNode 类在场景图中实现了裁剪功能。
QSGTransformNode 类在场景图中实现变换。
QSGOpacityNode 类用于改变节点的透明度。
自定义节点通过子类化updatePaintNode()并设置ItemHasContents标志添加到场景图中。
警告
至关重要的是,原生图形(OpenGL、Vulkan、Metal等)操作以及与场景图的交互必须仅在渲染线程上进行,主要是在updatePaintNode()调用期间。经验法则是仅在updatePaintNode()函数内部使用带有“QSG”前缀的类。
更多详情,请参见场景图 - 自定义几何。
预处理¶
节点有一个虚拟的preprocess()函数,它将在场景图渲染之前被调用。节点子类可以设置标志UsePreprocess并重写preprocess()函数,以完成其节点的最终准备工作。例如,将贝塞尔曲线分割为适合当前比例因子的细节级别,或更新纹理的一部分。
节点所有权¶
节点的所有权可以由创建者显式设置,也可以通过设置标志OwnedByParent由场景图来管理。将所有权分配给场景图通常是更可取的,因为当场景图存在于GUI线程之外时,它可以简化清理工作。
材料¶
该材料描述了QSGGeometryNode中几何体内部的填充方式。它封装了图形管线的顶点和片段阶段的图形着色器,并提供了实现各种效果的充分灵活性,尽管大多数Qt Quick项目本身只使用非常基本的材料,例如纯色和纹理填充。
对于只想将自定义着色应用于QML Item类型的用户,可以直接在QML中使用ShaderEffect类型来实现。
以下是材料类别的完整列表:
QSGMaterialType 类与 QSGMaterial 结合使用,作为唯一的类型标记。
QSGMaterial 类封装了着色器程序的渲染状态。
QSGMaterialShader 类表示一个与图形 API 无关的着色器程序。
QSGFlatColorMaterial 类提供了一种在场景图中渲染纯色几何图形的便捷方式。
QSGOpaqueTextureMaterial 类提供了一种在场景图中渲染纹理几何体的便捷方式。
QSGTextureMaterial 类提供了一种在场景图中渲染纹理几何体的便捷方式。
QSGVertexColorMaterial 类提供了一种便捷的方式,用于在场景图中渲染每个顶点着色的几何体。
便利节点¶
场景图API是低层次的,侧重于性能而非便利性。从头开始编写自定义几何体和材质,即使是最基本的,也需要相当数量的代码。因此,API包含了一些便利类,以便最常见的自定义节点能够轻松使用。
QSGSimpleRectNode- 一个QSGGeometryNode子类,定义了一个具有纯色材质的矩形几何体。
QSGSimpleTextureNode- 一个QSGGeometryNode子类,定义了带有纹理材质的矩形几何体。
场景图和渲染¶
场景图的渲染在QQuickWindow类内部进行,没有公开的API可以访问它。然而,在渲染管道中有几个地方用户可以附加应用程序代码。这可以用于添加自定义的场景图内容或通过直接调用场景图使用的图形API(OpenGL、Vulkan、Metal等)插入任意的渲染命令。集成点由渲染循环定义。
有关场景图渲染器如何工作的详细描述,请参见Qt Quick Scene Graph Default Renderer。
有两种渲染循环变体可用:basic 和 threaded。basic 是单线程的,而 threaded 在专用线程上执行场景图渲染。Qt 尝试根据平台和可能使用的图形驱动程序选择一个合适的循环。当这不令人满意时,或出于测试目的,可以使用环境变量 QSG_RENDER_LOOP 来强制使用给定的循环。要验证正在使用哪个渲染循环,请启用 qt.scenegraph.general 日志类别。
线程化渲染循环('threaded')¶
在许多配置中,场景图渲染将在专用的渲染线程上进行。这样做是为了增加多核处理器的并行性,并更好地利用等待阻塞交换缓冲区调用等停滞时间。这提供了显著的性能改进,但对场景图的交互发生的地点和时间施加了某些限制。
以下是一个简单的概述,说明了如何使用线程渲染循环和OpenGL渲染帧。除了OpenGL上下文的具体细节外,其他图形API的步骤也是相同的。
![]()
QML场景中发生了一个变化,导致
QQuickItem::update()被调用。这可能是由于动画或用户输入的结果。一个事件被发布到渲染线程以启动一个新帧。渲染线程准备绘制新帧并启动对GUI线程的阻塞。
当渲染线程准备新帧时,GUI线程调用
updatePolish()以在渲染之前对项目进行最后的修饰。GUI 线程被阻塞。
发出
beforeSynchronizing()信号。应用程序可以直接连接(使用 Qt::DirectConnection)到此信号,以在调用updatePaintNode()之前进行任何所需的准备工作。将QML状态同步到场景图中。这是通过调用自上一帧以来已更改的所有项目上的
updatePaintNode()函数来完成的。这是QML项目与场景图中的节点交互的唯一时间。GUI线程阻塞已解除。
场景图被渲染:
发出
beforeRendering()信号。应用程序可以直接连接(使用 Qt::DirectConnection)到此信号,以使用自定义图形 API 调用,这些调用将在视觉上堆叠在 QML 场景之下。指定了
UsePreprocess的项目将调用其preprocess()函数。渲染器处理节点。
渲染器生成状态并记录当前使用的图形 API 的绘制调用。
发出
afterRendering()信号。应用程序可以直接连接(使用 Qt::DirectConnection)到此信号,以发出自定义图形 API 调用,这些调用将在视觉上堆叠在 QML 场景之上。帧现在已准备就绪。交换缓冲区(OpenGL),或记录一个呈现命令并将命令缓冲区提交到图形队列(Vulkan、Metal)。发出
frameSwapped()。当渲染线程正在渲染时,GUI可以自由地推进动画、处理事件等。
线程渲染器目前在Windows上默认使用Direct3D 11和OpenGL(当使用opengl32.dll时),Linux(不包括Mesa llvmpipe),macOS(使用Metal),移动平台,以及使用EGLFS的嵌入式Linux,以及无论平台如何都使用Vulkan。所有这些在未来的版本中可能会有所变化。始终可以通过在环境中设置QSG_RENDER_LOOP=threaded来强制使用线程渲染器。
非线程渲染循环('basic')¶
在Windows上使用OpenGL时,如果不使用系统的标准opengl32.dll,macOS上使用OpenGL,WebAssembly,以及Linux上使用某些驱动程序时,默认使用非线程渲染循环。对于后者,这主要是一种预防措施,因为并非所有OpenGL驱动程序和窗口系统的组合都经过了测试。
在macOS和OpenGL上,当使用XCode 10(10.14 SDK)或更高版本构建时,不支持线程渲染循环,因为这选择了在macOS 10.14上使用层支持的视图。您可以使用Xcode 9(10.13 SDK)构建以选择不使用层支持,在这种情况下,线程渲染循环可用并默认使用。Metal没有这样的限制。
WebAssembly不支持线程渲染循环,因为Web平台对在主线程以外的其他线程上使用WebGL的支持有限,并且对阻塞主线程的支持也有限。
即使在使用非线程渲染循环时,您也应该像使用线程渲染器一样编写代码,因为如果不这样做,代码将不可移植。
以下是非线程渲染器中帧渲染序列的简化示意图。
驾驶动画¶
什么是 `` Advance Animations``
参考上面的图表?¶
默认情况下,Qt Quick动画(例如NumberAnimation)由默认的动画驱动程序驱动。这依赖于基本的系统计时器,例如QObject::startTimer()。计时器通常以16毫秒的间隔运行。虽然这永远不会完全准确,并且还取决于底层平台计时器的准确性,但它具有独立于渲染的优势。无论显示刷新率如何以及是否启用了与显示垂直同步的同步,它都能提供一致的结果。这就是动画在basic渲染循环中的工作方式。
为了在屏幕上提供更准确的结果并减少卡顿,独立于渲染循环设计(无论是单线程还是多线程),渲染循环可能会决定安装自己的自定义动画驱动程序,并将推进操作掌握在自己手中,而不依赖于计时器。
这就是threaded渲染循环所实现的内容。实际上,它安装的不是一个,而是两个动画驱动程序:一个在GUI线程上(用于驱动常规动画,如NumberAnimation),另一个在渲染线程上(用于驱动渲染线程动画,即Animator类型,如OpacityAnimator或XAnimator)。这两者都在帧的准备过程中进行,即动画现在与渲染同步。这是有意义的,因为底层的图形堆栈将呈现限制在显示器的垂直同步上。
因此,在上面的threaded渲染循环图中,两个线程上都有一个明确的Advance animations步骤。对于渲染线程来说,这是微不足道的:由于线程被限制为与垂直同步(vsync)同步,在每一帧中推进动画(对于Animator类型)就好像已经过去了16.67毫秒,这比依赖系统计时器提供了更准确的结果。(当限制为vsync计时时,即60 Hz刷新率下的1000/60毫秒,可以合理地假设自上一帧执行相同操作以来已经过去了大约那么长时间)
同样的方法也适用于在GUI(主)线程上的动画:由于GUI和渲染线程之间的数据同步,GUI线程实际上被限制在与渲染线程相同的速率,同时仍然具有较少工作的优势,为应用程序逻辑留下更多的空间,因为许多渲染准备工作现在被卸载到渲染线程。
虽然上述示例使用了每秒60帧,但Qt Quick也准备适应其他刷新率:该速率是从QScreen和平台查询的。例如,对于144 Hz的屏幕,间隔为6.94毫秒。同时,如果基于垂直同步的节流功能未按预期工作,这恰恰可能导致问题,因为如果渲染循环认为正在发生的事情与现实不匹配,将会出现错误的动画节奏。
注意
从 Qt 6.5 开始,线程渲染循环提供了选择另一种动画驱动的可能性,该驱动仅基于经过的时间(QElapsedTimer)。要启用此功能,请将 QSG_USE_SIMPLE_ANIMATION_DRIVER 环境变量设置为非零值。这样做的好处包括:当有多个窗口时,不需要任何回退到 QTimer 的基础设施;不需要启发式方法来确定基于垂直同步的节流是否缺失或损坏;与垂直同步节流中的任何时间漂移兼容;并且不依赖于主屏幕的刷新率,因此在多屏幕设置中可能表现更好。即使基于垂直同步的节流被破坏或禁用,它也能正确驱动渲染线程动画(Animator 类型)。另一方面,使用这种方法时,动画可能会被认为不够流畅。考虑到兼容性,目前它作为一个可选功能提供。
总之,只要满足以下条件,threaded 渲染循环预计将提供更流畅的动画,减少卡顿:
屏幕上正好有一个窗口(如
QQuickWindow)。基于VSync的节流与底层图形和显示堆栈按预期工作。
如果没有或超过一个窗口可见怎么办?¶
当没有可渲染的窗口时,例如因为我们的QQuickWindow被最小化(Windows)或完全遮挡(macOS),我们无法呈现帧,因此无法依赖线程与屏幕刷新率同步“工作”。在这种情况下,threaded渲染循环会自动切换到基于系统定时器的方法来驱动动画,即暂时切换到basic循环会使用的机制。
当屏幕上有多个QQuickWindow实例时,情况也是如此。上面介绍的通过与渲染线程同步来推进GUI线程上的动画的模型不再令人满意,因为现在有多个渲染线程的多个同步点(每个窗口一个)。在这种情况下,回退到基于系统计时器的方法也变得必要,因为GUI线程将阻塞多长时间和频率现在取决于许多因素,包括窗口中的内容(它们是否在动画?它们更新的频率如何?)和图形堆栈行为(它如何处理两个或多个线程的呈现与等待垂直同步?)。由于我们无法以稳定的跨平台方式保证被限制在窗口的呈现速率(首先,那会是哪个窗口?),因此推进动画不能基于渲染。
这种动画处理机制的切换对应用程序是透明的。
如果基于垂直同步的节流功能失效、全局禁用或应用程序自行禁用了它,会发生什么?¶
threaded 渲染循环依赖于图形API实现和/或窗口系统进行节流,例如,在OpenGL(GLX、EGL、WGL)的情况下请求交换间隔为1,在Direct 3D的情况下调用间隔为1的Present(),或在使用Vulkan时使用FIFO呈现模式。
一些图形驱动程序允许用户覆盖此设置并关闭它,忽略Qt的请求。例如,图形驱动程序的系统范围控制面板可能允许覆盖应用程序的垂直同步设置。也可能出现图形堆栈无法提供基于垂直同步的适当节流的情况,这在某些虚拟机中可能会发生(主要是由于使用了基于软件光栅化的OpenGL或Vulkan实现)。
在交换/呈现操作(或其他图形操作)中没有阻塞的情况下,这样的渲染循环会使动画推进得太快。这对于basic渲染循环来说不是问题,因为它总是依赖于系统计时器。而对于threaded,行为可能会根据Qt版本的不同而有所变化:
如果已知系统无法提供基于垂直同步的节流,那么在Qt 6.4之前,唯一的选择是通过在运行应用程序之前在环境中手动设置
QSG_RENDER_LOOP=basic来使用basic渲染循环。从 Qt 6.4 开始,将
QSG_NO_VSYNC环境变量设置为非零值,或将窗口的 QSurfaceFormat::swapInterval() 设置为0也可以缓解这个问题:通过显式请求禁用基于 vsync 的阻塞,无论该请求在实践中是否有效,threaded渲染循环可以由此识别出依赖 vsync 来驱动动画是徒劳的,并且它将回退到使用系统计时器,就像它对多个窗口所做的那样。更好的是,从Qt 6.4开始,场景图还尝试通过一些简单的启发式方法识别帧是否“过快”呈现,并在必要时自动切换到系统计时器。这意味着在大多数情况下,无需进行任何操作,应用程序将按预期运行动画,即使默认的渲染循环是
threaded。虽然这对应用程序是透明的,但对于故障排除和开发目的,了解这一点是有用的,当启用QSG_INFO或qt.scenegraph.general时,会打印"Window 0x7ffc8489c3d0 is determined to have broken vsync throttling ..."消息。这种方法的缺点是在一小部分帧之后才会激活,因为它首先需要收集数据来评估,这意味着在打开QQuickWindow时,应用程序可能仍会在短时间内显示过快的动画。此外,它可能无法捕获所有可能的vsync中断情况。
但请记住,根据设计,这些方法都无法帮助渲染线程动画(Animator 类型)。在没有基于垂直同步的阻塞的情况下,animators 默认会错误地推进,比预期的更快,即使为常规的 animations 启用了解决方法。如果这成为一个问题,考虑通过设置 QSG_USE_SIMPLE_ANIMATION_DRIVER 来使用替代的动画驱动。
注意
请注意,即使禁用了等待垂直同步(vsync),GUI(主)线程上的渲染循环逻辑和事件处理也不一定是无限制的:两个渲染循环都通过QWindow::requestUpdate()为窗口安排更新。在大多数平台上,这是由一个5毫秒的GUI线程计时器支持的,以便为事件处理留出时间。在某些平台上,例如macOS,它使用特定于平台的API(如CVDisplayLink)来获取准备新帧的适当时间的通知,这可能以某种形式与显示器的垂直同步相关联。这在基准测试和类似情况下可能是相关的。对于尝试执行低级基准测试的应用程序和工具,将QT_QPA_UPDATE_IDLE_TIME环境变量设置为0可能是有益的,以潜在地减少GUI线程上的空闲时间。对于正常的应用程序使用,在大多数情况下,默认设置应该是足够的。
注意
当有疑问时,启用qt.scenegraph.general和qt.scenegraph.time.renderloop日志类别进行故障排除,因为这些可能会揭示为什么渲染和动画没有以预期速度运行的一些线索。
使用QQuickRenderControl自定义渲染控制¶
当使用QQuickRenderControl时,驱动渲染循环的责任转移到应用程序。在这种情况下,不使用内置的渲染循环。相反,应用程序需要在适当的时间调用抛光、同步和渲染步骤。可以实现类似于上面所示的线程或非线程行为。
此外,应用程序可能希望结合QQuickRenderControl实现并安装自己的QAnimationDriver。这提供了对驱动Qt Quick动画的完全控制,这对于不显示在屏幕上的内容尤其重要,因为没有任何帧的呈现发生,所以与呈现速率无关。这是可选的,默认情况下动画将基于系统计时器前进。
使用基于QRhi和原生3D渲染扩展场景图¶
场景图提供了三种方法来集成应用程序提供的图形命令:
在场景图自身的渲染之前或之后直接发出基于QRhi或OpenGL、Vulkan、Metal、Direct3D的命令。这实际上是在主渲染通道中前置或追加一组绘制调用。不使用额外的渲染目标。
渲染到纹理并在场景图中创建一个带纹理的节点。这涉及到一个额外的渲染过程和渲染目标。
通过实例化场景图中的
QSGRenderNode子类,在场景图自身的渲染过程中内联发出绘制调用。这与第一种方法类似,但自定义的绘制调用有效地注入到场景图的命令流中。
底层/覆盖模式¶
通过连接到beforeRendering()和afterRendering()信号,应用程序可以直接在场景图渲染的同一上下文中进行QRhi或原生3D API调用。使用像Vulkan或Metal这样的API,应用程序可以通过QSGRendererInterface查询原生对象,例如场景图的命令缓冲区,并根据需要记录命令。正如信号名称所示,用户可以在Qt Quick场景下或之上渲染内容。以这种方式集成的好处是不需要额外的渲染目标来执行渲染,并且可能昂贵的纹理步骤被消除。缺点是自定义渲染只能在Qt Quick自身渲染的开始或结束时进行。使用QSGRenderNode而不是QQuickWindow信号可以在一定程度上解除这一限制,但在任何情况下,都必须小心处理3D内容和深度缓冲区的使用,因为依赖深度测试和启用深度写入的渲染很容易导致自定义内容和Qt Quick内容的深度缓冲区使用相互冲突。
从Qt 6.6开始,QRhi API被视为半公开的,即提供给应用程序并进行了文档记录,尽管兼容性保证有限。这允许通过使用场景图本身使用的相同图形和着色器抽象来创建可移植的跨平台2D/3D渲染代码。
场景图 - QML下的RHI示例展示了如何使用QRhi实现底层/覆盖层方法。
场景图 - QML下的OpenGL示例展示了如何使用这些信号与OpenGL结合。
场景图 - QML下的Direct3D 11示例展示了如何使用Direct3D使用这些信号的示例。
场景图 - QML下的Metal示例展示了如何使用这些信号与Metal结合。
场景图 - Vulkan 在 QML 下 示例展示了如何使用 Vulkan 使用这些信号。
从 Qt 6.0 开始,直接使用底层图形 API 必须通过调用 beginExternalCommands() 和 endExternalCommands() 来封装。这个概念可能类似于 QPainter::beginNativePainting(),并且具有类似的目的:它允许 Qt Quick 场景图识别当前记录的渲染通道中的任何缓存状态和假设(如果有的话)现在无效,因为应用程序代码可能通过直接使用底层图形 API 来更改它。在使用 QRhi 时,这不适用且不必要。
当将自定义的OpenGL渲染与场景图混合使用时,应用程序不应将OpenGL上下文留在绑定缓冲区、启用属性、z缓冲区或模板缓冲区中有特殊值或类似状态的状态中。这样做可能会导致不可预测的行为。
自定义渲染代码必须具有线程意识,即不应假设它在应用程序的GUI(主)线程上执行。当连接到QQuickWindow信号时,应用程序应使用Qt::DirectConnection,并理解连接的槽是在场景图的专用渲染线程上调用的(如果有的话)。
基于纹理的方法¶
当应用程序需要在Qt Quick场景中拥有某种自定义3D渲染的“扁平化”2D图像时,基于纹理的替代方案是最灵活的方法。这也允许使用独立于主渲染通道使用的缓冲区的专用深度/模板缓冲区。
在使用OpenGL时,可以使用传统的便利类QQuickFramebufferObject来实现这一点。基于QRhi的自定义渲染器和除OpenGL之外的其他图形API也可以遵循这种方法,尽管QQuickFramebufferObject目前不支持它们。以下示例展示了如何使用底层API直接创建和渲染到纹理,然后在自定义的QQuickItem中包装并使用此资源在Qt Quick场景中:
场景图 - RHI 纹理项 示例。
场景图 - Vulkan 纹理导入 示例。
场景图 - 金属纹理导入 示例。
内联方法¶
使用QSGRenderNode时,自定义绘制调用不是在场景图渲染通道录制的开始或结束时注入的,而是在场景图渲染过程中注入的。这是通过创建一个基于QSGRenderNode实例的自定义QQuickItem来实现的,QSGRenderNode是一个场景图节点,专门用于允许通过QRhi或原生3D API(如OpenGL、Vulkan、Metal或Direct 3D)发出图形命令。
场景图 - 自定义QSGRenderNode示例展示了这种方法。
使用QPainter的自定义项目¶
QQuickItem 提供了一个子类 QQuickPaintedItem,允许用户使用 QPainter 渲染内容。
警告
使用 QQuickPaintedItem 使用间接的2D表面来渲染其内容,无论是使用软件光栅化还是使用OpenGL帧缓冲对象(FBO),因此渲染是一个两步操作。首先光栅化表面,然后绘制表面。直接使用场景图API总是显著更快。
日志支持¶
场景图支持多种日志类别。这些类别不仅对Qt贡献者有帮助,而且在追踪性能问题和错误时也非常有用。
qt.scenegraph.time.texture- 记录进行纹理上传所花费的时间
qt.scenegraph.time.compilation- 记录进行着色器编译所花费的时间
qt.scenegraph.time.renderer- 记录渲染器在各个步骤中花费的时间
qt.scenegraph.time.renderloop- 记录渲染循环中各个步骤所花费的时间。使用threaded渲染循环时,这可以深入了解GUI和渲染线程上各个帧准备步骤之间所经过的时间。因此,它也可以是一个有用的故障排除工具,例如,确认基于vsync的节流和其他低级Qt启用器(如QWindow::requestUpdate())如何影响渲染和呈现管道。
qt.scenegraph.time.glyph- 记录准备距离场字形所花费的时间
qt.scenegraph.general- 记录场景图和图形堆栈各个部分的常规信息
qt.scenegraph.renderloop- 创建渲染过程中各个阶段的详细日志。此日志模式主要对从事Qt开发的开发人员有用。
传统的 QSG_INFO 环境变量也可用。将其设置为非零值将启用 qt.scenegraph.general 类别。
注意
当遇到图形问题,或不确定使用哪个渲染循环或图形API时,始终启动应用程序时至少启用qt.scenegraph.general和qt.rhi.*,或设置QSG_INFO=1。这将在初始化期间将一些重要信息打印到调试输出中。
场景图后端¶
除了公共API之外,场景图还有一个适配层,该层开放了实现以进行硬件特定的适配。这是一个未记录的、内部的和私有的插件API,它使硬件适配团队能够充分利用他们的硬件。它包括:
自定义纹理;特别是
createTextureFromImage的实现以及Image和BorderImage类型使用的纹理的内部表示。自定义渲染器;适配层允许插件决定场景图的遍历和渲染方式,从而可以针对特定硬件优化渲染算法或利用提高性能的扩展。
许多默认QML类型的自定义场景图实现,包括其文本和字体渲染。
自定义动画驱动程序;允许动画系统连接到低级别的显示垂直刷新以实现平滑渲染。
自定义渲染循环;允许更好地控制QML如何处理多个窗口。