QSGRenderNode 类

QSGRenderNode 类表示一组针对场景图中使用的图形 API 定制的渲染命令。更多...

头文件 #include <QSGRenderNode>
CMakefind_package(Qt6 REQUIRED COMPONENTS Quick)
target_link_libraries(mytarget PRIVATE Qt6::Quick)
qmakeQT += quick
继承 QSGNode

公共类型

枚举RenderingFlag { BoundedRectRendering, DepthAwareRendering, OpaqueRendering, NoExternalRendering }
标志RenderingFlags
枚举StateFlag { DepthState, StencilState, ScissorState, ColorState, BlendState, …, RenderTargetState }
标志StateFlags

公共函数

virtual~QSGRenderNode() override
virtual QSGRenderNode::StateFlagschangedStates() const
const QSGClipNode *clipList() const
(since 6.6) QRhiCommandBuffer *commandBuffer() const
virtual QSGRenderNode::RenderingFlagsflags() const
qrealinheritedOpacity() const
const QMatrix4x4 *matrix() const
(since 6.0) virtual voidprepare()
(since 6.5) const QMatrix4x4 *projectionMatrix() const
virtual QRectFrect() const
virtual voidreleaseResources()
virtual voidrender(const QSGRenderNode::RenderState *state) = 0
(since 6.6) QRhiRenderTarget *renderTarget() const

详细描述

QSGRenderNode 允许通过 QRhi 创建场景图节点以执行自己的自定义渲染(从 Qt 6.6 开始的常用方法),直接通过 3D 图形 API(如 OpenGL、Vulkan 或 Metal),或者在软件后端程序使用时,通过 QPainter

QSGRenderNode 是将自定义 2D/3D 渲染集成到 Qt Quick 场景的三种方法之一。其他两种方法是:在 Qt Quick 场景的自身渲染之前或之后执行渲染,或生成一个针对专用渲染目标(纹理)的整个独立的渲染过程,然后在场景的一个项目中显示这个纹理。基于 QSGRenderNode 的方法与前者类似,因为不涉及额外的渲染过程或渲染目标,并允许在 Qt Quick 场景的自身渲染中“内联”注入自定义渲染命令。

另请参阅场景图 - 自定义 QSGRenderNode

成员类型文档

QSGRenderNode::RenderingFlag枚举
QSGRenderNode::RenderingFlags 标志项

flags() 返回的位掩码的可能值。

常量描述
QSGRenderNode::BoundedRectRendering0x01指示 render() 的实现不渲染在项目坐标中由 rect() 报告的区域之外。这样的节点实现可以导致更有效的渲染,具体取决于场景图的底层。例如,软件 后端可以继续使用更优的局部更新路径,前提是场景中所有渲染节点都设置了此标志。
QSGRenderNode::DepthAwareRendering0x02指示 render() 的实现通过仅生成场景坐标中为 0 的 Z 值,并通过从 RenderState::projectionMatrix() 和 matrix() 获取的矩阵来转换,从而符合场景图期望,如 render() 的说明中所述。这样的节点实现可以导致更有效的渲染,具体取决于场景图的底层。例如,当场景中所有渲染节点都设置了此标志时,批处理 OpenGL 渲染器可以继续使用更优的路径。
QSGRenderNode::OpaqueRendering0x04指示 render() 的实现为从 rect() 报告的整个区域写入不透明像素。默认情况下,渲染器必须假设 render() 也可以输出半透明或全透明像素。设置此标志可以在某些情况下提高性能。
QSGRenderNode::NoExternalRendering0x08指示 prepare() 和 render() 的实现使用 QRhi 系列的 API,而不是直接调用 OpenGL、Vulkan 或 Metal 等三维 API。

RenderingFlags 类型是 QFlags<RenderingFlag> 的typedef。它存储 RenderingFlag 值的逻辑或组合。

另请参阅render(),prepare(),rect() 以及 QRhi

枚举 QSGRenderNode::StateFlag
QSGRenderNode::StateFlags 标志项

此枚举是用于识别多个状态的位掩码。

常量描述
QSGRenderNode::DepthState0x01深度
QSGRenderNode::StencilState0x02模板缓冲区
QSGRenderNode::ScissorState0x04裁剪
QSGRenderNode::ColorState0x08颜色
QSGRenderNode::BlendState0x10混合
QSGRenderNode::CullState0x20消除隐藏面
QSGRenderNode::ViewportState0x40视口
QSGRenderNode::RenderTargetState0x80渲染目标

StateFlags 类型是 QFlags<StateFlag> 的typedef。它存储 StateFlag 值的逻辑或组合。

成员函数文档

[重载虚析构函数无异常] QSGRenderNode::~QSGRenderNode()

销毁渲染节点。派生类预计在这里执行类似于 releaseResources() 的清理。

当使用低级图形API时,场景图将确保在删除场景图的节点之前,CPU端会等待GPU完成提交给场景图的图形命令队列的所有工作。因此,在此处无需发出额外的等待指令,除非render()实现正在使用额外的命令队列。

使用QRhi和如QRhiBufferQRhiTextureQRhiGraphicsPipeline等资源时,通常建议使用智能指针,例如std::unique_ptr,这通常可以避免实现析构函数的需要,并导致代码更加紧凑。然而,请记住,实现releaseResources(),大多数情况下在unique_ptr上进行多个reset()调用,仍然很重要。

另请参阅 releaseResources

[虚拟] QSGRenderNode::StateFlags QSGRenderNode::changedStates() const

当底层渲染API为OpenGL时,此函数应返回一个掩码,其中每个位表示由render()函数更改的图形状态

常量描述
深度状态深度写入掩码,启用深度测试,深度比较函数
模板状态模板写入掩码,启用模板测试,模板操作,模板比较函数
剪切状态启用剪切,启用剪切测试
颜色状态清除颜色,颜色写入掩码
混合状态启用混合,混合函数
剔除状态前面向量,启用剔除面
视口状态视口
渲染目标状态渲染目标

对于OpenGL以外的API,只有与命令列表/缓冲区上记录的动态状态更改相关联的值才是相关的。例如,在D3D11的情况下,RSSetViewports、RSSetScissorRects、OMSetBlendState、OMSetDepthStencilState,或者在Vulkan的情况下,vkCmdSetViewport、vkCmdSetScissor、vkCmdSetBlendConstants、vkCmdSetStencilRef,只有在将这些命令添加到通过QSGRendererInterface::CommandList资源枚举查询的场景图的命令列表的情况下才如此。在管道状态对象中设置的状态不需要在此处报告。同样,与绘制调用相关的设置(管道状态、描述符集、顶点或索引缓冲区绑定、根签名、描述符堆等)总是由场景图再次设置,因此render()可以自由地更改它们。

RenderTargetState不再支持Vulkan之类的API。这是其本性。在Qt Quick场景图主命令缓冲区记录渲染pass时,将调用render(),因此不可能更改目标和启动另一个renderpass(至少在该命令缓冲区上)。因此,返回带有RenderTargetState设置的值是不合理的。

注意: 软件后端暴露了其QPainter并在调用render()前后进行保存和恢复。因此,此处报告任何更改过的状态是不必要的。

该函数由渲染器调用,以便在渲染此节点之后重置状态。这使得render()的实现更简单,因为它不必查询和恢复这些状态。

默认实现返回0,表示在render()中没有更改任何相关状态。

注意: 此函数可能在render()之前调用。

注意: 在Qt 6和基于QRhi的渲染中,只有ViewportStateScissorState是相关值。其他值可以返回但实际中会被忽略。

常量 QSGClipNode *QSGRenderNode::clipList() const

返回当前剪辑列表。

[自 6.6] QRhiCommandBuffer *QSGRenderNode::commandBuffer() const

返回当前命令缓冲区。

此函数是在 Qt 6.6 中引入的。

另请参阅renderTarget

[虚函数] QSGRenderNode::RenderingFlags QSGRenderNode::flags() const

返回描述此渲染节点行为的标志。

默认实现返回 0。

另请参阅RenderingFlagrect

qreal QSGRenderNode::inheritedOpacity() const

返回当前有效不透明度。

const QMatrix4x4 *QSGRenderNode::matrix() const

返回指向当前模型视图矩阵的指针。

[虚拟,自 6.0] void QSGRenderNode::prepare()

在帧准备阶段调用。在调用 render 之前会调用此函数。

render 不同,此函数在_scenegraph_开始记录当前帧的渲染通道之前被调用。这在使用图形API(如Vulkan)进行渲染时很有用,因为在渲染通道之前需要记录操作类型。

默认实现为空。

当实现一个使用 QRhi 渲染的 QSGRenderNode 时,通过调用 QQuickWindowQQuickWindow::rhi() 从 QRhi 对象。要获取提交工作要调用的 QRhiCommandBuffer,请调用 commandBuffer()。要查询活动渲染目标的信息,请调用 renderTarget()。有关详细信息,请参阅 {场景图 - 自定义 QSGRenderNode} 例子。

此函数是在 Qt 6.0 中引入的。

[自 6.5] const QMatrix4x4 *QSGRenderNode::projectionMatrix() const

返回指向当前投影矩阵的指针。

render() 中,这是与从 RenderState::projectionMatrix 返回的相同的矩阵。此获取器存在,以便在 prepare() 中也可以查询投影矩阵。

在处理现代图形API或Qt自己的图形抽象层时,很可能需要将 *projectionMatrix() * *matrix() 加载到统一缓冲区。然而,这是一个需要在 prepare 中完成的操作,且在记录渲染通道之外。这就是为什么可以直接从 QSGRenderNode 查询两个矩阵,在 preparerender 中都可以查询。

此函数是在 Qt 6.5 中引入的。

[虚拟] QRectF QSGRenderNode::rect() const

获取受render()影响的区域的边界矩形(以项目坐标为单位)。此值仅在flags()包含BoundedRectRendering时使用,否则忽略。

软件后端,报告与BoundedRectRendering一起的矩形特别重要,因为否则在场景中具有渲染节点将触发全屏更新,跳过所有部分更新优化。

对于覆盖相应QQuickItem整个区域的渲染节点,返回值将为(0, 0, item->width(), item->height())。

注意:节点还可以在项目宽度和高度的界限之外渲染,因为场景图节点不是由QQuickItem几何形状界定的,只要这个函数正确报告即可。

另请参阅:flags()。

[纯虚] void QSGRenderNode::releaseResources()

当所有通过此节点分配的定制图形资源都必须立即释放时,将调用此函数。如果节点没有通过使用的图形API(缓冲区、纹理、渲染目标、栅栏等)直接分配图形资源,则在这里没有要做的。

未能释放所有自定义资源可能导致某些系统在图形设备丢失场景中出现不正确的行为,因为后续的图形系统重新初始化可能失败。

注意:某些场景图后端可能选择不调用此函数。因此,预计QSGRenderNode实现将在其析构函数和releaseResources()中进行清理。

与析构函数不同,预计在调用releaseResources()之后调用它时,render()可以重新初始化其所需的全部资源。

使用OpenGL时,在调用析构函数和此函数时,场景图的OpenGL上下文都是当前上下文。

[纯虚] void QSGRenderNode::render(const QSGRenderNode::RenderState *state)

此函数由渲染器调用,应该使用当前使用的图形API(OpenGL、Direct3D等)直接调用命令来绘制此节点。

可以使用inheritedOpacity()检索实际的不透明度。

可以通过state获取投影矩阵,使用matrix()可以检索模型视图矩阵。然后组合矩阵是投影矩阵乘以模型视图矩阵。场景中项目的正确堆叠是通过投影矩阵保证的。

当使用提供的矩阵时,顶点数据的坐标系遵循QQuickItem的传统约定:左上角为(0, 0),右下角为相应的QQuickItem的宽度()和高度()减一。例如,假设每个顶点有两个浮点(x-y)坐标,则可以指定一个占据项目一半宽度的三角形,为(宽度 - 1, 高度 - 1),(0, 0),(0, 高度 - 1),使用逆时针方向。

注意:QSGRenderNode相对于基于纹理的方法(例如,QQuickFramebufferObject)在性能上有显著的提升,尤其是在片段处理能力有限的系统上。这是因为它避免了渲染到纹理然后绘制纹理四边形的操作。相反,QSGRenderNode允许在场景图其他命令的同时录制绘制调用,从而避免额外的渲染目标和昂贵的纹理混合。

裁剪信息在函数被调用之前计算。希望考虑裁剪的实现可以根据状态中的信息设置剪裁或模板。模板缓冲区用必要的裁剪形状填充,但启用模板测试是由实现来决定的。

有些场景图后端,特别是软件后端,不使用剪裁或模板。那里,裁剪区域作为一个普通的QRegion提供。

当实现一个使用 QRhi 渲染的 QSGRenderNode 时,通过调用 QQuickWindowQQuickWindow::rhi() 从 QRhi 对象。要获取提交工作要调用的 QRhiCommandBuffer,请调用 commandBuffer()。要查询活动渲染目标的信息,请调用 renderTarget()。有关详细信息,请参阅 {场景图 - 自定义 QSGRenderNode} 例子。

在Qt 6及其基于QRhi的场景图渲染器中,当调用此函数时,不应假设活动的(OpenGL)状态,即使在使用OpenGL时也是如此。在调用此函数时,不要假设命令列表/缓冲区上绑定的管道和动态状态。

注意:预期不会启用深度写入。启用深度写入可能会导致根据所使用的场景图后端和场景内容出现意外结果,因此请谨慎操作。

注意:在Qt 6中,changedStates()的使用有限。请参阅changedStates()的文档以获取更多信息。

在某些图形API中,包括直接使用QRhi时,可能需要重新实现prepare(),或者作为可选方案,连接到QQuickWindow::beforeRendering()信号。这些在命令缓冲区上记录渲染阶段开始之前(Vulkan中的vkCmdBeginRenderPass或Metal中通过MTLRenderCommandEncoder开始编码)之前被调用/发射。这样API中不能在render()函数内部执行复制操作。而是,这样的操作需要在prepare()中完成或者在连接到beforeRendering的槽中进行(使用DirectConnection)。

另请参阅:QSGRendererInterfaceQQuickWindow::rendererInterface

[since 6.6] QRhiRenderTarget *QSGRenderNode::renderTarget() const

返回当前的渲染目标。

这主要提供启用prepare()和render()实现,使得使用QRhi的实现可以访问QRhiRenderTargetrenderPassDescriptor像素大小

要构建一个QRhiGraphicsPipeline,这意味着需要提供一个QRhiRenderPassDescriptor,从渲染目标查询renderPassDescriptor。但请注意,渲染目标可能会在自定义QQuickItemQSGRenderNode的整个生命周期内发生变化。例如,考虑当在项目或其祖先上动态设置layer.enabled: true时会发生什么:这将在纹理中触发渲染,而不是直接到窗口,这意味着QSGRenderNode将从此工作在不同的渲染目标上。新的渲染目标可能具有不同的像素格式,这可能使已经构建的图形管道不兼容。这可以通过以下逻辑处理

if (m_pipeline && renderTarget()->renderPassDescriptor()->serializedFormat() != m_renderPassFormat) {
    delete m_pipeline;
    m_pipeline = nullptr;
}
if (!m_pipeline) {
    // Build a new QRhiGraphicsPipeline.
    // ...
    // Store the serialized format for fast and simple comparisons later on.
    m_renderPassFormat = renderTarget()->renderPassDescriptor()->serializedFormat();
}

此函数是在 Qt 6.6 中引入的。

另请参阅:commandBuffer

© 2024 Qt公司有限公司。本文件中包含的文档贡献是各自所有者的版权。所提供的文档在自由软件基金会发布的GNU自由文档许可协议1.3条款下提供。