QRhiWidget Class

QRhiWidget 类是通过加速图形 API(如 Vulkan、Metal 或 Direct 3D)渲染 3D 图形的部件。更多

Header: #include <QRhiWidget>
CMake: find_package(Qt6 REQUIRED COMPONENTS Widgets)
target_link_libraries(mytarget PRIVATE Qt6::Widgets)
qmake: QT += widgets
Qt 6.7
继承: QWidget

公共类型

enum class Api { Null, OpenGL, Metal, Vulkan, Direct3D11, Direct3D12 }
enum class TextureFormat { RGBA8, RGBA16F, RGBA32F, RGB10A2 }

属性

公共功能

QRhiWidget(QWidget *parent = nullptr, Qt::WindowFlags f = {})
virtual ~QRhiWidget() override
QRhiWidget::Api api() const
QRhiWidget::TextureFormat colorBufferFormat() const
QSize fixedColorBufferSize() const
QImage grabFramebuffer() const
bool isDebugLayerEnabled() const
bool isMirrorVerticallyEnabled() const
int sampleCount() const
void setApi(QRhiWidget::Api api)
void setColorBufferFormat(QRhiWidget::TextureFormat format)
void setDebugLayerEnabled(bool enable)
void setFixedColorBufferSize(QSize pixelSize)
void setFixedColorBufferSize(int w, int h)
void setMirrorVertically(bool enabled)
void setSampleCount(int samples)

信号

void colorBufferFormatChanged(QRhiWidget::TextureFormat format)
void fixedColorBufferSizeChanged(const QSize &pixelSize)
void frameSubmitted()
void mirrorVerticallyChanged(bool enabled)
void renderFailed()
void sampleCountChanged(int samples)

受保护函数

QRhiTexture *colorTexture() const
QRhiRenderBuffer *depthStencilBuffer() const
virtual void initialize(QRhiCommandBuffer *cb)
QRhiRenderBuffer *msaaColorBuffer() const
virtual void releaseResources()
virtual void render(QRhiCommandBuffer *cb)
QRhiRenderTarget *renderTarget() const
QRhiTexture *resolveTexture() const
QRhi *rhi() const
void setAutoRenderTarget(bool enabled)

重新实现的受保护函数

virtual bool event(QEvent *e) override
virtual void paintEvent(QPaintEvent *e) override
virtual void resizeEvent(QResizeEvent *e) override

详细说明

QRhiWidget 为在基于QWidget 的应用程序中显示通过QRhi API 渲染的 3D 内容提供了功能。在许多方面,它相当于可移植的QOpenGLWidget ,不依赖于单一的 3D 图形 API,而是可以使用QRhi 支持的所有 API(如 Direct 3D 11/12、Vulkan、Metal 和 OpenGL)。

QRhiWidget 预计将被子类化。要渲染 QRhiWidget 隐式创建和管理的 2D 纹理,子类应重新实现虚拟函数initialize() 和render()。

默认情况下,纹理的大小将与部件的大小相适应。如果希望使用固定尺寸,可调用setFixedColorBufferSize() 设置固定尺寸(以像素为单位)。

除了用作颜色缓冲区的纹理外,还隐式地维护了深度/模板缓冲区和将它们绑定在一起的渲染目标。

小部件顶层窗口的QRhi 默认配置为使用特定平台的后端和图形 API:在 macOS 和 iOS 上使用 Metal,在 Windows 上使用 Direct 3D 11,否则使用 OpenGL。调用setApi() 可覆盖这一点。

注意: 单个 widget 窗口只能使用一个QRhi 后端,因此只能使用一个 3D 图形 API。如果窗口 widget 层次结构中的两个 QRhiWidget 或QQuickWidget widget 请求不同的 API,则其中只有一个能正常运行。

注意: 虽然 QRhiWidget 是公共 Qt API,但 Qt GUI 模块中的QRhi 系列类(包括QRhiQShaderQShaderDescription )提供了有限的兼容性保证。这些类没有源代码或二进制兼容性保证,这意味着 API 只能保证与应用程序开发时所使用的 Qt 版本兼容。不过,源代码不兼容的改动将保持在最低水平,而且只会在小版本(6.7、6.8 等)中进行。qrhiwidget.h 并不直接包含任何与QRhi 相关的头文件。要在实现 QRhiWidget 子类时使用这些类,请链接到Qt::GuiPrivate (如果使用 CMake),并包含带有rhi 前缀的相应头文件,例如#include <rhi/qrhi.h>

下面是一个简单的 QRhiWidget 子类渲染三角形的例子:

class ExampleRhiWidget : public QRhiWidget
{
public:
    ExampleRhiWidget(QWidget *parent = nullptr) : QRhiWidget(parent) { }
    void initialize(QRhiCommandBuffer *cb) 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_rotation = 0.0f;
};

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,
};

QShader getShader(const QString &name)
{
    QFile f(name);
    return f.open(QIODevice::ReadOnly) ? QShader::fromSerialized(f.readAll()) : QShader();
}

void ExampleRhiWidget::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(":/shader_assets/color.vert.qsb")) },
            { QRhiShaderStage::Fragment, getShader(QLatin1String(":/shader_assets/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 = colorTexture()->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 ExampleRhiWidget::render(QRhiCommandBuffer *cb)
{
    QRhiResourceUpdateBatch *resourceUpdates = m_rhi->nextResourceUpdateBatch();
    m_rotation += 1.0f;
    QMatrix4x4 modelViewProjection = m_viewProjection;
    modelViewProjection.rotate(m_rotation, 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 = colorTexture()->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();

    update();
}

这是一个持续请求更新的 widget,由呈现率(vsync,取决于屏幕刷新率)节流。如果不希望连续渲染,则应删除render() 中的update() 调用,而只在需要更新渲染内容时才发出该调用。例如,如果立方体的旋转应与QSlider 的值挂钩,那么将滑块的值变化信号连接到转发新值并调用update() 的槽或 lambda 即可。

顶点和片段着色器以 Vulkan 风格的 GLSL 提供,必须首先由 Qt 着色器基础架构处理。这可以通过手动运行qsb 命令行工具或使用 CMake 中的qt_add_shaders()函数来实现。QRhiWidget 实现会加载这些预处理过的.qsb 文件,这些文件随应用程序一起提供。有关Qt着色器翻译基础结构的更多信息,请参阅 Qt Shader 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);
}

结果是显示以下内容的 widget:

如需完整、简约的入门示例,请查看简单 RHI Widget 示例

如需了解更多功能和更多概念演示,请参阅立方体 RHI Widget 示例

QRhiWidget 总是渲染到背景纹理,而不是直接渲染到窗口(窗口系统为本地窗口提供的表面或图层)。这样就可以将内容与基于 Widget 的用户界面的其他部分适当合成,并提供简单紧凑的应用程序接口,使用户可以轻松上手。所有这些都以额外的资源和潜在的性能影响为代价。这在实践中通常是完全可以接受的,但高级用户应牢记不同方法的利弊。有关这两种方法的详细信息,请参阅RHI 窗口示例,并与简单 RHI Widget 示例进行比较。

将一个 QRhiWidget 转到属于不同窗口(顶层 widget)的 widget 层次结构中,或使 QRhiWidget 本身成为顶层(通过将父级设置为nullptr ),需要更改相关的QRhi (并有可能破坏旧的 ),而 QRhiWidget 则继续保持活力。为了支持这一点,我们希望健壮的 QRhiWidget 实现也能重新实现releaseResources() 虚拟函数,并像在析构函数中那样丢弃其QRhi 资源。Cube RHI Widget 示例实际演示了这一点。

虽然 QRhiWidget 并非主要用例,但它也允许整合直接使用 3D 图形 API(如 Vulkan、Metal、Direct 3D 或 OpenGL)的渲染代码。关于在QRhi 渲染传递中记录本地命令的详情,请参见QRhiCommandBuffer::beginExternal() ;关于封装现有本地纹理并在后续渲染传递中使用QRhi 的方法,请参见QRhiTexture::createFrom() 。不过请注意,底层图形 API(其设备或上下文功能、层、扩展等)的可配置性将会受到限制,因为 QRhiWidget 的主要目标是为基于QRhi 的渲染代码提供一个合适的环境,而不是启用任意的、潜在复杂的外来渲染引擎。

另请参阅 QRhi,QShader,QOpenGLWidget,Simple RHI Widget ExampleCube RHI Widget Example

成员类型文档

enum class QRhiWidget::Api

指定要使用的 3D API 和QRhi 后端

常数
QRhiWidget::Api::Null0
QRhiWidget::Api::OpenGL1
QRhiWidget::Api::Metal2
QRhiWidget::Api::Vulkan3
QRhiWidget::Api::Direct3D114
QRhiWidget::Api::Direct3D125

另请参阅 QRhi

enum class QRhiWidget::TextureFormat

指定QRhiWidget 渲染纹理的格式。

常量说明
QRhiWidget::TextureFormat::RGBA80请参见QRhiTexture::RGBA8
QRhiWidget::TextureFormat::RGBA16F1请参见QRhiTexture::RGBA16F
QRhiWidget::TextureFormat::RGBA32F2请参见QRhiTexture::RGBA32F
QRhiWidget::TextureFormat::RGB10A23参见QRhiTexture::RGB10A2

另请参见 QRhiTexture

财产文件

autoRenderTarget : const bool

自动深度模版缓冲区和渲染目标维护的当前设置。

默认值为true

colorBufferFormat : TextureFormat

该属性控制用作色彩缓冲区的纹理(或 renderbuffer)的纹理格式。默认值为TextureFormat::RGBA8QRhiWidget 支持以QRhiTexture 所支持格式的子集进行渲染。只应指定QRhi::isTextureFormatSupported() 报告支持的格式,否则将无法进行渲染。

注意: 在部件已初始化并已渲染的情况下设置新格式,意味着渲染器创建的所有QRhiGraphicsPipeline 对象都可能无法使用,如果相关的QRhiRenderPassDescriptor 现在因纹理格式不同而不兼容的话。与动态更改sampleCount 相似,这意味着initialize() 或render() 的实现必须释放现有管道并创建新管道。

访问功能:

QRhiWidget::TextureFormat colorBufferFormat() const
void setColorBufferFormat(QRhiWidget::TextureFormat format)

通知信号

void colorBufferFormatChanged(QRhiWidget::TextureFormat format)

fixedColorBufferSize : QSize

QRhiWidget 相关纹理的固定尺寸(像素)。当需要一个固定的纹理尺寸而不依赖于窗口小部件的尺寸时,就需要用到它。该尺寸对窗口小部件的几何形状(其尺寸和在顶层窗口中的位置)没有影响,这意味着纹理的内容会被拉伸(放大)或缩小到窗口小部件的区域中。

例如,如果设置的大小正好是部件(像素)大小的两倍,就会有效执行 2 倍的超级采样(以两倍的分辨率进行渲染,然后在对窗口中与部件相对应的四边形进行纹理绘制时隐含地缩小比例)。

默认情况下,QSize 。空值或空QSize 意味着纹理的大小与QRhiWidget 的大小一致。(texture size =widget size *device pixel ratio)。

访问功能:

QSize fixedColorBufferSize() const
void setFixedColorBufferSize(QSize pixelSize)
void setFixedColorBufferSize(int w, int h)

通知信号:

void fixedColorBufferSizeChanged(const QSize &pixelSize)

mirrorVertically : bool

启用后,在合成QRhiWidget 的背景纹理和顶层窗口中 widget 的其他内容时,图像会绕 X 轴翻转。

默认值为false

访问功能:

bool isMirrorVerticallyEnabled() const
void setMirrorVertically(bool enabled)

通知信号:

void mirrorVerticallyChanged(bool enabled)

sampleCount : int

该属性控制多采样抗锯齿的采样计数。默认值为1 ,表示禁用 MSAA。

有效值为 1、4、8,有时为 16 和 32。QRhi::supportedSampleCounts() 可用于在运行时查询支持的采样计数,但通常情况下,应用程序应请求 1(无 MSAA)、4x(正常 MSAA)或 8x(高 MSAA)。

注意: 设置新值意味着渲染器创建的所有QRhiGraphicsPipeline 对象从此都必须使用相同的采样计数。使用不同样本数创建的现有QRhiGraphicsPipeline 对象不得再使用。当值发生变化时,所有颜色和深度样板缓冲区都会自动销毁和重新创建,并再次调用initialize() 。不过,当autoRenderTargetfalse 时,应用程序将自行管理深度钢网缓冲区或其他颜色缓冲区。

将采样计数从默认的 1 改为更高值意味着colorTexture() 变为nullptrmsaaColorBuffer() 开始返回有效对象。返回 1(或 0)则意味着相反的结果:在下一次调用initialize() 时,msaaColorBuffer() 将返回nullptr ,而colorTexture() 则再次成为有效对象。此外,只要采样计数大于 1(即使用 MSAA),resolveTexture() 就会返回一个有效的(非多采样)QRhiTexture

访问功能:

int sampleCount() const
void setSampleCount(int samples)

通知信号:

void sampleCountChanged(int samples)

另请参阅 msaaColorBuffer() 和resolveTexture()。

成员函数文档

[explicit] QRhiWidget::QRhiWidget(QWidget *parent = nullptr, Qt::WindowFlags f = {})

构造一个 widget,它是parent 的子 widget,widget 标志设置为f

[override virtual noexcept] QRhiWidget::~QRhiWidget()

毁灭者

QRhiWidget::Api QRhiWidget::api() const

返回当前设置的图形 API(QRhi 后台)。

另请参阅 setApi().

[protected] QRhiTexture *QRhiWidget::colorTexture() const

返回作为 widget 颜色缓冲器的纹理。

只能在initialize() 和render() 中调用。

与深度模板缓冲区和QRhiRenderTarget 不同,该纹理始终可用,由QRhiWidget 管理,与autoRenderTarget 的值无关。

注: sampleCount 大于 1 且启用多采样抗锯齿时,返回值为nullptr 。请调用msaaColorBuffer() 查询QRhiRenderBuffer

注: 也可以通过renderTarget() 返回的QRhiRenderTarget 来查询后备纹理大小和采样计数。这比从QRhiTextureQRhiRenderBuffer 查询更方便、更简洁,因为无论是否使用多重采样,它都能正常工作。

另请参见 msaaColorBuffer()、depthStencilBuffer()、renderTarget() 和resolveTexture()。

[protected] QRhiRenderBuffer *QRhiWidget::depthStencilBuffer() const

返回部件渲染所使用的深度模板缓冲区。

只能在initialize() 和render() 中调用。

只有当autoRenderTargettrue 时才可用。否则返回值为nullptr ,并由initialize() 的重新实现来创建和管理深度钢网缓冲区和QRhiTextureRenderTarget

另请参见 colorTexture() 和renderTarget()。

[override virtual protected] bool QRhiWidget::event(QEvent *e)

重实现:QWidget::event(QEvent *event).

[signal] void QRhiWidget::frameSubmitted()

该信号在窗口部件的顶层窗口完成组成并显示submitted a frame 后发出。

QImage QRhiWidget::grabFramebuffer() const

渲染一个新帧,读取纹理内容,并以QImage 的形式返回。

如果出现错误,则会返回一个空的QImage

返回的QImage 格式为QImage::Format_RGBA8888QImage::Format_RGBA16FPx4QImage::Format_RGBA32FPx4QImage::Format_BGR30 ,具体取决于colorBufferFormat() 。

QRhiWidget 由于不知道渲染器的混合和合成方法,因此无法知道输出的 RGB 颜色值中是否预乘了 alpha。因此,即使在合适的情况下, 格式也不会用于返回的 。调用者可以根据自己的需要重新解释生成的数据。_Premultiplied QImage QImage

注: QRhiWidget 未添加到属于屏幕顶层窗口的 widget 层次结构中时,也可调用此函数。这样就可以从屏幕外的 3D 渲染生成图像。

为了与QOpenGLWidgetQQuickWidget 保持一致,该函数被命名为 grabFramebuffer()。这并不是从QRhiWidget 的内容中获取 CPU 端图像数据的唯一方法:在QRhiWidget 或其祖先上调用QWidget::grab() 也同样有效(返回QPixmap )。除了直接使用QImage 外,grabFramebuffer() 的另一个优点是性能略高,因为它无需使用QWidget 基础架构的其他部分,而是可以立即触发渲染新帧,然后进行回读。

另请参见 setColorBufferFormat().

[virtual protected] void QRhiWidget::initialize(QRhiCommandBuffer *cb)

在首次初始化 widget 时,或相关纹理的大小、格式或采样计数发生变化时,或QRhi 和纹理因任何原因发生变化时调用。该函数将维护render() 中渲染代码使用的图形资源(如果尚未创建,则创建;如果大小发生变化,则调整并重建)。

要查询QRhiQRhiTexture 和其他相关对象,请调用rhi()、colorTexture()、depthStencilBuffer() 和renderTarget() 。

当 widget 的大小发生变化时,QRhi 对象、颜色缓冲区纹理和深度模版缓冲区对象都是与之前相同的实例(因此获取器返回相同的指针),但颜色和深度/模版缓冲区很可能已经重建,这意味着size 和底层本地纹理资源可能与上次调用时不同。

重新实现时还应做好准备,QRhi 对象和颜色缓冲区纹理可能会在调用该函数之间发生变化。在一种特殊情况下,对象会有所不同,那就是在对一个尚未显示的部件执行grabFramebuffer() 时,然后在一个顶层部件中使该部件在屏幕上可见。在这种情况下,将使用专用的QRhi 进行抓取,然后在随后的初始化() 和render() 调用中用顶层窗口的相关QRhi 代替。另一种更常见的情况是,当窗口部件被重新转属到一个新的顶层窗口时。在这种情况下,在随后调用该函数时,QRhiQRhiWidget 管理的所有相关资源都将是与之前不同的实例。重要的是,子类之前创建的所有QRhi 资源都将被销毁,因为它们属于之前的QRhi ,而小工具不应再使用这些资源。

autoRenderTargettrue 时(这是默认值),深度钢网QRhiRenderBuffer 和与colorTexture() (或msaaColorBuffer() )相关的QRhiTextureRenderTarget 以及深度钢网缓冲区会自动创建和管理。初始化() 和render() 的重新实现可以通过depthStencilBuffer() 和renderTarget() 查询这些对象。当autoRenderTarget 设置为false 时,这些对象将不再自动创建和管理。相反,将由 initialize() 实现来创建缓冲区并设置合适的呈现目标。在手动管理渲染目标的附加颜色或深度模板附件时,它们的大小和样本数必须始终遵循colorTexture() /msaaColorBuffer() 的大小和样本数,否则可能会出现渲染或 3D API 验证错误。

子类创建的图形资源将在子类的析构函数中释放。

cb 是部件当前帧的 。调用该函数时正在记录帧,但没有活动的渲染传递。提供命令缓冲区主要是为了在不延迟 () 的情况下排队 。QRhiCommandBuffer render resource updates

另请参阅 render()。

bool QRhiWidget::isDebugLayerEnabled() const

如果将请求调试层或验证层(如果适用于使用中的图形 API),则返回 true。

另请参见 setDebugLayerEnabled()。

[protected] QRhiRenderBuffer *QRhiWidget::msaaColorBuffer() const

返回作为 widget 多采样颜色缓冲区的 renderbuffer。

只能在initialize() 和render() 中调用。

sampleCount 大于 1 且启用多采样反锯齿时,返回的QRhiRenderBuffer 将具有匹配的采样计数,并用作颜色缓冲区。用于渲染到该缓冲区的图形管道必须使用相同的样本数创建,深度模板缓冲区的样本数也必须匹配。多采样内容有望解析为从resolveTexture() 返回的纹理。当autoRenderTargettrue 时,renderTarget() 会自动设置为这样做,方法是将 msaaColorBuffer() 设置为颜色附件 0 的renderbuffer ,并将resolveTexture() 设置为其resolveTexture

当不使用 MSAA 时,返回值为nullptr 。这时请使用colorTexture() 代替。

根据底层 3D 图形 API 的不同,多采样纹理和采样数大于 1 的彩色呈现缓冲区之间可能没有实际区别(QRhi 可能只是将两者映射到相同的本地资源类型)。不过,一些较早的应用程序接口可能会区分纹理和呈现缓冲区。在 OpenGL ES 3.0 中,多采样呈现缓冲区可用,但多采样纹理不可用,为了支持 OpenGL ES 3.0,QRhiWidget 在执行 MSAA 时总是使用多采样QRhiRenderBuffer 作为颜色附件(而不是多采样QRhiTexture )。

注: 也可以通过renderTarget() 返回的QRhiRenderTarget 来查询背景纹理大小和样本数。这比从QRhiTextureQRhiRenderBuffer 查询更方便、更简洁,因为无论是否使用多重采样,它都能正常工作。

另请参见 colorTexture()、depthStencilBuffer()、renderTarget() 和resolveTexture()。

[override virtual protected] void QRhiWidget::paintEvent(QPaintEvent *e)

重实现:QWidget::paintEvent(QPaintEvent *event).

处理绘画事件。

调用QWidget::update() 将导致发送油漆事件e ,从而调用此函数。事件的发送是异步的,将在从update() 返回后的某个时刻发生。然后,经过一些准备工作后,该函数将调用虚拟render() 来更新QRhiWidget 的相关纹理内容。然后,窗口小部件的顶层窗口将把纹理与窗口的其他内容合成在一起。

[virtual protected] void QRhiWidget::releaseResources()

当需要提前释放图形资源时调用。

通常情况下,如果QRhiWidget 被添加到顶层窗口部件的子层级结构中,并且在顶层窗口部件和顶层窗口部件的剩余生命周期中一直保留在该层级结构中,就不会出现这种情况。因此,在很多情况下,例如应用程序只有一个顶层部件(本地窗口),就没有必要重新实现该功能。但是,当涉及到部件(或其祖先)的再父系化时,在健壮、编写良好的QRhiWidget 子类中就有必要重新实现该函数。

调用该函数时,实现过程应销毁所有QRhi 资源(QRhiBufferQRhiTexture 等对象),这与在析构函数中的做法类似。由于initialize() 最终会被调用,因此还需要清空、使用智能指针或设置resources-invalid 标志。但请注意,将释放资源的操作推迟到随后的initialize() 是错误的。如果调用了该函数,必须在返回之前放弃资源。还要注意的是,执行该函数并不能取代类的析构函数(或智能指针):图形资源仍必须在这两个函数中释放。

请参阅Cube RHI Widget 示例以了解实际操作。在该示例中,在作为子窗口部件(由于有父窗口部件)和作为顶层窗口部件(由于没有父窗口部件)之间切换QRhiWidget 的按钮会触发调用该函数,因为相关的顶层窗口部件、本地窗口和QRhi 都会在QRhiWidget 的生命周期内发生变化,先前使用的QRhi 会被销毁,这意味着仍在运行的QRhiWidget 所管理的相关资源会被提前释放。

调用该函数的另一种情况是grabFramebuffer() 与未添加到可见窗口的QRhiWidget 一起使用,即在屏幕外进行渲染。如果以后该QRhiWidget 变为可见,或添加到可见部件层次结构中,相关的QRhi 将从用于离屏渲染的临时部件变为窗口的专用部件,从而也会触发该函数。

另请参见 initialize().

[virtual protected] void QRhiWidget::render(QRhiCommandBuffer *cb)

当 widget 内容(即纹理内容)需要更新时调用。

在调用此函数之前,总会至少调用一次initialize() 。

要请求更新,请调用QWidget::update() 。在 render() 中调用update() 会导致在 vsync 的控制下持续更新。

cb 是部件当前帧的 。调用该函数时正在记录一帧,但没有活动的渲染传递。QRhiCommandBuffer

另请参见 initialize()。

[signal] void QRhiWidget::renderFailed()

当部件本应渲染到其衬底纹理时(可能是由于widget update ,也可能是由于调用了grabFramebuffer()) ,但可能由于与图形配置相关的问题,没有QRhi 供部件使用时,就会发出该信号。

出现问题时,该信号可能会多次发出。不要认为它只会发出一次。如果只想通知错误处理代码一次,请连接Qt::SingleShotConnection

[protected] QRhiRenderTarget *QRhiWidget::renderTarget() const

返回在重新实现render() 时必须与QRhiCommandBuffer::beginPass() 一起使用的呈现目标对象。

只能从initialize() 和render() 调用。

仅当autoRenderTargettrue 时可用。否则,返回值为nullptr ,并由initialize() 的重新实现来创建和管理深度模板缓冲区和QRhiTextureRenderTarget

创建graphics pipelines 时,需要一个QRhiRenderPassDescriptor 。可以通过调用renderPassDescriptor() 从返回的QRhiTextureRenderTarget 中查询。

另请参见 colorTexture() 和depthStencilBuffer()。

[override virtual protected] void QRhiWidget::resizeEvent(QResizeEvent *e)

重实现:QWidget::resizeEvent(QResizeEvent *event)。

处理通过e 事件参数传递的调整大小事件。调用虚拟函数initialize().

注意: 避免在派生类中覆盖此函数。如果不可行,请确保也调用QRhiWidget 的实现。否则,底层纹理对象和相关资源将无法正确调整大小,从而导致不正确的渲染。

[protected] QRhiTexture *QRhiWidget::resolveTexture() const

返回多采样内容解析到的非多采样纹理。

未启用多采样抗锯齿时,结果为nullptr

只能在initialize() 和render() 中调用。

启用 MSAA 后,该纹理将与屏幕上其他QWidget 内容合成。但是,QRhiWidget 的渲染必须以msaaColorBuffer() 返回的(多采样)QRhiRenderBuffer 为目标。如果autoRenderTargettrue ,则由renderTarget() 返回的QRhiRenderTarget 来处理。否则,就需要子类代码来正确配置具有颜色缓冲区和解析纹理的呈现目标对象。

另请参见 colorTexture()。

[protected] QRhi *QRhiWidget::rhi() const

返回当前QRhi 对象。

只能在initialize() 和render() 中调用。

void QRhiWidget::setApi(QRhiWidget::Api api)

设置要使用的图形 API 和QRhi 后端为api

警告: 必须在部件添加到部件层次结构并显示在屏幕上之前尽早调用该函数。例如,应调用子类构造函数的函数。如果调用得太晚,该函数将不起作用。

默认值取决于平台:macOS 和 iOS 上为 Metal,Windows 上为 Direct 3D 11,其他平台为 OpenGL。

api 只能为部件及其顶层窗口设置一次,一旦设置完成并生效,窗口就只能使用该 API 和QRhi 后端进行渲染。如果试图设置其他值,或使用不同的api 添加另一个QRhiWidget ,将无法实现预期功能。

另请参阅 setColorBufferFormat()、setDebugLayerEnabled() 和api()。

[protected] void QRhiWidget::setAutoRenderTarget(bool enabled)

控制 widget 是否自动创建和维护深度模版QRhiRenderBufferQRhiTextureRenderTarget 。默认值为true

在自动模式下,深度模版缓冲区的大小和采样计数遵循颜色缓冲区纹理的设置。在非自动模式下,renderTarget() 和depthStencilBuffer() 总是返回nullptr ,然后由应用程序实现initialize() 来设置和管理这些对象。

调用该函数时,应尽早将enabled 设置为false ,例如在派生类的构造函数中,以禁用自动模式。

void QRhiWidget::setDebugLayerEnabled(bool enable)

enable 为 true 时,请求底层图形 API 的调试或验证层。

警告: 必须在部件添加到部件层次结构并显示在屏幕上之前尽早调用该函数。例如,应调用子类构造函数的函数。如果调用得太晚,该函数将不起作用。

适用于 Vulkan 和 Direct 3D。

默认情况下禁用。

另请参见 setApi() 和isDebugLayerEnabled()。

© 2025 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.