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