- class QQuickRenderControl#
QQuickRenderControl类提供了一个机制,可以在完全由应用程序控制的方式下将 Qt Quick 场景图渲染到离屏渲染目标。更多信息...概述#
方法#
def
__init__()def
beginFrame()def
commandBuffer()def
endFrame()def
initialize()def
invalidate()def
polishItems()def
prepareThread()def
render()def
rhi()def
samples()def
setSamples()def
sync()def
window()
虚拟方法#
def
renderWindow()
信号#
静态函数#
备注
本文档可能包含自动从 C++ 翻译到 Python 的代码片段。我们始终欢迎对片段翻译的贡献。如果您发现翻译有问题,也可以通过在 https:/bugreports.qt.io/projects/PYSIDE 上创建工单的方式来告诉我们。
详细描述#
QQuickWindow和QQuickView以及它们的关联内部渲染循环在原生窗口上渲染 Qt Quick 场景。在某些情况下,例如与第三方 OpenGL、Vulkan、Metal 或 Direct 3D 渲染器集成时,将场景放入可由外部渲染引擎任意使用的纹理中非常有用。这种机制在集成 VR 框架时也是必不可少的。与其他导致性能下降的替代方案(如使用grabWindow())不同,QQuickRenderControl以硬件加速的方式实现了这一功能。在使用
QQuickRenderControl时,QQuickWindow必须不可见(它不会在屏幕上可见),并且将没有底层的原生窗口。相反,QQuickWindow实例与渲染控制对象关联,使用QQuickWindow构造函数的重载,以及通过setRenderTarget()指定的纹理或图像对象关联。尽管QQuickWindow对象仍然是必需的,因为它代表着 Qt Quick 场景,并提供了大量场景管理和事件传递机制,但它并不会作为窗口系统视角下的实际屏幕窗口。图形设备、上下文、图像和纹理对象的管理由应用程序负责。在调用
initialize()之前,必须创建将使用 Qt Quick 的设备或上下文。纹理对象的创建可以延迟,请参阅下文。Qt 5.4 引入了 QOpenGLContext 采取现有本地上下文的能力。与QQuickRenderControl结合,这使得可以创建一个与外部渲染引擎现有上下文共享的 QOpenGLContext。此新的 QOpenGLContext 可以用于将 Qt Quick 场景渲染到其他引擎的上下文可访问的纹理中。对于 Vulkan、Metal 和 Direct 3D,没有为设备对象提供 Qt 提供的包装器,因此现有的可以原样通过setGraphicsDevice()传递。通过 QQmlEngine 实现加载和实例化 QML 组件。一旦创建了根对象,它需要将其关联到
QQuickWindow的 contentItem()。应用程序通常需要连接到 4 个重要的信号
sceneGraphInitialized()推出在调用initialize()之后的某个时刻。在此信号上,应用程序预计将创建其帧缓冲区对象并将其关联到QQuickWindow。sceneGraphInvalidated()当场景图资源被释放时,帧缓冲区对象也可以被销毁。renderRequested()表示场景必须通过调用render()进行渲染。在使上下文成为当前上下文后,应用程序预计将调用render()。sceneChanged()表示场景已更改,这意味着在渲染之前,还需要进行抛光和同步。
要向场景发送事件,例如鼠标或键盘事件,请使用 QCoreApplication::sendEvent() 并以
QQuickWindow实例作为接收者。对于关键事件,可能还需要手动将焦点设置到所需的项目上。在实践中,这涉及到在项目与场景关联之后(例如,场景的根项目,
QQuickWindow),调用forceActiveFocus()。备注
一般来说,《
QQuickRenderControl》与所有Qt Quick后端兼容。然而,某些功能,尤其是在某些情况下,可能无法使用grab()。构建一个具有父对象
parent的QQuickRenderControl对象。- beginFrame()#
指定图形帧的开始。在对
sync()或render()的调用中必须包含对beginFrame()和endFrame()的调用。与Qt 5早期仅支持OpenGL的世界不同,使用其他图形API进行渲染需要更明确的帧开始和结束点。当通过
QQuickRenderControl手动驱动渲染循环时,现在必须由QQuickRenderControl的用户指定这些点。一个典型的更新步骤,包括将渲染初始化到一个现有的纹理中,可能如下所示。示例代码片段假设Direct3D 11,但也适用于其他图形API。
if (!m_quickInitialized) { m_quickWindow->setGraphicsDevice(QQuickGraphicsDevice::fromDeviceAndContext(m_engine->device(), m_engine->context())); if (!m_renderControl->initialize()) qWarning("Failed to initialize redirected Qt Quick rendering"); m_quickWindow->setRenderTarget(QQuickRenderTarget::fromNativeTexture({ quint64(m_res.texture), 0 }, QSize(QML_WIDTH, QML_HEIGHT), SAMPLE_COUNT)); m_quickInitialized = true; } m_renderControl->polishItems(); m_renderControl->beginFrame(); m_renderControl->sync(); m_renderControl->render(); m_renderControl->endFrame(); // Qt Quick's rendering commands are submitted to the device context here备注
在使用Qt Quick的
software版本时,不需要也不应该调用此函数。备注
内部,
beginFrame()和endFrame()分别调用beginOffscreenFrame()和endOffscreenFrame()。这意味着在调用此函数时,QRhi上不能有任何帧(无论是离屏帧还是基于swapchain的帧)正在记录。- commandBuffer()#
- 返回类型:
QRhiCommandBuffer
返回当前命令缓冲区。
调用
beginFrame()后,将自动设置 QRhiCommandBuffer。这是 Qt Quick 场景图使用的命令缓冲区,但在某些情况下,应用程序可能还需要查询它,例如进行资源更新(例如,纹理读取回)。返回的命令缓冲区引用仅在
beginFrame()和endFrame()之间使用。存在一些特定异常,例如在endFrame()之后和下次beginFrame()之前调用 lastCompletedGpuTime() 是有效的。- endFrame()#
指定图形框架的结束。调用
sync()或render()必须在beginFrame()和 endFrame() 之间进行。当调用此函数时,由场景图排队的所有图形命令将被提交到上下文或命令队列,具体取决于应用场景。
备注
在使用Qt Quick的
software版本时,不需要也不应该调用此函数。- initialize()#
- 返回类型:
bool
初始化场景图资源。当使用例如 Vulkan、Metal、OpenGL 或 Direct3D 等图形 API 渲染 Qt Quick 时,在调用此函数时,
QQuickRenderControl将设置适当的渲染引擎。这个渲染基础设施存在直到QQuickRenderControl存在。要控制 Qt Quick 使用哪个图形 API,在被调用此函数之前,使用
setGraphicsApi()并传入QSGRendererInterface的 :GraphicsApi 常量进行操作。为了防止场景图创建自己的设备和上下文对象,通过调用
setGraphicsDevice()方法,指定适当的QQuickGraphicsDevice,来包装现有的图形对象。要配置哪些设备扩展要启用(例如,对于 Vulkan),在调用此函数之前调用
setGraphicsConfiguration()。备注
在使用 Vulkan 的时候,
QQuickRenderControl并不会自动创建一个 QVulkanInstance。相反,创建一个合适的 QVulkanInstance 并将其与QQuickWindow关联是应用程序的责任。在初始化 QVulkanInstance 之前,强烈建议通过调用静态函数preferredInstanceExtensions()来查询 Qt Quick 期望的实例扩展列表,并将返回的列表传递给 QVulkanInstance::setExtensions()。成功返回
true,否则返回false。备注
在使用Qt Quick的
software版本时,不需要也不应该调用此函数。使用默认的 Qt Quick 适配时,此函数将创建一个新的 QRhi 对象,类似于在没有使用
QQuickRenderControl的情况下,屏幕上的QQuickWindow发生的情况。为了使这个新的 QRhi 对象采用一些现有的设备或上下文资源(例如,使用现有的 QOpenGLContext 而不是创建一个新的),请使用上面提到的setGraphicsDevice()。当应用程序想要让 Qt Quick 渲染使用现有的 QRhi 对象时,这同样是可能的,可以通过fromRhi()实现。当设置一个引用现有 QRhi 的QQuickGraphicsDevice时,init() 函数中将不会创建新的 QRhi 对象。- invalidate()#
停止渲染并释放资源。
这相当于当窗口变为隐藏时,真实的
QQuickWindow执行的清理操作。这个函数是从析构函数中调用的。因此通常不需要直接调用它。
一旦调用了 invalidate(),就可以通过再次调用
initialize()来重用QQuickRenderControl实例。备注
此函数不考虑QQuickWindow::persistentSceneGraph()或QQuickWindow::persistentGraphics()。这意味着上下文特定的资源总是会被释放。
- polishItems()#
此函数应该在调用
sync()之前尽可能晚地调用。在多线程场景中,渲染可以与此函数并行进行。准备在GUI线程之外渲染Qt Quick场景。
targetThread指定将在其上发生同步和渲染的线程。在单线程场景中不需要调用此函数。- render()#
使用当前上下文渲染场景图。
- renderRequested()#
当场景图需要渲染时,发出此信号。不需要调用
sync()。备注
避免在发出此信号时直接触发渲染。例如,最好通过使用计时器等延迟它。这样可以提高性能。
在子类中重实现以返回此渲染控制正在渲染到的实际窗口。
如果
offset非空,它将设置为控制在此窗口内的偏移。备注
虽然不是强制性的,但在支持不同设备像素比的多屏幕以及正确定位从QML打开的弹出窗口时,重写此函数变得至关重要。因此,在子类中提供它是非常推荐的。
- 静态 renderWindowFor(win[, offset=None])#
- 参数:
win –
QQuickWindowoffset –
QPoint
- 返回类型:
如果有的话,返回
win被渲染到的实际窗口。如果
offset非空,它将设置为在该窗口内的渲染偏移。- rhi()#
- 返回类型:
QRhi
返回与此
QQuickRenderControl关联的QRhi。备注
当
initialize()函数成功完成后,QRhi 才存在。在此之前,返回值是 null。- samples()#
- 返回类型:
int
返回当前采样数量。1 或 0 表示无多采样。
参阅
- sceneChanged()#
当场景图更新时,会发出此信号,意味着需要调用
polishItems()和sync()。如果sync()返回 true,则需要调用render()。备注
在发出此信号时,避免直接触发抛光、同步和渲染。相反,最好使用定时器等来延迟处理。这将提高性能。
- setSamples(sampleCount)#
- 参数:
sampleCount – int
设置用于多采样的样本数。当
sampleCount为 0 或 1 时,禁用多采样。备注
此函数通常与多采样渲染目标一起使用,这意味着
sampleCount必须与传递给 QQuickRenderTarget::fromNativeTexture() 的样本数匹配,而 QQuickRenderTarget::fromNativeTexture() 的样本数必须与原生纹理的样本数匹配。- sync()#
- 返回类型:
bool
此函数用于同步 QML 场景与渲染场景图。
如果使用专用渲染线程,则在调用此函数期间应阻塞 GUI 线程。
如果同步改变了场景图,则返回 true。
- window()#
- 返回类型:
返回与此
QQuickWindow相关的QQuickRenderControl。备注
QQuickRenderControl在构造QQuickWindow时与QQuickWindow关联。在此点之前此函数的返回值为空。