PySide6.QtGui.QRhiBuffer

class QRhiBuffer

Vertex, index, or uniform (constant) buffer resource. More

Inheritance diagram of PySide6.QtGui.QRhiBuffer

Added in version 6.6.

Synopsis

Methods

Virtual methods

Note

This documentation may contain snippets that were automatically translated from C++ to Python. We always welcome contributions to the snippet translation. If you see an issue with the translation, you can also let us know by creating a ticket on https:/bugreports.qt.io/projects/PYSIDE

Detailed Description

Note

This is a RHI API with limited compatibility guarantees, see QRhi for details.

A QRhiBuffer encapsulates zero, one, or more native buffer objects (such as a VkBuffer or MTLBuffer). With some graphics APIs and backends certain types of buffers may not use a native buffer object at all (e.g. OpenGL if uniform buffer objects are not used), but this is transparent to the user of the QRhiBuffer API. Similarly, the fact that some types of buffers may use two or three native buffers underneath, in order to allow efficient per-frame content update without stalling the GPU pipeline, is mostly invisible to the applications and libraries.

A QRhiBuffer instance is always created by calling the QRhi's newBuffer() function . This creates no native graphics resources. To do that, call create() after setting the appropriate options, such as the type, usage flags, size, although in most cases these are already set based on the arguments passed to newBuffer() .

Example usage

To create a uniform buffer for a shader where the GLSL uniform block contains a single mat4 member, and update the contents:

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

An example of creating a buffer with vertex data:

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

An index buffer:

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

Common patterns

A call to create() destroys any existing native resources if create() was successfully called before. If those native resources are still in use by an in-flight frame (i.e., there’s a chance they are still read by the GPU), the destroying of those resources is deferred automatically. Thus a very common and convenient pattern to safely increase the size of an already initialized buffer is the following. In practice this drops and creates a whole new set of native resources underneath, so it is not necessarily a cheap operation, but is more convenient and still faster than the alternatives, because by not destroying the buf object itself, all references to it stay valid in other data structures (e.g., in any QRhiShaderResourceBinding the QRhiBuffer is referenced from).

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

When working with uniform buffers, it will sometimes be necessary to combine data for multiple draw calls into a single buffer for efficiency reasons. Be aware of the aligment requirements: with some graphics APIs offsets for a uniform buffer must be aligned to 256 bytes. This applies both to QRhiShaderResourceBinding and to the dynamic offsets passed to setShaderResources() . Use the ubufAlignment() and ubufAligned() functions to create portable code. As an example, the following is an outline for issuing multiple (N) draw calls with the same pipeline and geometry, but with a different data in the uniform buffers exposed at binding point 0. This assumes the buffer is exposed via uniformBufferWithDynamicOffset() which allows passing a QRhiCommandBuffer::DynamicOffset list to 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);
}
class Type

Specifies storage type of buffer resource.

Constant

Description

QRhiBuffer.Immutable

Indicates that the data is not expected to change ever after the initial upload. Under the hood such buffer resources are typically placed in device local (GPU) memory (on systems where applicable). Uploading new data is possible, but may be expensive. The upload typically happens by copying to a separate, host visible staging buffer from which a GPU buffer-to-buffer copy is issued into the actual GPU-only buffer.

QRhiBuffer.Static

Indicates that the data is expected to change only infrequently. Typically placed in device local (GPU) memory, where applicable. On backends where host visible staging buffers are used for uploading, the staging buffers are kept around for this type, unlike with Immutable, so subsequent uploads do not suffer in performance. Frequent updates, especially updates in consecutive frames, should be avoided.

QRhiBuffer.Dynamic

Indicates that the data is expected to change frequently. Not recommended for large buffers. Typically backed by host visible memory in 2 copies in order to allow for changing without stalling the graphics pipeline. The double buffering is managed transparently to the applications and is not exposed in the API here in any form. This is the recommended, and, with some backends, the only possible, type for buffers with UniformBuffer usage.

class UsageFlag

(inherits enum.Flag) Flag values to specify how the buffer is going to be used.

Constant

Description

QRhiBuffer.VertexBuffer

Vertex buffer. This allows the QRhiBuffer to be used in setVertexInput() .

QRhiBuffer.IndexBuffer

Index buffer. This allows the QRhiBuffer to be used in setVertexInput() .

QRhiBuffer.UniformBuffer

Uniform buffer (also called constant buffer). This allows the QRhiBuffer to be used in combination with UniformBuffer . When NonDynamicUniformBuffers is reported as not supported, this usage can only be combined with the type Dynamic.

QRhiBuffer.StorageBuffer

Storage buffer. This allows the QRhiBuffer to be used in combination with BufferLoad , BufferStore , or BufferLoadStore . This usage can only be combined with the types Immutable or Static, and is only available when the Compute feature is reported as supported.

PySide6.QtGui.QRhiBuffer.m_type
PySide6.QtGui.QRhiBuffer.m_usage
PySide6.QtGui.QRhiBuffer.m_size
abstract create()
Return type:

bool

Creates the corresponding native graphics resources. If there are already resources present due to an earlier create() with no corresponding destroy() , then destroy() is called implicitly first.

Returns true when successful, false when a graphics operation failed. Regardless of the return value, calling destroy() is always safe.

endFullDynamicBufferUpdateForCurrentFrame()

To be called when the entire contents of the buffer data has been updated in the memory block returned from beginFullDynamicBufferUpdateForCurrentFrame() .

fullDynamicBufferUpdateForCurrentFrame(data[, size=0])
Parameters:
  • datavoid

  • size – int

setSize(sz)
Parameters:

sz – int

Sets the size of the buffer in bytes. The size is normally specified in newBuffer() so this function is only used when the size has to be changed. As with other setters, the size only takes effect when calling create() , and for already created buffers this involves releasing the previous native resource and creating new ones under the hood.

Backends may choose to allocate buffers bigger than sz in order to fulfill alignment requirements. This is hidden from the applications and size() will always report the size requested in sz.

See also

size()

setType(t)
Parameters:

tType

Sets the buffer’s type to t.

See also

type()

setUsage(u)
Parameters:

u – Combination of UsageFlag

Sets the buffer’s usage flags to u.

See also

usage()

size()
Return type:

int

Returns the buffer’s size in bytes.

This is always the value that was passed to setSize() or newBuffer() . Internally, the native buffers may be bigger if that is required by the underlying graphics API.

See also

setSize()

type()
Return type:

Type

Returns the buffer type.

See also

setType()

usage()
Return type:

Combination of UsageFlag

Returns the buffer’s usage flags.

See also

setUsage()