QQuickRhiItem Class
QQuickRhiItem 类是QQuickFramebufferObject 的一种可移植替代方案,它不依赖于 OpenGL,而是允许通过Qt Quick 将渲染与QRhi 中的 API 集成。更多内容...
| 头文件: | #include <QQuickRhiItem> |
| CMake: | find_package(Qt6 REQUIRED COMPONENTS Quick) target_link_libraries(mytarget PRIVATE Qt6::Quick) |
| qmake: | QT += quick |
| 自: | Qt 6.7 |
| 继承自: | QQuickItem |
公共类型
| enum class | TextureFormat { RGBA8, RGBA16F, RGBA32F, RGB10A2 } |
属性
|
|
公共函数
| QQuickRhiItem(QQuickItem *parent = nullptr) | |
| virtual | ~QQuickRhiItem() override |
| bool | alphaBlending() const |
| QQuickRhiItem::TextureFormat | colorBufferFormat() const |
| QSize | effectiveColorBufferSize() const |
| int | fixedColorBufferHeight() const |
| int | fixedColorBufferWidth() const |
| bool | isMirrorVerticallyEnabled() const |
| int | sampleCount() const |
| void | setAlphaBlending(bool enable) |
| void | setColorBufferFormat(QQuickRhiItem::TextureFormat format) |
| void | setFixedColorBufferHeight(int height) |
| void | setFixedColorBufferWidth(int width) |
| void | setMirrorVertically(bool enable) |
| void | setSampleCount(int samples) |
重新实现的公共函数
| virtual bool | isTextureProvider() const override |
| virtual QSGTextureProvider * | textureProvider() const override |
信号
| void | alphaBlendingChanged() |
| void | colorBufferFormatChanged() |
| void | effectiveColorBufferSizeChanged() |
| void | fixedColorBufferHeightChanged() |
| void | fixedColorBufferWidthChanged() |
| void | mirrorVerticallyChanged() |
| void | sampleCountChanged() |
受保护函数
| virtual QQuickRhiItemRenderer * | createRenderer() = 0 |
| bool | isAutoRenderTargetEnabled() const |
| void | setAutoRenderTarget(bool enabled) |
重新实现的受保护函数
| virtual bool | event(QEvent *e) override |
| virtual void | geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override |
| virtual void | releaseResources() override |
详细说明
在Qt Quick 中,QQuickRhiItem实际上是QRhiWidget 的对应类。这两个类都旨在被子类化,并且都能支持基于QRhi 的渲染,其目标是离屏颜色缓冲区。生成的2D图像随后会与Qt Quick 场景的其余部分进行合成。
注意:虽然 QQuickRhiItem 是 Qt 的公共 API,但 Qt GUI 模块中的QRhi 类族(包括QShader 和QShaderDescription )仅提供有限的兼容性保证。这些类不提供源代码或二进制兼容性保证,这意味着该 API 仅保证与应用程序开发时所基于的 Qt 版本兼容。 不过,源代码不兼容的更改将尽可能控制在最低限度,且仅会在次要版本(如 6.7、6.8 等)中进行。qquickrhiitem.h 并未直接包含任何与QRhi 相关的头文件。 若要在实现 QQuickRhiItem 子类时使用这些类,请链接到Qt::GuiPrivate (如果使用 CMake),并包含带有rhi 前缀的相应头文件,例如#include <rhi/qrhi.h> 。
QQuickRhiItem 是对旧版QQuickFramebufferObject 类的替代。后者本质上与 OpenGL / OpenGL ES 绑定,而 QQuickRhiItem 与QRhi 类配合使用,允许在 Vulkan、Metal、Direct 3D 11/12 以及 OpenGL / OpenGL ES 上运行相同的渲染代码。 从概念和功能上来看,它们非常相似,因此从QQuickFramebufferObject 迁移到 QQuickRhiItem 非常简单。QQuickFramebufferObject 仍将继续提供,以确保与直接使用 OpenGL API 的现有应用程序代码的兼容性。
注意: 在使用software 适配的Qt Quick 场景图时,QQuickRhiItem 将无法正常工作。
在大多数平台上,场景图的渲染(以及由此产生的由 QQuickRhiItem 执行的渲染)将在专用线程上进行。因此,QQuickRhiItem 类强制要求项目实现(即QQuickItem 的子类)与实际渲染逻辑之间保持严格分离。 所有项目逻辑(例如向 QML 暴露的属性及与 UI 相关的辅助函数)都必须位于 QQuickRhiItem 子类中。一切与渲染相关的内容都必须位于QQuickRhiItemRenderer 类中。为避免两个线程引发的竞争条件和读写冲突,渲染器与项目绝不能读取或写入共享变量,这一点至关重要。 项与渲染器之间的通信应主要通过 QQuickRhiItem::synchronize() 函数进行。该函数将在渲染线程上被调用,而此时 GUI 线程会被阻塞。也可以使用队列连接或事件来实现项与渲染器之间的通信。
应用程序必须同时继承 QQuickRhiItem 和QQuickRhiItemRenderer 。必须重写纯虚函数createRenderer(),使其返回QQuickRhiItemRenderer 子类的全新实例。
与QRhiWidget 类似,QQuickRhiItem会自动管理颜色缓冲区,该缓冲区通常是一个2D纹理(QRhiTexture ),而在使用多采样时则为QRhiRenderBuffer 。 (某些 3D API 会区分纹理和渲染缓冲区,而另一些 API 中底层原生资源则是相同的;渲染缓冲区主要用于支持 OpenGL ES 3.0 中的多采样)
纹理的大小默认会根据项的大小进行调整(同时会考虑device pixel ratio 的值)。如果项的大小发生变化,系统会重新创建具有正确大小的纹理。如果希望使用固定大小,请将fixedColorBufferWidth 和fixedColorBufferHeight 设置为非零值。
QQuickRhiItem 是一个texture provider ,可直接用于ShaderEffects 以及其他使用纹理提供程序的类中。
虽然这不是主要用例,但 QQuickRhiItem 还允许集成直接使用 Vulkan、Metal、Direct 3D 或 OpenGL 等 3D 图形 API 的渲染代码。 有关在QRhi 渲染通道中记录原生命令的详细信息,请参阅QRhiCommandBuffer::beginExternal();有关如何封装现有原生纹理,然后在后续渲染通道中通过QRhi 使用该纹理的方法,请参阅QRhiTexture::createFrom()。 另请参阅QQuickGraphicsConfiguration ,了解有关配置原生 3D API 环境(例如设备扩展)的信息,并请注意,可以通过尽早调用QWindow::setVulkanInstance() 将QQuickWindow 与自定义的QVulkanInstance 关联起来。
注意:QQuickRhiItem始终 使用与QQuickWindow 相同的QRhi 实例(进而使用相同的OpenGL上下文、Vulkan设备等)。若要选择使用哪种底层3D图形API,请尽早对QQuickWindow 调用setGraphicsApi()。 一旦场景图初始化完成,便无法再进行更改,且场景中的所有 QQuickRhiItem 实例都将使用相同的 3D API 进行渲染。
一个简单示例
以下是 QQuickRhiItem 的一个子类。此处展示了其完整代码。它通过透视投影渲染一个三角形,该三角形会根据自定义项的angle 属性进行旋转。(这意味着它可以通过 QML 中的NumberAnimation 等动画进行驱动)
class ExampleRhiItemRenderer : public QQuickRhiItemRenderer
{
public:
void initialize(QRhiCommandBuffer *cb) override;
void synchronize(QQuickRhiItem *item) override;
void render(QRhiCommandBuffer *cb) override;
private:
QRhi *m_rhi = nullptr;
std::unique_ptr<QRhiBuffer> m_vbuf;
std::unique_ptr<QRhiBuffer> m_ubuf;
std::unique_ptr<QRhiShaderResourceBindings> m_srb;
std::unique_ptr<QRhiGraphicsPipeline> m_pipeline;
QMatrix4x4 m_viewProjection;
float m_angle = 0.0f;
};
class ExampleRhiItem : public QQuickRhiItem
{
Q_OBJECT
QML_NAMED_ELEMENT(ExampleRhiItem)
Q_PROPERTY(float angle READ angle WRITE setAngle NOTIFY angleChanged)
public:
QQuickRhiItemRenderer *createRenderer() override;
float angle() const { return m_angle; }
void setAngle(float a);
signals:
void angleChanged();
private:
float m_angle = 0.0f;
};
QQuickRhiItemRenderer *ExampleRhiItem::createRenderer()
{
return new ExampleRhiItemRenderer;
}
void ExampleRhiItem::setAngle(float a)
{
if (m_angle == a)
return;
m_angle = a;
emit angleChanged();
update();
}
void ExampleRhiItemRenderer::synchronize(QQuickRhiItem *rhiItem)
{
ExampleRhiItem *item = static_cast<ExampleRhiItem *>(rhiItem);
if (item->angle() != m_angle)
m_angle = item->angle();
}
static QShader getShader(const QString &name)
{
QFile f(name);
return f.open(QIODevice::ReadOnly) ? QShader::fromSerialized(f.readAll()) : QShader();
}
static float vertexData[] = {
0.0f, 0.5f, 1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, -0.5f, 0.0f, 0.0f, 1.0f,
};
void ExampleRhiItemRenderer::initialize(QRhiCommandBuffer *cb)
{
if (m_rhi != rhi()) {
m_pipeline.reset();
m_rhi = rhi();
}
if (!m_pipeline) {
m_vbuf.reset(m_rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData)));
m_vbuf->create();
m_ubuf.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64));
m_ubuf->create();
m_srb.reset(m_rhi->newShaderResourceBindings());
m_srb->setBindings({
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, m_ubuf.get()),
});
m_srb->create();
m_pipeline.reset(m_rhi->newGraphicsPipeline());
m_pipeline->setShaderStages({
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/shaders/color.vert.qsb")) },
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/shaders/color.frag.qsb")) }
});
QRhiVertexInputLayout inputLayout;
inputLayout.setBindings({
{ 5 * sizeof(float) }
});
inputLayout.setAttributes({
{ 0, 0, QRhiVertexInputAttribute::Float2, 0 },
{ 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) }
});
m_pipeline->setVertexInputLayout(inputLayout);
m_pipeline->setShaderResourceBindings(m_srb.get());
m_pipeline->setRenderPassDescriptor(renderTarget()->renderPassDescriptor());
m_pipeline->create();
QRhiResourceUpdateBatch *resourceUpdates = m_rhi->nextResourceUpdateBatch();
resourceUpdates->uploadStaticBuffer(m_vbuf.get(), vertexData);
cb->resourceUpdate(resourceUpdates);
}
const QSize outputSize = renderTarget()->pixelSize();
m_viewProjection = m_rhi->clipSpaceCorrMatrix();
m_viewProjection.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 1000.0f);
m_viewProjection.translate(0, 0, -4);
}
void ExampleRhiItemRenderer::render(QRhiCommandBuffer *cb)
{
QRhiResourceUpdateBatch *resourceUpdates = m_rhi->nextResourceUpdateBatch();
QMatrix4x4 modelViewProjection = m_viewProjection;
modelViewProjection.rotate(m_angle, 0, 1, 0);
resourceUpdates->updateDynamicBuffer(m_ubuf.get(), 0, 64, modelViewProjection.constData());
const QColor clearColor = QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f);
cb->beginPass(renderTarget(), clearColor, { 1.0f, 0 }, resourceUpdates);
cb->setGraphicsPipeline(m_pipeline.get());
const QSize outputSize = renderTarget()->pixelSize();
cb->setViewport(QRhiViewport(0, 0, outputSize.width(), outputSize.height()));
cb->setShaderResources();
const QRhiCommandBuffer::VertexInput vbufBinding(m_vbuf.get(), 0);
cb->setVertexInput(0, 1, &vbufBinding);
cb->draw(3);
cb->endPass();
}值得注意的是,这个简单的类与QRhiWidget 介绍中展示的代码几乎完全相同。顶点着色器和片段着色器也完全一致。这些着色器以Vulkan风格的GLSL源代码形式提供,必须先由Qt着色器基础设施进行处理。 这可以通过手动运行qsb 命令行工具,或使用CMake中的qt_add_shaders()函数来实现。QQuickRhiItem会加载随应用程序一起提供的这些经过预处理的.qsb 文件。有关Qt着色器转换基础设施的更多信息,请参阅QtShader Tools 。
color.vert
#version 440
layout(location = 0) in vec4 position;
layout(location = 1) in vec3 color;
layout(location = 0) out vec3 v_color;
layout(std140, binding = 0) uniform buf {
mat4 mvp;
};
void main()
{
v_color = color;
gl_Position = mvp * position;
}color.frag
#version 440
layout(location = 0) in vec3 v_color;
layout(location = 0) out vec4 fragColor;
void main()
{
fragColor = vec4(v_color, 1.0);
}一旦通过 QML 进行暴露(请注意QML_NAMED_ELEMENT ),我们的自定义项就可以在任何场景中实例化。(前提是在 CMake 项目中导入了为qt_add_qml_module()指定的相应URI 文件)
ExampleRhiItem {
anchors.fill: parent
anchors.margins: 10
NumberAnimation on angle { from: 0; to: 360; duration: 5000; loops: Animation.Infinite }
}更复杂的示例请参见“场景图 - RHI 纹理项”。
另请参阅 QQuickRhiItemRenderer 、场景图 - RHI 纹理项、QRhi 以及《场景图与渲染》。
成员类型文档
enum class QQuickRhiItem::TextureFormat
指定QQuickRhiItem 渲染到的底层纹理的格式。
| 常量 | 值 | 描述 |
|---|---|---|
QQuickRhiItem::TextureFormat::RGBA8 | 0 | 参见QRhiTexture::RGBA8 。这是默认设置。 |
QQuickRhiItem::TextureFormat::RGBA16F | 1 | 参见QRhiTexture::RGBA16F 。 |
QQuickRhiItem::TextureFormat::RGBA32F | 2 | 参见QRhiTexture::RGBA32F 。 |
QQuickRhiItem::TextureFormat::RGB10A2 | 3 | 参见QRhiTexture::RGB10A2 。 |
另请参阅 QRhiTexture 。
属性文档
alphaBlending : bool
控制在绘制由QQuickRhiItem 及其渲染器生成的内容作为纹理的四边形时,是否始终启用混合效果。
默认值为false 。这是出于性能考虑:如果不涉及半透明效果,由于QQuickRhiItemRenderer 会清屏为不透明颜色,且绝不会渲染alpha值小于1的片段,因此启用混合功能毫无意义。
如果QQuickRhiItemRenderer 的子类在渲染时涉及半透明效果,请将此属性设置为 true。
注意:在 某些情况下, 无论此属性的值如何,混合渲染仍会发生。例如,如果该项的opacity (更准确地说,是从父级链继承的综合不透明度)小于1,即使此属性设置为false,混合渲染也会自动启用。
注意: Qt Quick 场景图 依赖并期望使用 预乘 alpha值 。例如,如果打算将渲染器中的背景清除为 alpha 值 0.5,则请确保将红色、绿色和蓝色的清除颜色值也乘以 0.5。否则,混合结果将不正确。
访问函数:
| bool | alphaBlending() const |
| void | setAlphaBlending(bool enable) |
通知器信号:
| void | alphaBlendingChanged() |
colorBufferFormat : TextureFormat
该属性控制用作颜色缓冲区的纹理的纹理格式。默认值为TextureFormat::RGBA8 。QQuickRhiItem 支持渲染到QRhiTexture 所支持格式中的一部分。仅应指定通过QRhi::isTextureFormatSupported()报告为受支持的格式,否则渲染将无法正常工作。
注意: 当项及其渲染器已初始化并完成渲染后,若此时设置 新格式,且由于纹理格式不同导致关联的QRhiRenderPassDescriptor 变得不兼容,则渲染器创建的所有QRhiGraphicsPipeline 对象都可能无法使用。 这与动态更改sampleCount 类似,意味着initialize()或render()的实现必须负责释放现有管道并创建新的管道。
访问函数:
| QQuickRhiItem::TextureFormat | colorBufferFormat() const |
| void | setColorBufferFormat(QQuickRhiItem::TextureFormat format) |
通知器信号:
| void | colorBufferFormatChanged() |
[read-only] effectiveColorBufferSize : QSize
该属性返回底层颜色缓冲区(QRhiTexture 或QRhiRenderBuffer )的大小(以像素为单位)。该属性供在 GUI(主)线程、QML 绑定或 JavaScript 中使用。
注意: 在场景图渲染线程上运行的QQuickRhiItemRenderer 实现不应使用此属性。此类实现应通过render target 查询尺寸。
注意: 从主线程的角度来看,该值的 可用性是异步的,因为当渲染线程进行渲染时,该值会发生变化。这意味着该属性主要在 QML 绑定中才有用。应用程序代码不得假设在QQuickRhiItem 对象构造时该值已经是最新的。
这是一个只读属性。
访问函数:
| QSize | effectiveColorBufferSize() const |
Notifier 信号:
| void | effectiveColorBufferSizeChanged() |
fixedColorBufferHeight : int
该物品关联纹理的固定高度(以像素为单位)。 当需要设置一个不依赖于物品大小的固定纹理尺寸时,此属性才相关。该尺寸不会影响物品的几何属性(即其在场景中的大小和位置),这意味着纹理内容会在物品的区域内呈现拉伸(放大)或缩小的效果。
默认值为0 。值为 0 表示纹理大小随项目大小变化。(texture size =item size *device pixel ratio )。
有关设置固定宽度和高度的使用场景的更多信息,请参阅fixedColorBufferWidth 。
访问函数:
| int | fixedColorBufferHeight() const |
| void | setFixedColorBufferHeight(int height) |
通知器信号:
| void | fixedColorBufferHeightChanged() |
fixedColorBufferWidth : int
该项关联的纹理或渲染缓冲区的固定宽度(以像素为单位)。 当需要固定颜色缓冲区大小且该大小不依赖于项的尺寸时,此参数才相关。该大小不会影响项的几何属性(即其在场景中的尺寸和位置),这意味着纹理内容将在项的区域内呈现拉伸(放大)或缩小效果。
例如,将大小设置为该项(像素)大小的两倍,实际上会执行 2 倍超采样(以两倍的分辨率进行渲染,然后在为场景中对应该项的四边形贴图时隐式缩小)。 另一方面,将大小设置为对象像素大小的一半,实际上相当于以一半的分辨率进行渲染,然后将结果放大。
默认值为0 。值为 0 表示纹理大小遵循对象的大小。(texture size =item size *device pixel ratio )。
注意:设备像素比 (系统合成器的缩放因子)会对性能产生重大影响,因为缩放因子为 2 (200%)意味着以两倍的分辨率进行渲染,即开发者与 UI 设计师所感知项目大小的两倍,随后再对内容进行实质性的缩放——这与在设备像素比为 1 的系统上将该属性设置为项目像素大小的两倍时的情况类似。 因此,预计该属性很少会用于大于项目像素大小的尺寸,因为当系统本身使用大于 1 的设备像素比时,许多现代桌面系统既没有这种需求,也没有相应的性能预算。 相反,该属性的主要用例是设置较小的尺寸,以便以合理的小分辨率进行渲染,而不是盲目地遵循项目(以及可能的窗口)几何形状,无论其尺寸有多大。
访问函数:
| int | fixedColorBufferWidth() const |
| void | setFixedColorBufferWidth(int width) |
通知信号:
| void | fixedColorBufferWidthChanged() |
mirrorVertically : bool
该属性控制在绘制带纹理的四边形时,纹理 UV 是否被翻转。它对离屏颜色缓冲区的内容以及由 `QQuickRhiItemRenderer` 实现的渲染没有影响。
默认值为false 。
访问函数:
| bool | isMirrorVerticallyEnabled() const |
| void | setMirrorVertically(bool enable) |
通知器信号:
| void | mirrorVerticallyChanged() |
sampleCount : int
此属性控制多采样抗锯齿(MSAA)的采样次数。默认值为1 ,这意味着MSAA已被禁用。
有效值为 1、4、8,有时也包括 16 和 32。可通过QRhi::supportedSampleCounts() 在运行时查询支持的采样数,但通常应用程序应请求 1(无 MSAA)、4x(标准 MSAA)或 8x(高 MSAA)。
注意:设置 新值意味着渲染器创建的所有QRhiGraphicsPipeline 对象此后必须使用相同的采样数。使用不同采样数创建的现有QRhiGraphicsPipeline 对象不得再继续使用。 当该值发生变化时,所有颜色和深度-模板缓冲区都会被自动销毁并重新创建,且会再次调用initialize()。但是,当isAutoRenderTargetEnabled()被false 时,深度-模板缓冲区或额外的颜色缓冲区将由应用程序自行管理。
将采样数从默认值 1 更改为更高数值,意味着colorTexture() 将变为nullptr ,而msaaColorBuffer() 开始返回一个有效的对象。切换回 1(或 0)则意味着相反的情况:在下一次调用 initialize() 时,msaaColorBuffer() 将返回nullptr ,而 colorTexture() 将再次返回有效结果。 此外,当采样数大于 1 时(即启用了 MSAA),resolveTexture() 将返回一个有效的(非多采样)QRhiTexture 。
访问函数:
| int | sampleCount() const |
| void | setSampleCount(int samples) |
通知器信号:
| void | sampleCountChanged() |
另请参阅 QQuickRhiItemRenderer::msaaColorBuffer() 和QQuickRhiItemRenderer::resolveTexture()。
成员函数文档
[explicit] QQuickRhiItem::QQuickRhiItem(QQuickItem *parent = nullptr)
使用给定的parent 创建一个新的QQuickRhiItem。
[override virtual noexcept] QQuickRhiItem::~QQuickRhiItem()
析构函数。
[pure virtual protected] QQuickRhiItemRenderer *QQuickRhiItem::createRenderer()
重写此函数,以创建并返回QQuickRhiItemRenderer 子类的全新实例。
该函数将在 GUI 线程被阻塞期间,在渲染线程上被调用。
[override virtual protected] bool QQuickRhiItem::event(QEvent *e)
重写了:QQuickItem::event(QEvent *ev)。
[override virtual protected] void QQuickRhiItem::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
重写了:QQuickItem::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)。
[protected] bool QQuickRhiItem::isAutoRenderTargetEnabled() const
返回当前的自动深度-模板缓冲区和渲染目标管理设置。
默认情况下,此值为true 。
另请参阅 setAutoRenderTarget()。
[override virtual] bool QQuickRhiItem::isTextureProvider() const
重新实现了:QQuickItem::isTextureProvider() const。
[override virtual protected] void QQuickRhiItem::releaseResources()
重写了:QQuickItem::releaseResources()。
[protected] void QQuickRhiItem::setAutoRenderTarget(bool enabled)
控制该项是否自动创建并维护深度-模板缓冲区(QRhiRenderBuffer )和模板缓冲区(QRhiTextureRenderTarget )。默认值为true 。请尽早调用此函数(例如在派生类的构造函数中),并将enabled 设置为false 以禁用此功能。
在自动模式下,深度-模板缓冲区的大小和采样数遵循颜色缓冲区纹理的设置。在非自动模式下,renderTarget() 和 depthStencilBuffer() 始终返回nullptr ,此时需要由应用程序对 initialize() 的实现来负责设置和管理这些对象。
[override virtual] QSGTextureProvider *QQuickRhiItem::textureProvider() const
重新实现了:QQuickItem::textureProvider() const。
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.