QRhiSwapChain 类

交换链资源。更多信息...

头文件 #include <QRhiSwapChain>
CMakefind_package(Qt6 REQUIRED COMPONENTS Gui)
target_link_libraries(mytarget PRIVATE Qt6::Gui)
qmakeQT += gui
自从Qt 6.6
继承 QRhiResource

公共类型

枚举Flag { SurfaceHasPreMulAlpha, SurfaceHasNonPreMulAlpha, sRGB, UsedAsTransferSource, NoVSync, MinimalBufferCount }
标志标志
枚举Format { SDR, HDRExtendedSrgbLinear, HDR10, HDRExtendedDisplayP3Linear }
枚举StereoTargetBuffer { LeftBuffer, RightBuffer }

公共函数

virtual boolcreateOrResize() = 0
virtual QRhiCommandBuffer *currentFrameCommandBuffer() = 0
virtual QRhiRenderTarget *currentFrameRenderTarget() = 0
virtual QRhiRenderTarget *currentFrameRenderTarget(QRhiSwapChain::StereoTargetBuffer targetBuffer)
QSizecurrentPixelSize() const
QRhiRenderBuffer *depthStencil() const
QRhiSwapChain::Flagsflags() const
QRhiSwapChain::Formatformat() const
virtual QRhiSwapChainHdrInfohdrInfo()
virtual boolisFormatSupported(QRhiSwapChain::Format f) = 0
virtual QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() = 0
QRhiSwapChainProxyDataproxyData() const
QRhiRenderPassDescriptor *renderPassDescriptor() const
intsampleCount() const
voidsetDepthStencil(QRhiRenderBuffer *ds)
voidsetFlags(QRhiSwapChain::Flags f)
voidsetFormat(QRhiSwapChain::Format f)
voidsetProxyData(const QRhiSwapChainProxyData &d)
voidsetRenderPassDescriptor(QRhiRenderPassDescriptor *desc)
voidsetSampleCount(int samples)
voidsetWindow(QWindow *window)
virtual QSizesurfacePixelSize() = 0
QWindow *window() const

重实现的公共函数

virtual QRhiResource::TyperesourceType() const override

详细描述

交换链允许将渲染结果呈现到表面上。交换链通常后面是一组颜色缓冲区。其中之一每次显示。

以下是在QWindow上渲染时创建和管理swapchain及其相关资源的典型模式。

void init()
{
    sc = rhi->newSwapChain();
    ds = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
                              QSize(), // no need to set the size here due to UsedWithSwapChainOnly
                              1,
                              QRhiRenderBuffer::UsedWithSwapChainOnly);
    sc->setWindow(window);
    sc->setDepthStencil(ds);
    rp = sc->newCompatibleRenderPassDescriptor();
    sc->setRenderPassDescriptor(rp);
    resizeSwapChain();
}

void resizeSwapChain()
{
    hasSwapChain = sc->createOrResize();
}

void render()
{
    if (!hasSwapChain || notExposed)
        return;

    if (sc->currentPixelSize() != sc->surfacePixelSize() || newlyExposed) {
        resizeSwapChain();
        if (!hasSwapChain)
            return;
        newlyExposed = false;
    }

    rhi->beginFrame(sc);
    // ...
    rhi->endFrame(sc);
}

避免依赖QWindow的尺寸调整事件来调整swapchain,尤其是在考虑到表面大小可能与QWindow报告的维度不完全匹配的情况下。一个安全、跨平台的方法是在启动新帧时通过surfacePixelSize()进行检查。

释放swapchain必须发生在QWindow及其底层本地窗口完全运行时。基于前一个示例

void releaseSwapChain()
{
    if (hasSwapChain) {
        sc->destroy();
        hasSwapChain = false;
    }
}

// assuming Window is our QWindow subclass
bool Window::event(QEvent *e)
{
    switch (e->type()) {
    case QEvent::UpdateRequest: // for QWindow::requestUpdate()
        render();
        break;
    case QEvent::PlatformSurface:
        if (static_cast<QPlatformSurfaceEvent *>(e)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed)
            releaseSwapChain();
        break;
    default:
        break;
    }
    return QWindow::event(e);
}

初始化swapchain并开始渲染第一帧不能在任何时间开始。一个安全、跨平台的办法是依赖于暴露事件。QExposeEvent()是一个松散定义的事件,在窗口被映射、遮挡和调整大小时发送,具体取决于平台。

void Window::exposeEvent(QExposeEvent *)
{
    // initialize and start rendering when the window becomes usable for graphics purposes
    if (isExposed() && !running) {
        running = true;
        init();
    }

    // stop pushing frames when not exposed or size becomes 0
    if ((!isExposed() || (hasSwapChain && sc->surfacePixelSize().isEmpty())) && running)
        notExposed = true;

    // continue when exposed again and the surface has a valid size
    if (isExposed() && running && notExposed && !sc->surfacePixelSize().isEmpty()) {
        notExposed = false;
        newlyExposed = true;
    }

    if (isExposed() && !sc->surfacePixelSize().isEmpty())
        render();
}

一旦开始渲染,请求新帧的一个简单方法是QWindow::requestUpdate().在某些平台上,这只是一个小计时器,在其他平台上有一个特定的实现:例如,在macOS或iOS上,它可能由CVDisplayLink()支持。上面的例子已经准备好了更新请求,通过处理QEvent::UpdateRequest()。

当作为QRhiRenderTarget()工作时,QRhiSwapChain也会管理一个QRhiCommandBuffer()。调用QRhi::endFrame()会提交记录的命令,并队列一个present请求。默认行为是在遇到QRhiSwapChain:NoVSync()时禁用这个行为。这意味着同步到显示器的垂直刷新被启用。因此,调用beginFrame()和endFrame()的渲染线程将被降低到vsync。在某些后端中,可以通过在flags()中传递QRhiSwapChain:NoVSync()来禁用这一点。

当通过setSampleCount()请求时,多重采样(MSAA)对应用程序是透明的。适用时,QRhiSwapChain将负责创建额外的颜色缓冲区,并在一帧结束时发出多重采样解析命令。对于OpenGL,也有必要通过调用QSurfaceFormat::setDefaultFormat()在初始化QRhi()之前请求适当的样本数量。

注意: 这是一个RHI API,具有有限的兼容性保证,有关详细信息请见QRhi()。

成员类型文档

enum QRhiSwapChain::Flag
flags QRhiSwapChain::Flags

Flag值用于描述swapchain属性

常量描述
QRhiSwapChain::SurfaceHasPreMulAlpha1 << 0表示目标表面具有预乘alpha的透明度。例如,当目标QWindow()上的alpha通道开启时,Qt Quick就是这样使用的,因为场景图渲染器总是输出带有将alpha值乘入红色、绿色和蓝色值的片段。为了保证跨平台的相同行为,每当在swapchain上设置此标志时,始终将QSurfaceFormat::alphaBufferSize()设置为非零值在目标QWindow()上。
QRhiSwapChain::SurfaceHasNonPreMulAlpha1 << 1表示目标表面具有非预乘alpha的透明度。请注意,这可能在某些系统上不受支持,如果系统合成器始终期望预乘alpha的内容。在这种情况下,设置此标志后的行为预计与SurfaceHasPreMulAlpha相同。
QRhiSwapChain::sRGB1 << 2如果是适用的情况下,请求为swapchain的色彩缓冲区以及/或者渲染目标视图选择sRGB格式。请注意,这意味着将启用sRGB帧缓冲区更新和混合功能,适用于所有针对此swapchain的目标内容,选择退出是不可能的。对于OpenGL,请此外在QSurfaceFormatQSurfaceFormat上设置QWindowsRGBColorSpace。仅当swapchain格式设置为QRhiSwapChain::SDR时适用。
QRhiSwapChain::UsedAsTransferSource1 << 3表示swapchain将被用作QRhiResourceUpdateBatch::readBackTexture读取回的源。
QRhiSwapChain::NoVSync1 << 4请求禁用等待垂直同步,同时也避免限制渲染线程。该行为是后端特定的,并且仅在其存在控制此功能的情况时适用。有些人可能会完全忽略这个请求。对于OpenGL,尝试通过在QWindow上设置交换间隔为0来代替,通过QSurfaceFormat::setSwapInterval
QRhiSwapChain::MinimalBufferCount1 << 5请求以最小数量的缓冲区创建swapchain,实际情况下通常是2,除非图形实现具有更高的最小数量。仅适用于通过图形API提供此类控制的后期支持,例如Vulkan。默认情况下,由后期支持决定要求多少个缓冲区(实际上这几乎是总是2或3),这不是应用的关注点。然而,例如在Vulkan中,后期支持可能会偏向更高的数字(3),例如避免移动设备上某些Vulkan实现的一些不寻常的性能问题。在某些平台上,强迫更低的缓冲区数量(2)可能是有益的,因此此标志允许强制这样做。请注意,所有这些对飞行帧的数量没有影响,因此CPU(QRhi)仍然最多会提前准备N - 1帧,即使当swapchain图像缓冲区数量大于N。 (N = QRhi::FramesInFlight并且通常是2)。

Flags类型是QFlags<Flag>的一个typedef。它存储了Flag值的或组合。

enum QRhiSwapChain::Format

描述了swapchain格式。默认格式是SDR。

此枚举与isFormatSupported一起使用,用于提前检查使用给定格式创建swapchain是否受平台和窗口关联屏幕支持,并在第一次调用createOrResize之前通过setFormat设置请求的格式。

常量描述
QRhiSwapChain::SDR08位RGBA或BGRA,取决于后端和平台。特别是对于OpenGL ES,平台可能提供的位数少于8位(例如,由于EGL和QSurfaceFormat选择565或444格式 - 这超出了QRhi的控制)。标准动态范围。可能结合设置QRhiSwapChain::sRGB标志。
QRhiSwapChain::HDRExtendedSrgbLinear116位浮点RAVA,高动态范围,扩展线性sRGB(scRGB)颜色空间。这涉及到Rec.709原色(与SDR/sRGB相同)和线性颜色。将转换为显示的本地颜色空间(例如,HDR10)由窗口系统执行。在Windows中,这是系统合成器的规范颜色空间,并且在桌面平台上是HDR swapchain的一般的推荐格式。
QRhiSwapChain::HDR10210位无符号RGB或BGR带2位alpha,高动态范围,HDR 10(Rec.2020)颜色空间,带有ST 2084 PQ转换函数。
QRhiSwapChain::HDRExtendedDisplayP3Linear316位浮点RGBA,高动态范围,扩展线性Display P3色彩空间。是iOS和VisionOS等平台上的HDR首选。

枚举 QRhiSwapChain::StereoTargetBuffer

选择与立体交换链一起使用的后备缓冲区。

常量
QRhiSwapChain::LeftBuffer0
QRhiSwapChain::RightBuffer1

成员函数文档

[纯虚函数] bool QRhiSwapChain::createOrResize()

如果尚未创建,则创建交换链,并调整交换链缓冲区的大小以匹配目标表面的当前尺寸。当目标表面的尺寸与之前不同时,请调用此函数。

注意:只有在交换链需要完全释放时才调用 destroy(),通常是在 QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed 时。要进行缩放,只需调用 createOrResize()。

成功时返回 true,图形操作失败时返回 false。无论返回值如何,调用 destroy() 总是安全的。

[纯虚函数] QRhiCommandBuffer *QRhiSwapChain::currentFrameCommandBuffer()

返回一个可以在 beginFrame - endFrame 块内记录渲染命令和资源更新的命令缓冲区,前提是使用此交换链调用了 beginFrame()。

注意:返回的对象在 endFrame() 之后仍然有效,直到下一次调用 beginFrame(),但此时不应使用该返回的命令缓冲区记录任何命令。相反,可以使用它查询在帧(或以前的帧)期间收集的数据,例如通过调用 last Completed GpuTime()。

注意:该值不得在帧之间缓存和重用。调用者不应在再次调用 beginFrame() 后保留返回的对象。相反,应该通过调用此函数再次查询命令缓冲区对象。

[纯虚函数] QRhiRenderTarget *QRhiSwapChain::currentFrameRenderTarget()

返回一个可以与 beginPass() 一起使用以便渲染交换链当前后缓冲区的渲染目标。仅在调用 beginFrame() 时使用此交换链的 QRhi::beginFrame() - QRhi::endFrame() 块内有效。

注意:该值不得在帧之间缓存和重用

[虚拟] QRhiRenderTarget *QRhiSwapChain::currentFrameRenderTarget(QRhiSwapChain::StereoTargetBuffer targetBuffer)

返回一个可以通过 beginPass() 用于将渲染到交换链的左或右后缓冲区的渲染目标。此重载只有在立体渲染时才应使用,即在关联的 QWindow 由两个颜色缓冲区支持时,每个眼睛一个,而不是只有一个。

当不支持立体渲染时,返回值将是默认目标。Metal和Null后端不支持立体渲染,仅当运行时图形和显示驱动程序堆栈支持时才支持,除非是Metal,与 QSurfaceFormat::StereoBuffers 结合使用。

注意:该值不得在帧之间缓存和重用

QSize QRhiSwapChain::currentPixelSize() const

返回上次成功构建swapchain时的大小。使用此信息来决定是否需要再次调用createOrResize():如果currentPixelSize() != surfacePixelSize(),则需要调整swapchain的大小。

注意:典型的渲染逻辑将在开始准备新帧时调用此函数以获取输出大小,并基于此函数返回的大小执行基于依赖的计算(例如,视口)。

虽然在不 nombreuses情况下,这个值与QWindow::size() * QWindow::devicePixelRatio()相同,但依赖于QWindow报告的大小并不保证在所有平台和图形API实现上都正确。因此,在需要识别输出层或表面的像素尺寸时,强烈建议使用此函数。

此外,这还有一个好处,可以避免在专用的渲染线程中使用QRhi时潜在的竞态条件,因为避免了调用可能会访问主线程上更新的数据的QWindow函数。

另请参阅surfacePixelSize

QRhiRenderBuffer *QRhiSwapChain::depthStencil() const

返回当前关联的用于深度-模板的rendebuffer。

另请参阅setDepthStencil

QRhiSwapChain::Flags QRhiSwapChain::flags() const

返回当前设置的标志。

另请参阅setFlags

QRhiSwapChain::Format QRhiSwapChain::format() const

返回当前设置的格式。

另请参阅setFormat

[虚拟] QRhiSwapChainHdrInfo QRhiSwapChain::hdrInfo()

返回关联显示的高动态范围信息。

不要假设这是一个便宜的操作。根据平台的不同,此函数会执行各种平台查询,可能会影响性能。

注意:只要设置了窗口,就可以在createOrResize()之前调用此函数。

注意:在多个显示(HDR到HDR特性不同的HDR,HDR到SDR等)之间移动已初始化了swapchain的窗口时发生的情况目前定义得并不好,并且高度取决于窗口系统和合成器,不同平台之间的行为可能会有所不同。目前QRhi仅保证在创建或调整大小时的swapchain相关窗口所属的显示上,如果可用,则hdrInfo()返回有效的数据。

另请参阅QRhiSwapChainHdrInfo

[纯净虚拟] 布尔值 QRhiSwapChain::isFormatSupported(QRhiSwapChain::Format f)

如果给定的swapchain格式f受支持,则返回true。SDR始终受支持。

注意: 可以独立于createOrResize()调用,但window()必须已经设置。在没有设置窗口的情况下调用可能会导致根据后端和平台出现意外的结果(对于任何HDR格式很可能为false),因为HDR格式支持通常是与swapchain关联的窗口在任何给定时间所属的输出(屏幕)绑定。如果结果是HDR格式的true,那么创建该格式的swapchain预计在中间没有将窗口移动到另一个屏幕的情况下应该成功。

该函数的主要用途是在设置窗口之后调用createOrResize()之前调用它。这允许QRhi后端执行平台或窗口系统特定的查询,以确定窗口(及其屏幕)是否能够使用指定的格式输出真正的HDR。

当格式报告为支持时,调用setFormat()设置请求的格式,并调用createOrResize()。但是请注意后果:成功请求HDR格式将涉及处理不同的色彩空间,可能需要对非HDR感知内容进行白场校正,调整色调映射方法,调整离屏渲染目标设置等。

另请参阅setFormat

[纯虚函数] QRhiRenderPassDescriptor *QRhiSwapChain::newCompatibleRenderPassDescriptor()

返回一个与新swapchain兼容的QRhiRenderPassDescriptor

返回值有两种用途:它可以传递给setRenderPassDescriptor()和QRhiGraphicsPipeline::setRenderPassDescriptor()。渲染通道描述符描述了附件(颜色、深度/模板)和加载/存储行为,这些行为可以受到flags的影响。一个QRhiGraphicsPipeline只能与设置有兼容QRhiRenderPassDescriptor的swapchain一起使用。

另请参阅 createOrResize

QRhiSwapChainProxyData QRhiSwapChain::proxyData() const

返回当前设置的代理数据。

另请参阅 setProxyData

QRhiRenderPassDescriptor *QRhiSwapChain::renderPassDescriptor() const

返回当前关联的QRhiRenderPassDescriptor对象。

另请参阅 setRenderPassDescriptor

[重写虚函数] QRhiResource::Type QRhiSwapChain::resourceType() const

重写: QRhiResource::resourceType() const.

返回资源类型。

int QRhiSwapChain::sampleCount() const

返回当前设置的样本计数。1表示没有多样本抗锯齿。

另请参阅 setSampleCount

void QRhiSwapChain::setDepthStencil(QRhiRenderBuffer *ds)

设置渲染缓冲区ds以用作深度-模板缓冲区。

另请参阅 depthStencil

void QRhiSwapChain::setFlags(QRhiSwapChain::Flags f)

设置标志f

另请参阅 flags

void QRhiSwapChain::setFormat(QRhiSwapChain::Format f)

设置格式f

避免设置从isFormatSupported报告中指出的不受支持的格式。注意,对特定格式的支持可能取决于交换链关联的窗口打开的屏幕。在某些平台上,例如Windows和macOS,要使HDR输出正常工作,必须在显示设置中启用HDR输出。

有关高动态范围输出的更多信息,请参阅isFormatSupportedQRhiSwapChainHdrInfoFormat

另请参阅 format

void QRhiSwapChain::setProxyData(const QRhiSwapChainProxyData &d)

设置代理数据d

另请参阅 proxyDataQRhi::updateSwapChainProxyData

void QRhiSwapChain::setRenderPassDescriptor(QRhiRenderPassDescriptor *desc)

QRhiRenderPassDescriptor desc相关联。

另请参阅 renderPassDescriptor

void QRhiSwapChain::setSampleCount(int samples)

设置样本计数。samples的常见值是1(无MSAA)、4(4x MSAA)或8(8x MSAA)。

另请参阅 sampleCountQRhi::supportedSampleCounts

void QRhiSwapChain::setWindow(QWindow *window)

设置window

另请参阅 window

[纯虚函数] QSize QRhiSwapChain::surfacePixelSize()

返回窗口关联的表面或层的尺寸。

警告: 不要假设这和QWindow::size() * QWindow::devicePixelRatio()相同。在一些图形API和窗口系统接口(例如,Vulkan)中,表面可能具有不同于相关窗口的尺寸。为了支持这些情况,渲染逻辑必须始终基于从QRhiSwapChain返回的尺寸进行尺寸衍生计算(例如,视口),而不是基于从QWindow查询的尺寸

注意:如果已经设置了 createOrResize(),也可以在调用之前做这样的操作。此操作与 window() 结合,可以用来检测当需要调整 swapchain 的大小。然而,请注意,底层原始对象(表面、层等)的大小是“实时”的,因此每次调用此函数时,它都返回底层实现报告的最新值,而不提供任何原子性保证。因此,强烈不鼓励使用此函数来确定用于帧中图形资源的像素大小。相反,请依赖于 currentPixelSize(),它返回一个在 createOrResize() 调用之间不会改变的原子性大小。

注意:对于与 swapchain 的颜色缓冲区一起使用的深度-模板缓冲区,强烈建议依赖于 QRhiRenderBuffer:UsedWithSwapChainOnly 标志提供的自动大小调整和重建行为。避免通过此函数查询表面大小,仅为了将大小传递给 QRhiRenderBuffer::setPixelSize(),因为这会像上述一样缺乏原子性。

另请参阅:currentPixelSize().

QWindow *QRhiSwapChain::window() const

返回当前已设置的窗口。

另请参阅:setWindow().

© 2024 The Qt Company Ltd. 本文件中包含的文档贡献版权归其各自所有者所有。本文件中提供的文档是在自由软件基金会发布的 GNU 自由文档许可协议版本 1.3 的条款下授权的。Qt 及相关标志是 The Qt Company Ltd. 在芬兰和/或其他国家的商标。所有其他商标均为其各自所有者的财产。