QRhiWidget 类
QRhiWidget 类是一个用于通过加速图形 API(如 Vulkan、Metal 或 Direct 3D)渲染 3D 图形的小部件。 更多...
头文件 | #include <QRhiWidget> |
CMake | find_package(Qt6 REQUIRED COMPONENTS Widgets) target_link_libraries(mytarget PRIVATE Qt6::Widgets) |
qmake | QT += widgets |
自从 | Qt 6.7 |
继承自 | QWidget |
状态 | 初步 |
此类正在开发中,可能会更改。
公开类型
枚举类 | Api { Null, OpenGL, Metal, Vulkan, Direct3D11, Direct3D12 } |
枚举类 | TextureFormat { RGBA8, RGBA16F, RGBA32F, RGB10A2 } |
属性
|
|
公开函数
QRhiWidget(QWidget *parent = nullptr, Qt::WindowFlags f = {}) | |
虚拟 | ~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 在 Qt 6.7 中处于技术预览阶段。API 正在开发中,可能发生变化。
QRhiWidget 提供了在 QWidget 基于的应用程序中显示通过 QRhi API 渲染的 3D 内容的功能。在许多方面,它与不绑定到单个 3D 图形 API 的便携式 QOpenGLWidget 相当,但它可以与 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() 以覆盖此设置。
注意:单个小部件窗口只能使用一个 QRhi 后端,因此只有一个 3D 图形 API。如果窗口的小部件层次结构中的两个 QRhiWidget 或 QQuickWidget 小部件请求不同的 API,则只有一个可以正确工作。
注意:虽然 QRhiWidget 是一个公开的 Qt API,但 Qt Gui 模块中的 QRhi 类族(包括 QRhi、QShader 和 QShaderDescription)提供有限的兼容性保证。这些类没有源代码或二进制兼容性保证,这意味着 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(); }
这是一个持续请求更新、由显示刷新率(VSync,取决于屏幕刷新率)控制的窗口部件。如果不需要连续绘制,则应从 render() 中的 update() 调用中删除,而仅在需要更新渲染内容时进行发出。例如,如果立方体的旋转应与一个 QSlider 的值绑定,则将滑块的值变化信号连接到一个槽或 lambda,该 lambda 将转发新值并调用 update() 就足够了。
顶点和片元着色器以 Vulkan 风格的 GLSL 提供,必须首先由 Qt 着色器基础设施处理。这可以通过手动运行 qsb
命令行工具或使用 CMake 中的 qt_add_shaders() 函数来实现。QRhiWidget 实现加载了与应用程序一起提供的预处理的 .qsb
文件。有关 Qt 着色器翻译基础设施的更多信息,请参阅 Qt 着色器工具。
这些着色器的源代码可能是以下内容
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); }
结果是展示以下内容的窗口部件
要查看一个完整、最小、入门级别的示例,请查看 简单 RHI Widget 示例。
有关具有更多功能和进一步概念示范的示例,请参阅 立方体 RHI Widget 示例。
QRhiWidget 总是涉及到将渲染到后置纹理中,而不是直接到窗口中(由窗口系统提供给原生窗口的表面或层)。这允许正确地将内容与基于窗口部件的 UI 的其余部分组合,并提供一个简单且紧凑的 API,使其易于入门。所有这些都以额外的资源和使用性能上的潜在影响为代价。这在实践中通常完全可接受,但对于高级用户,应牢记不同方法的优势和劣势。有关两个方法的具体细节,请参考 RHI 窗口示例 并将其与 简单 RHI Widget 示例 进行比较。
将 QRhiWidget 移入属于不同窗口(顶层窗口部件)的窗口部件层次结构中,或将 QRhiWidget 本身设置为顶层(通过将父设置为 nullptr
),涉及到在 QRhiWidget 继续正常运行的同时更改关联的 QRhi(以及可能销毁旧的),稳健的 QRhiWidget 实现应重新实现 releaseResources() 虚拟函数,并像在析构函数中一样丢弃它们的 QRhi 资源。《立方体 RHI Widget 示例》在实践中展示了这一点。
虽然不是主要的使用案例,但QRhiWidget还允许集成直接使用3D图形API(如Vulkan、Metal、Direct 3D或OpenGL)的渲染代码。有关在`QRhi`渲染通道中记录本地命令的详细信息,请参阅QRhiCommandBuffer::beginExternal(),以及有关将现有本地纹理包装并随后在随后的渲染通道中使用`QRhi`的QRhiTexture::createFrom()方法。然而,请注意,底层图形API的配置性(如其设备或上下文功能、层、扩展等)将受到限制,因为QRhiWidget的主要目标是提供一个适合基于`QRhi`的渲染代码的环境,而不是启用任意、潜在复杂的国外渲染引擎。
另请参阅QRhi、QShader、QOpenGLWidget、简单RHI Widget示例和立方RHI Widget示例。
成员类型文档
枚举类QRhiWidget::Api
指定要使用的3D API和`QRhi`后端
常量 | 值 |
---|---|
QRhiWidget::Api::Null | 0 |
QRhiWidget::Api::OpenGL | 1 |
QRhiWidget::Api::Metal | 2 |
QRhiWidget::Api::Vulkan | 3 |
QRhiWidget::Api::Direct3D11 | 4 |
QRhiWidget::Api::Direct3D12 | 5 |
另请参阅QRhi。
枚举类QRhiWidget::TextureFormat
指定`QRhiWidget`渲染的纹理格式
常量 | 值 | 描述 |
---|---|---|
QRhiWidget::TextureFormat::RGBA8 | 0 | 参见QRhiTexture::RGBA8。 |
QRhiWidget::TextureFormat::RGBA16F | 1 | 参见QRhiTexture::RGBA16F。 |
QRhiWidget::TextureFormat::RGBA32F | 2 | 参见QRhiTexture::RGBA32F。 |
QRhiWidget::TextureFormat::RGB10A2 | 3 | 参见QRhiTexture::RGB10A2。 |
另请参阅QRhiTexture。
属性文档
autoRenderTarget : const bool
当前自动深度-模板缓冲区和渲染目标维护设置的值。
默认值是true
。
colorBufferFormat : TextureFormat
该属性控制用于颜色缓冲区的纹理(或渲染缓冲区)的格式。默认值是`TextureFormat::RGBA8`。QRhiWidget支持将绘制到由QRhiTexture支持的子集中。只有那些报告为支持的格式应通过`QRhi::isTextureFormatSupported`检测出来,否则渲染将无法正常工作。
注意:在控件已经初始化并且已经渲染后设置新格式意味着由渲染器创建的所有`QRhiGraphicsPipeline`对象可能都变得不可用,如果相关的`QRhiRenderPassDescriptor`由于不同的纹理格式而变得不兼容。这类似于动态更改`sampleCount`,这意味着`initialize`或`render`实现必须负责释放现有管线并创建新的管线。
访问函数
QRhiWidget::TextureFormat | colorBufferFormat() const |
void | setColorBufferFormat(QRhiWidget::TextureFormat format) |
通知信号
void | colorBufferFormatChanged(QRhiWidget::TextureFormat format) |
fixedColorBufferSize : QSize
固定纹理的像素大小。当需要固定的纹理大小,且不依赖于小部件大小时适用。此大小不会影响小部件的几何形状(大小和在顶级窗口中的位置),这意味着纹理内容将在小部件区域拉伸(放大)或缩小。
例如,将大小设置为小部件大小(像素大小)的两倍,实际上执行了2x超采样(在两倍分辨率下渲染,然后隐式缩放窗口中小部件对应的四边形纹理)。
默认值为null QSize。null或空 QSize 意味着纹理的大小与小部件的大小一致。(纹理大小 = 小部件大小 x 设备像素比)。
访问函数
QSize | fixedColorBufferSize() const |
void | setFixedColorBufferSize(QSize pixelSize) |
void | setFixedColorBufferSize(int w, int h) |
通知信号
void | fixedColorBufferSizeChanged(const QSize &pixelSize) |
mirrorVertically : bool
启用时,在将 QRhiWidget 的背衬纹理与顶级窗口中的其他小部件内容组合时,沿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()。但是,当 autoRenderTarget 为 false
时,它将由应用程序负责管理深度-模板缓冲区或额外的颜色缓冲区。
将样本数从默认的1更改为更高值意味着 colorTexture() 成为 nullptr
,而 msaaColorBuffer() 开始返回一个有效的对象。切换回1(或0)意味着相反:在下一次调用 initialize() 时,msaaColorBuffer() 将返回 nullptr
,而 colorTexture() 重新变得有效。此外,当样本数大于1(即使用MSAA时),resolveTexture() 返回一个有效的(非多采样)QRhiTexture。
访问函数
int | sampleCount() const |
void | setSampleCount(int samples) |
通知信号
void | sampleCountChanged(int samples) |
另请参阅msaaColorBuffer() 和 resolveTexture.
成员函数文档
[显式]
QRhiWidget::QRhiWidget(QWidget *parent = nullptr, Qt::WindowFlags f = {})
构造一个作为 parent 子对象的小部件,控件标志设置为 f。
[重载虚拟 noexcept]
QRhiWidget::~QRhiWidget()
析构函数。
QRhiWidget::Api QRhiWidget::api() const
返回当前设置的图形 API (QRhi 后端)。
另请参阅setApi.
[受保护的]
QRhiTexture *QRhiWidget::colorTexture() const
返回作为小部件颜色缓冲区的纹理。
必须在 initialize() 和 render() 中调用。
与深度-字符缓冲区和 QRhiRenderTarget 不同,此纹理始终可用,并由 QRhiWidget 管理,独立于 autoRenderTarget 的值。
注意:当 sampleCount 大于 1,并且已启用多样本抗锯齿时,返回值是 nullptr
。相反,通过调用 msaaColorBuffer() 来查询 QRhiRenderBuffer。
注意:可以通过 QRhiRenderTarget 从 renderTarget() 查询支持纹理大小和样本计数。这可能比从 QRhiTexture 或 QRhiRenderBuffer 中查询更方便和紧凑,因为无论是否使用多采样都可以工作。
另请参阅msaaColorBuffer()、depthStencilBuffer()、renderTarget() 和 resolveTexture。
[受保护的]
QRhiRenderBuffer *QRhiWidget::depthStencilBuffer() const
返回小部件渲染使用的深度-字符缓冲区。
必须在 initialize() 和 render() 中调用。
仅当 autoRenderTarget 为 true
时可用。否则返回的值是 nullptr
,并且必须由 initialize() 的重实现来创建和管理深度-字符缓冲区和 QRhiTextureRenderTarget。
另请参阅colorTexture() 和 renderTarget。
[重载虚拟受保护的]
bool QRhiWidget::event(QEvent *e)
重实现: QWidget::event(QEvent *event)。
[信号]
void QRhiWidget::frameSubmitted()
此信号在部件的最顶层窗口完成合成并向提交帧后发出。
QImage QRhiWidget::grabFramebuffer() const
渲染新帧,读取纹理内容,并以QImage的形式返回。
当发生错误时,将返回空的QImage。
返回的QImage将具有QImage::Format_RGBA8888、QImage::Format_RGBA16FPx4、QImage::Format_RGBA32FPx4或QImage::Format_BGR30的格式,具体取决于colorBufferFormat。
QRhiWidget不知道渲染器的混合和合成方法,因此无法确定输出RGB颜色值中是否已经预乘了alpha通道。因此,即使在这种情况下也永远不会使用_Premultiplied
QImage格式,由调用方负责根据需要重新解释结果数据。
注意:在QRhiWidget未被添加到属于屏幕顶层窗口的部件层次结构时,也可以调用此函数。这允许从不显示的3D渲染中生成图像。
此函数命名为grabFramebuffer()是为了与QOpenGLWidget和QQuickWidget保持一致。获取QRhiWidget内容中的CPU端图像数据的不是唯一方法:在QRhiWidget或其祖先上调用QWidget::grab()也是可行的(返回QPixmap)。除了直接使用QImage外,grabFramebuffer()的另一个优点可能是性能略高,因为它无需通过QWidget的其他基础设施,但可以直接触发渲染新帧然后进行读取。
另见:setColorBufferFormat()。
[虚受保护]
void QRhiWidget::initialize(QRhiCommandBuffer *cb)
在组件首次初始化、相关纹理的大小、格式或样本计数更改,或当QRhi和纹理因任何原因更改时被调用。该功能应维护(如尚未创建则创建,大小更改则调整和重建)在
要查询QRhi、QRhiTexture和其他相关对象,请调用rhi()、colorTexture()、depthStencilBuffer()和renderTarget()。
当组件大小变化时,QRhi对象、颜色缓冲区纹理和深度/模板缓冲区对象都是相同的实例(因此getter返回相同的指针),但颜色和深度/模板缓冲区可能已重建,这意味着与上次调用相比,大小和底层的本地纹理资源可能不同。
还应准备重新实现,以便在这函数调用之间,QRhi 对象和颜色缓冲纹理可能会发生变化。一个对象将不同的特殊情况是在执行一个与尚未显示的窗口小部件相关的 grabFramebuffer() 后,然后在顶层窗口中将该窗口小部件显示出来。在那里,将使用一个专门的 QRhi 进行抓取,然后在后续的 initialize() 和 render() 调用中使用相应的顶层窗口的 QRhi 替换它。另一个更常见的情况是,当窗口小部件被重新设置其父窗口为新的顶层窗口时。在这种情况下,QRhi 及其所有相关资源将由 QRhiWidget 管理,将在随后的函数调用中与之前不同。那时,重要的是要销毁由子类先前创建的所有现有的 QRhi 资源,因为它们属于之前不应再由窗口小部件使用的 QRhi。
当 autoRenderTarget 为 true
(默认值)时,将自动创建和管理工作与 QRhiRenderBuffer 关联的深度-模板缓冲区和与 QRhiTextureRenderTarget 关联的深度-模板缓冲区以及与 colorTexture()(或 msaaColorBuffer())关联的颜色纹理。初始化() 和 render() 的重新实现可以查询这些对象,通过 depthStencilBuffer() 和 renderTarget()。当 autoRenderTarget 设置为 false
时,这些对象将不再自动创建和管理。取而代之的是,将取决于 initialize() 实现根据需要创建缓冲区并设置渲染目标。当手动管理为渲染目标添加的额外颜色或深度-模板附加时,其大小和样本数必须始终遵循 colorTexture() / msaaColorBuffer() 的大小和样本数,否则可能会发生渲染或 3D API 验证错误。
子类创建的图形资源应在子类的析构函数实现中释放。
cb 是窗口小部件当前帧的 QRhiCommandBuffer。函数调用中的帧正在录制,但没有活动的渲染通道。命令缓冲区主要提供在 render() 推迟之前排队 资源更新 的能力。
另请参阅 render()。
bool QRhiWidget::isDebugLayerEnabled() const
如果适用的图形 API 要求,则在没有参数的情况下,将请求调试或验证层。
另请参阅 setDebugLayerEnabled()。
[protected]
QRhiRenderBuffer *QRhiWidget::msaaColorBuffer() const
返回作为窗口小部件的倍样本颜色缓冲区的渲染缓冲区。
必须在 initialize() 和 render() 中调用。
当sampleCount大于1且启用多采样抗锯齿时,返回的QRhiRenderBuffer具有匹配的样本计数,充当颜色缓冲区。用于渲染到该缓冲区的图形管线必须使用相同的样本计数创建,并且深度-模板缓冲区的样本计数也必须匹配。多采样内容应解析为resolveTexture()返回的纹理。当autoRenderTarget为true
时,通过将renderbuffer设置为颜色附件0的msaaColorBuffer()以及将其resolveTexture()作为其resolveTexture来自动设置renderTarget()。
当未使用MSAA时,返回值是nullptr
。然后请使用colorTexture()代替。
根据底层3D图形API,在样本计数大于1的多样本纹理和颜色渲染缓冲区之间可能没有实际差异(QRhi可能将两者映射到相同的本地资源类型)。但是,一些较旧的API可能区分纹理和渲染缓冲区。为了支持OpenGL ES 3.0,在多样本渲染缓冲区可用而多样本纹理不可用的情况下,QRhiWidget始终通过使用多采样QRhiRenderBuffer作为颜色附件来执行MSAA(永远不会使用多样本QRhiTexture)。
注意:可以通过 QRhiRenderTarget 从 renderTarget() 查询支持纹理大小和样本计数。这可能比从 QRhiTexture 或 QRhiRenderBuffer 中查询更方便和紧凑,因为无论是否使用多采样都可以工作。
另请参阅:colorTexture(),depthStencilBuffer(),renderTarget()和resolveTexture()。
[重写虚拟受保护]
void QRhiWidget::paintEvent(QPaintEvent *e)
重实现:QWidget::paintEvent(QPaintEvent *event)。
处理绘制事件。
调用QWidget::update()将导致发送绘制事件e,从而调用此函数。事件的发送是异步的,将在从update()返回后某个时间点发生。然后此函数在做一些准备后,将调用虚拟的render()来更新QRhiWidget关联纹理的内容。然后顶层窗口将使用纹理将纹理与其他窗口组合在一起。
[虚拟受保护的]
void QRhiWidget::releaseResources()
在需要提前释放图形资源时调用。
通常,对于添加到顶层窗口的孩子层次结构中并且在整个生命周期中都保持在那里QRhiWidget的情况不会发生。因此,在许多情况下不需要重写此函数,例如,因为应用程序只有一个顶级窗口(本地窗口)。但是,当涉及小部件(或其祖先)的重命名时,重写此函数对于健壮、良好编写的QRhiWidget子类是必要的。
当调用此函数时,预期实现将销毁所有 QRhi 资源(例如 QRhiBuffer、QRhiTexture 等),类似于在析构函数中这样做。需要取消引用、使用智能指针或设置 resources-invalid
标志,因为最终还会调用到 initialize()。然而,延迟资源的释放到后续的 initialize() 是错误的。如果调用此函数,则必须在返回之前释放资源。此外,实现此函数并不替换类的析构函数(或智能指针):在两者中都必须释放图形资源。
请参考 Cube RHI Widget 示例,了解如何实际使用。在那里,切换 QRhiWidget 是否成为子控件(由于有父控件)或顶级控件(由于没有父控件)的按钮将触发调用此函数,因为相关的顶级窗口、原生窗口和 QRhi 都在 QRhiWidget 的生命周期内发生变化,之前使用的 QRhi 被销毁,这表明相关资源由仍活着 的 QRhiWidget 输出。
此函数被调用的另一个情况是在使用 grabFramebuffer() 并将 QRhiWidget 添加到可见窗口时。如果后来将此 QRhiWidget 设置为可见或添加到可见的窗口层次结构中,相关的 QRhi 将从用于离屏渲染的临时一个更改为窗口的专用一个,从而也将触发此函数。
另请参阅initialize。
[虚保护]
void QRhiWidget::render(QRhiCommandBuffer *cb)
当需要更新小部件内容(即纹理的内容)时调用。
在调用此函数之前,始终至少调用一次 initialize()。
要请求更新,请调用 QWidget::update。从 render() 中调用 update 将导致连续更新,由 vsync 节流。
cb 是小部件当前帧的 QRhiCommandBuffer。该函数在一个被记录的帧中被调用,但没有活动的渲染通道。
另请参阅initialize。
[信号]
void QRhiWidget::renderFailed()
每当小部件应渲染到其底层纹理时(无论是由于 小部件更新 还是由于对 grabFramebuffer 的调用),都会发出此信号,但没有为小部件使用 QRhi,很可能是因为与图形配置相关的问题。
当出现问题时会多次发出此信号。不要假设它只被发出一次。如果要在错误处理代码仅被通知一次的情况下连接,则请使用 Qt::SingleShotConnection。
[保护]
QRhiRenderTarget *QRhiWidget::renderTarget() const
返回需要在重写QRhiCommandBuffer::beginPass() 时使用的渲染目标对象。
必须在 initialize() 和 render() 中调用。
仅当 autoRenderTarget 为 true
时可用。否则返回的值是 nullptr
,并且必须由 initialize() 的重实现来创建和管理深度-字符缓冲区和 QRhiTextureRenderTarget。
创建 图形管线 时,需要使用到 QRhiRenderPassDescriptor。可以通过调用返回的 QRhiTextureRenderTarget 的 renderPassDescriptor() 来获取。
另见 colorTexture() 和 depthStencilBuffer()。
[重载虚保护]
void QRhiWidget::resizeEvent(QResizeEvent *e)
重写: QWidget::resizeEvent(QResizeEvent *event)。
处理传递给 e 事件参数的尺寸调整事件。调用虚函数 initialize()。
注意:避免在派生类中重写此函数。如果无法避免,确保还调用了 QRhiWidget 的实现。否则,底层纹理对象和相关资源将无法正确调整大小,从而导致渲染结果不正确。
[保护]
QRhiTexture *QRhiWidget::resolveTexture() const
返回解多采样内容的一个非多采样的纹理对象。
当未启用多采样抗锯齿时,此结果为 nullptr
。
必须在 initialize() 和 render() 中调用。
启用 MSAA 时,这是与屏幕上其他 QWidget 内容合并的纹理。然而,QRhiWidget 的渲染必须针对从 msaaColorBuffer 返回的 (多采样) QRhiRenderBuffer。如果 autoRenderTarget 是 true
,这会由从 renderTarget 返回的 QRhiRenderTarget 处理。否则,子类代码必须正确配置一个同时具有颜色缓冲区和解纹理的渲染目标对象。
另见 colorTexture()。
[保护]
QRhi *QRhiWidget::rhi() const
返回当前的 QRhi 对象。
必须在 initialize() 和 render() 中调用。
void QRhiWidget::setApi(QRhiWidget::Api api)
设置用于的图形 API 和 QRhi 后端。
警告:此函数必须在早期调用,在部件添加到部件层次结构并在屏幕上显示之前。例如,尝试在子类构造函数中调用该函数。如果调用太晚,该函数将没有任何效果。
默认值依平台而异:macOS 和 iOS 上的 Metal,Windows 上的 Direct 3D 11,其他情况下为 OpenGL。
对于部件及其顶层窗口,api 只能设置一次。一旦完成并且生效,该窗口只能使用那个 API 和 QRhi 后端进行渲染。尝试设置另一个值,或添加具有不同 api 的另一个 QRhiWidget 将不会按预期工作。
另请参阅 setColorBufferFormat(),setDebugLayerEnabled() 和 api。
[受保护]
void QRhiWidget::setAutoRenderTarget(bool enabled)
控制深度-模板 QRhiRenderBuffer 和 QRhiTextureRenderTarget 是否由小部件自动创建和维护。默认值是 true
。
在自动模式下,深度-模板缓冲区的大小和样本数遵循颜色缓冲区纹理的设置。在非自动模式下,renderTarget() 和 depthStencilBuffer() 总是返回 nullptr
,此时需要应用程序实现 initialize() 来负责设置和管理这些对象。
要禁用自动模式,可以在早期调用此函数,例如在派生类的构造函数中,将enabled 设置为 false
。
void QRhiWidget::setDebugLayerEnabled(bool enable)
当 enable 为 true 时,请求底层图形API的调试或验证层。
警告:此函数必须在早期调用,在部件添加到部件层次结构并在屏幕上显示之前。例如,尝试在子类构造函数中调用该函数。如果调用太晚,该函数将没有任何效果。
适用于 Vulkan 和 Direct 3D。
默认情况下,此功能是禁用的。
另请参阅 setApi() 和 isDebugLayerEnabled。
© 2024 The Qt Company Ltd. 本文档中包含的文档贡献是各自所有者的版权。此处提供的文档是根据 Free Software Foundation 公布的 GNU自由文档许可版1.3 的条款提供的。Qt 和相应的标识是 The Qt Company Ltd. 在芬兰和/或其他国家的商标。所有其他商标均为各自所有者的财产。