本页内容

QRhiBuffer Class

顶点、索引或统一(常量)缓冲区资源。更多...

头文件: #include <rhi/qrhi.h>
CMake: find_package(Qt6 REQUIRED COMPONENTS GuiPrivate)
target_link_libraries(mytarget PRIVATE Qt6::GuiPrivate)
qmake: QT += gui-private
自: Qt 6.6
继承自: QRhiResource

公共类型

struct NativeBuffer
enum Type { Immutable, Static, Dynamic }
enum UsageFlag { VertexBuffer, IndexBuffer, UniformBuffer, StorageBuffer, IndirectBuffer }
flags UsageFlags

公共函数

virtual char *beginFullDynamicBufferUpdateForCurrentFrame()
virtual bool create() = 0
virtual void endFullDynamicBufferUpdateForCurrentFrame()
virtual QRhiBuffer::NativeBuffer nativeBuffer()
void setSize(quint32 sz)
void setType(QRhiBuffer::Type t)
void setUsage(QRhiBuffer::UsageFlags u)
quint32 size() const
QRhiBuffer::Type type() const
QRhiBuffer::UsageFlags usage() const

重新实现的公共函数

virtual QRhiResource::Type resourceType() const override

详细说明

注意:这是一个 兼容性保证有限的 RHI API,详情请参阅QRhi 。

一个 QRhiBuffer 封装了零个、一个或多个本机缓冲区对象(例如VkBuffer 或MTLBuffer )。 在某些图形 API 和后端中,某些类型的缓冲区可能完全不使用本机缓冲区对象(例如,如果不使用统一缓冲区对象的 OpenGL),但这对 QRhiBuffer API 的用户来说是透明的。 同样,某些类型的缓冲区可能在底层使用两个或三个本机缓冲区,以便在不阻塞 GPU 管道的情况下高效地进行每帧内容更新,但这一点对应用程序和库来说基本上是不可见的。

QRhiBuffer 实例始终通过调用the QRhi's newBuffer() function 创建。这不会创建任何本机图形资源。若要创建本机图形资源,请在设置适当选项(如类型、使用标志、大小)后调用create(),尽管在大多数情况下,这些选项已根据传递给newBuffer()的参数自动设置。

使用示例

要为一个着色器创建统一缓冲区(其中 GLSL 统一块包含单个mat4 成员),并更新其内容:

QRhiBuffer *ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64);
if (!ubuf->create()) { error(); }
QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
QMatrix4x4 mvp;
// ... set up the modelview-projection matrix
batch->updateDynamicBuffer(ubuf, 0, 64, mvp.constData());
// ...
commandBuffer->resourceUpdate(batch); // or, alternatively, pass 'batch' to a beginPass() call

创建包含顶点数据的缓冲区的示例:

const float vertices[] = { -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 1.0f };
QRhiBuffer *vbuf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertices));
if (!vbuf->create()) { error(); }
QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
batch->uploadStaticBuffer(vbuf, vertices);
// ...
commandBuffer->resourceUpdate(batch); // or, alternatively, pass 'batch' to a beginPass() call

索引缓冲区:

static const quint16 indices[] = { 0, 1, 2 };
QRhiBuffer *ibuf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::IndexBuffer, sizeof(indices));
if (!ibuf->create()) { error(); }
QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
batch->uploadStaticBuffer(ibuf, indices);
// ...
commandBuffer->resourceUpdate(batch); // or, alternatively, pass 'batch' to a beginPass() call

常见模式

若此前已成功调用 `create()`,则调用 `create()` 将销毁任何现有的本机资源。 如果这些本机资源仍被正在渲染的帧所使用(即存在 GPU 仍在读取它们的可能性),则会自动推迟销毁这些资源。因此,以下模式是安全地增加已初始化缓冲区大小的非常常见且便捷的方法: 实际上,这会释放底层资源并创建一套全新的原生资源,因此并非必然是低开销的操作,但比其他替代方案更便捷且速度更快——因为未销毁buf 对象本身,因此其他数据结构中对其的所有引用仍保持有效(例如,在任何引用该QRhiBuffer的QRhiShaderResourceBinding 中)。

if (buf->size() < newSize) {
    buf->setSize(newSize);
    if (!buf->create()) { error(); }
}
// continue using buf, fill it with new data

在处理统一缓冲区时,出于效率考虑,有时需要将多个绘制调用的数据合并到一个缓冲区中。请注意对齐要求:在某些图形 API 中,统一缓冲区的偏移量必须对齐到 256 字节。这既适用于 `QRhiShaderResourceBinding `,也适用于传递给 `setShaderResources()` 的动态偏移量。 请使用ubufAlignment() 和ubufAligned() 函数来编写可移植的代码。例如,以下代码示例演示了如何使用相同的管道和几何体发出多个(N )绘制调用,但绑定点 0 处暴露的统一缓冲区中的数据各不相同。此示例假设缓冲区是通过uniformBufferWithDynamicOffset() 暴露的,该函数允许将QRhiCommandBuffer::DynamicOffset 列表传递给setShaderResources()。

const int N = 2;
const int UB_SIZE = 64 + 4; // assuming a uniform block with { mat4 matrix; float opacity; }
const int ONE_UBUF_SIZE = rhi->ubufAligned(UB_SIZE);
const int TOTAL_UBUF_SIZE = N * ONE_UBUF_SIZE;
QRhiBuffer *ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, TOTAL_UBUF_SIZE);
if (!ubuf->create()) { error(); }
QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
for (int i = 0; i < N; ++i) {
    batch->updateDynamicBuffer(ubuf, i * ONE_UBUF_SIZE, 64, matrix.constData());
    batch->updateDynamicBuffer(ubuf, i * ONE_UBUF_SIZE + 64, 4, &opacity);
}
// ...
// beginPass(), set pipeline, etc., and then:
for (int i = 0; i < N; ++i) {
    QRhiCommandBuffer::DynamicOffset dynOfs[] = { { 0, i * ONE_UBUF_SIZE } };
    cb->setShaderResources(srb, 1, dynOfs);
    cb->draw(36);
}

另请参阅 QRhiResourceUpdateBatch 、QRhi 以及QRhiCommandBuffer 。

成员类型文档

enum QRhiBuffer::Type

指定缓冲区资源的存储类型。

常量值描述
QRhiBuffer::Immutable0表示数据在初始上传后预计不会发生任何变化。在底层,此类缓冲区资源通常被放置在设备本地(GPU)内存中(在适用的系统上)。 虽然可以上传新数据,但可能开销较大。上传通常是通过复制到一个单独的、主机可见的中转缓冲区来实现的,随后从该中转缓冲区发起 GPU 缓冲区到缓冲区的复制,将数据写入实际的仅限 GPU 访问的缓冲区。
QRhiBuffer::Static1表示数据预计仅会偶尔发生变化。通常放置在设备本地(GPU)内存中(在适用的系统上)。 在采用主机可见暂存缓冲区进行上传的后端中,与“不可变”类型不同,此类数据对应的暂存缓冲区会被保留,因此后续上传不会影响性能。应避免频繁更新,尤其是连续帧中的更新。
QRhiBuffer::Dynamic2表示数据预计会频繁变化。不建议用于大型缓冲区。通常由主机可见内存提供支持,并保留两份副本,以便在不阻塞图形管道的情况下进行修改。 双缓冲机制对应用程序而言是透明管理的,且在此 API 中未以任何形式暴露。对于采用“UniformBuffer ”模式的缓冲区,这是推荐的类型,而在某些后端中,这也是唯一可用的类型。

enum QRhiBuffer::UsageFlag
flags QRhiBuffer::UsageFlags

用于指定缓冲区使用方式的标志值。

常量值描述
QRhiBuffer::VertexBuffer1 << 0顶点缓冲区。这使得QRhiBuffer 可在setVertexInput()中使用。
QRhiBuffer::IndexBuffer1 << 1索引缓冲区。这允许在 `setVertexInput()` 中使用 `QRhiBuffer `。
QRhiBuffer::UniformBuffer1 << 2统一缓冲区(也称为常量缓冲区)。这允许QRhiBuffer 与UniformBuffer()结合使用。当报告NonDynamicUniformBuffers 不被支持时,此用法只能与Dynamic类型结合使用。
QRhiBuffer::StorageBuffer1 << 3存储缓冲区。这允许将QRhiBuffer 与BufferLoad 、BufferStore 或BufferLoadStore 结合使用。此用法仅可与Immutable或Static类型结合使用,且仅在Compute feature 被报告为受支持时才可用。
QRhiBuffer::IndirectBuffer (since Qt 6.12)1 << 4间接绘制缓冲区。这允许在drawIndirect() 和drawIndexedIndirect() 中使用QRhiBuffer 。此用法可与 Immutable 或 Static 类型结合使用。在 D3D11 中,与 Dynamic 类型结合使用不受支持,此时create() 将失败。 在支持compute shaders 的后端上,此用法还可与 StorageBuffer 结合使用,从而允许计算着色器生成间接绘制命令,并由间接绘制调用使用。

UsageFlags 类型是QFlags<UsageFlag> 的 typedef。它存储 UsageFlag 值的按“或”运算组合。

成员函数文档

[virtual] char *QRhiBuffer::beginFullDynamicBufferUpdateForCurrentFrame()

返回指向包含主机可见缓冲区数据的内存块的指针。

对于中到大型的动态统一缓冲区,如果其全部内容(或至少是当前帧中着色器读取的所有区域)在每一帧都会发生变化,而基于QRhiResourceUpdateBatch 的更新机制因涉及大量数据复制而显得过于繁重,则此函数可作为一种快捷方式。

在记录任何依赖此缓冲区的渲染或计算通道之前,必须先调用此函数,随后再调用 endFullDynamicUniformBufferUpdateForCurrentFrame()。

警告: 通过此方法更新 数据与基于QRhiResourceUpdateBatch 的更新和读回操作不兼容。当尝试对同一缓冲区结合使用这两种更新模型时,可能会出现意外行为。同样,根据后端不同,通过此直接方式更新的数据可能无法被`readBackBuffer operations`识别。

警告: 通过此方法更新缓冲区数据时 ,必须在每一帧中执行更新,否则对资源执行双缓冲或三缓冲的后端可能会导致意外行为。

警告: 此方法不支持部分 更新,因为某些后端可能会采用这样的策略:在调用此函数时,缓冲区的先前内容将被丢失。必须将数据写入当前正在准备的帧中着色器读取的所有区域。

警告:此 函数仅可在录制帧时调用,即在QRhi::beginFrame()与QRhi::endFrame()之间。

警告:此 函数仅可在动态缓冲区上调用。

[pure virtual] bool QRhiBuffer::create()

创建相应的本机图形资源。如果由于之前调用了 create() 且未调用相应的destroy(),导致已经存在相关资源,则会先隐式调用destroy()。

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

[virtual] void QRhiBuffer::endFullDynamicBufferUpdateForCurrentFrame()

当缓冲区数据在beginFullDynamicBufferUpdateForCurrentFrame() 返回的内存块中全部更新完毕时,将调用此函数。

[virtual] QRhiBuffer::NativeBuffer QRhiBuffer::nativeBuffer()

返回该缓冲区的底层本机资源。如果后端不支持暴露底层本机资源,则返回值为空。

一个QRhiBuffer 可能由多个本机缓冲区对象支持,这取决于所使用的type()和QRhi 后端。 在这种情况下,所有这些资源都会包含在返回结构体中的 objects 数组内,其中 slotCount 指定了原生缓冲区对象的数量。虽然recording a frame ,但可以通过QRhi::currentFrameSlot() 来确定QRhi 正在使用哪个原生缓冲区,以执行在录制帧内对该QRhiBuffer 的读写操作。

在某些情况下,QRhiBuffer 可能完全不依赖于本机缓冲区对象。此时,slotCount 将被设置为 0,且不会返回任何有效的本机对象。这并非错误,当特定后端对于某些类型或用途的 QRhiBuffers 不使用本机缓冲区时,这种情况完全有效。

注意:请 注意,QRhi 后端可能采用各种缓冲区更新策略。与纹理不同——在纹理中,上传图像数据总是意味着在命令缓冲区中记录一个“缓冲区到图像”(或类似)的复制命令——而缓冲区(特别是动态缓冲区和UniformBuffer 缓冲区)可以以多种不同方式运行。 例如,如果某个后端和图形 API 不使用或不支持统一缓冲区(uniform buffers),则使用类型为“UniformBuffer ”的统一缓冲区(QRhiBuffer )甚至可能完全不以本机缓冲区对象为后端。 在数据写入缓冲区的方式以及所使用的后备内存类型方面也存在差异。对于由主机可见内存支持的缓冲区,调用此函数可确保对所有返回的原生缓冲区执行待处理的主机写入操作。

另请参阅 QRhi::currentFrameSlot() 和QRhi::FramesInFlight 。

[override virtual] QRhiResource::Type QRhiBuffer::resourceType() const

重写了:QRhiResource::resourceType() const。

返回资源类型。

void QRhiBuffer::setSize(quint32 sz)

设置缓冲区的大小(单位为字节)。该大小通常在QRhi::newBuffer()中指定,因此此函数仅在需要更改大小时使用。与其他设置器一样,该大小仅在调用create()时生效;对于已创建的缓冲区,这涉及释放之前的本机资源并在后台创建新的资源。

后端可能会选择分配比 `sz ` 更大的缓冲区,以满足对齐要求。这一操作对应用程序是不可见的,且 `size()` 始终会报告在 `sz` 中请求的大小。

另请参阅 size()。

void QRhiBuffer::setType(QRhiBuffer::Type t)

将缓冲区的类型设置为t 。

另请参阅 type()。

void QRhiBuffer::setUsage(QRhiBuffer::UsageFlags u)

将缓冲区的使用标志设置为u 。

另请参阅 usage()。

quint32 QRhiBuffer::size() const

返回缓冲区的大小(以字节为单位)。

该值始终是传递给 `setSize()` 或 `QRhi::newBuffer()` 的参数值。在内部,如果底层图形 API 有此要求,本机缓冲区可能会更大。

另请参阅 setSize()。

QRhiBuffer::Type QRhiBuffer::type() const

返回缓冲区类型。

另请参阅 setType()。

QRhiBuffer::UsageFlags QRhiBuffer::usage() const

返回缓冲区的使用标志。

另请参阅 setUsage()。

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