QRhiCommandBuffer Class
Command buffer resource. More...
| Header: | #include <rhi/qrhi.h> |
| CMake: | find_package(Qt6 REQUIRED COMPONENTS GuiPrivate)target_link_libraries(mytarget PRIVATE Qt6::GuiPrivate) |
| qmake: | QT += gui-private |
| Since: | Qt 6.6 |
| Inherits: | QRhiResource |
Public Types
| enum | BeginPassFlag { ExternalContent, DoNotTrackResourcesForCompute } |
| flags | BeginPassFlags |
| DynamicOffset | |
| enum | IndexFormat { IndexUInt16, IndexUInt32 } |
| VertexInput |
Public Functions
| void | beginComputePass(QRhiResourceUpdateBatch *resourceUpdates = nullptr, QRhiCommandBuffer::BeginPassFlags flags = {}) |
| void | beginExternal() |
| void | beginPass(QRhiRenderTarget *rt, const QColor &colorClearValue, const QRhiDepthStencilClearValue &depthStencilClearValue, QRhiResourceUpdateBatch *resourceUpdates = nullptr, QRhiCommandBuffer::BeginPassFlags flags = {}) |
| void | buildIndirect(QRhiIndirectCommandBuffer *icb, const QRhiIndirectCommandBufferBuildInfo &info) |
| void | debugMarkBegin(const QByteArray &name) |
| void | debugMarkEnd() |
| void | debugMarkMsg(const QByteArray &msg) |
| void | dispatch(int x, int y, int z) |
(since 6.13) void | dispatchIndirect(QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset = 0) |
| void | draw(quint32 vertexCount, quint32 instanceCount = 1, quint32 firstVertex = 0, quint32 firstInstance = 0) |
| void | drawIndexed(quint32 indexCount, quint32 instanceCount = 1, quint32 firstIndex = 0, qint32 vertexOffset = 0, quint32 firstInstance = 0) |
(since 6.12) void | drawIndexedIndirect(QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset, quint32 drawCount, quint32 stride = sizeof(QRhiIndexedIndirectDrawCommand)) |
(since 6.13) void | drawIndexedIndirectCount(QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset, QRhiBuffer *countBuffer, quint32 countBufferOffset, quint32 maxDrawCount, quint32 stride = sizeof(QRhiIndexedIndirectDrawCommand)) |
(since 6.12) void | drawIndirect(QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset, quint32 drawCount, quint32 stride = sizeof(QRhiIndirectDrawCommand)) |
(since 6.13) void | drawIndirectCount(QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset, QRhiBuffer *countBuffer, quint32 countBufferOffset, quint32 maxDrawCount, quint32 stride = sizeof(QRhiIndirectDrawCommand)) |
| void | endComputePass(QRhiResourceUpdateBatch *resourceUpdates = nullptr) |
| void | endExternal() |
| void | endPass(QRhiResourceUpdateBatch *resourceUpdates = nullptr) |
| void | executeIndirect(QRhiIndirectCommandBuffer *icb, quint32 firstCommand = 0, quint32 commandCount = 0xFFFFFFFFu) |
| double | lastCompletedGpuTime() |
| const QRhiNativeHandles * | nativeHandles() |
| void | resourceUpdate(QRhiResourceUpdateBatch *resourceUpdates) |
| void | setBlendConstants(const QColor &c) |
| void | setComputePipeline(QRhiComputePipeline *ps) |
| void | setGraphicsPipeline(QRhiGraphicsPipeline *ps) |
| void | setScissor(const QRhiScissor &scissor) |
| void | setShaderResources(QRhiShaderResourceBindings *srb = nullptr, int dynamicOffsetCount = 0, const QRhiCommandBuffer::DynamicOffset *dynamicOffsets = nullptr) |
(since 6.9) void | setShadingRate(const QSize &coarsePixelSize) |
| void | setStencilRef(quint32 refValue) |
| void | setVertexInput(int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings, QRhiBuffer *indexBuf = nullptr, quint32 indexOffset = 0, QRhiCommandBuffer::IndexFormat indexFormat = IndexUInt16) |
| void | setViewport(const QRhiViewport &viewport) |
Reimplemented Public Functions
| virtual QRhiResource::Type | resourceType() const override |
Detailed Description
Not creatable by applications at the moment. The only ways to obtain a valid QRhiCommandBuffer are to get it from the targeted swapchain via QRhiSwapChain::currentFrameCommandBuffer(), or, in case of rendering completely offscreen, initializing one via QRhi::beginOffscreenFrame().
Note: This is a RHI API with limited compatibility guarantees, see QRhi for details.
Member Type Documentation
enum QRhiCommandBuffer::BeginPassFlag
flags QRhiCommandBuffer::BeginPassFlags
Flag values for QRhi::beginPass()
| Constant | Value | Description |
|---|---|---|
QRhiCommandBuffer::ExternalContent | 0x01 | Specifies that there will be a call to QRhiCommandBuffer::beginExternal() in this pass. Some backends, Vulkan in particular, will fail if this flag is not set and beginExternal() is still called. |
QRhiCommandBuffer::DoNotTrackResourcesForCompute | 0x02 | Specifies that there is no need to track resources used in this pass if the only purpose of such tracking is to generate barriers for compute. Implies that there are no compute passes in the frame. This is an optimization hint that may be taken into account by certain backends, OpenGL in particular, allowing them to skip certain operations. When this flag is set for a render pass in a frame, calling beginComputePass() in that frame may lead to unexpected behavior, depending on the resource dependencies between the render and compute passes. |
The BeginPassFlags type is a typedef for QFlags<BeginPassFlag>. It stores an OR combination of BeginPassFlag values.
[alias] QRhiCommandBuffer::DynamicOffset
Synonym for std::pair<int, quint32>. The first entry is the binding, the second is the offset in the buffer.
enum QRhiCommandBuffer::IndexFormat
Specifies the index data type
| Constant | Value | Description |
|---|---|---|
QRhiCommandBuffer::IndexUInt16 | 0 | Unsigned 16-bit (quint16) |
QRhiCommandBuffer::IndexUInt32 | 1 | Unsigned 32-bit (quint32) |
[alias] QRhiCommandBuffer::VertexInput
Synonym for std::pair<QRhiBuffer *, quint32>. The second entry is an offset in the buffer specified by the first.
Member Function Documentation
void QRhiCommandBuffer::beginComputePass(QRhiResourceUpdateBatch *resourceUpdates = nullptr, QRhiCommandBuffer::BeginPassFlags flags = {})
Records starting a new compute pass.
resourceUpdates, when not null, specifies a resource update batch that is to be committed and then released.
Note: Do not assume that any state or resource bindings persist between passes.
Note: A compute pass can record setComputePipeline(), setShaderResources(), and dispatch() calls, not graphics ones. General functionality, such as, debug markers and beginExternal() is available both in render and compute passes.
Note: Compute is only available when the Compute feature is reported as supported.
flags is not currently used.
void QRhiCommandBuffer::beginExternal()
To be called when the application before the application is about to enqueue commands to the current pass' command buffer by calling graphics API functions directly.
Note: This is only available when the intent was declared upfront in beginPass() or beginComputePass(). Therefore this function must only be called when the pass recording was started with specifying QRhiCommandBuffer::ExternalContent.
With Vulkan, Metal, or Direct3D 12 one can query the native command buffer or encoder objects via nativeHandles() and enqueue commands to them. With OpenGL or Direct3D 11 the (device) context can be retrieved from QRhi::nativeHandles(). However, this must never be done without ensuring the QRhiCommandBuffer's state stays up-to-date. Hence the requirement for wrapping any externally added command recording between beginExternal() and endExternal(). Conceptually this is the same as QPainter's beginNativePainting() and endNativePainting() functions.
For OpenGL in particular, this function has an additional task: it makes sure the context is made current on the current thread.
Note: Once beginExternal() is called, no other render pass specific functions (set* or draw*) must be called on the QRhiCommandBuffer until endExternal().
Warning: Some backends may return a native command buffer object from QRhiCommandBuffer::nativeHandles() that is different from the primary one when inside a beginExternal() - endExternal() block. Therefore it is important to (re)query the native command buffer object after calling beginExternal(). In practical terms this means that with Vulkan for example the externally recorded Vulkan commands are placed onto a secondary command buffer (with VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT). nativeHandles() returns this secondary command buffer when called between begin/endExternal.
See also endExternal() and nativeHandles().
void QRhiCommandBuffer::beginPass(QRhiRenderTarget *rt, const QColor &colorClearValue, const QRhiDepthStencilClearValue &depthStencilClearValue, QRhiResourceUpdateBatch *resourceUpdates = nullptr, QRhiCommandBuffer::BeginPassFlags flags = {})
Records starting a new render pass targeting the render target rt.
resourceUpdates, when not null, specifies a resource update batch that is to be committed and then released.
The color and depth/stencil buffers of the render target are normally cleared. The clear values are specified in colorClearValue and depthStencilClearValue. The exception is when the render target was created with QRhiTextureRenderTarget::PreserveColorContents and/or QRhiTextureRenderTarget::PreserveDepthStencilContents. The clear values are ignored then.
Note: Enabling preserved color or depth contents leads to decreased performance depending on the underlying hardware. Mobile GPUs with tiled architecture benefit from not having to reload the previous contents into the tile buffer. Similarly, a QRhiTextureRenderTarget with a QRhiTexture as the depth buffer is less efficient than a QRhiRenderBuffer since using a depth texture triggers requiring writing the data out to it, while with renderbuffers this is not needed (as the API does not allow sampling or reading from a renderbuffer).
Note: Do not assume that any state or resource bindings persist between passes.
Note: The QRhiCommandBuffer's set and draw functions can only be called inside a pass. Also, with the exception of setGraphicsPipeline(), they expect to have a pipeline set already on the command buffer. Unspecified issues may arise otherwise, depending on the backend.
If rt is a QRhiTextureRenderTarget, beginPass() performs a check to see if the texture and renderbuffer objects referenced from the render target are up-to-date. This is similar to what setShaderResources() does for QRhiShaderResourceBindings. If any of the attachments had been rebuilt since QRhiTextureRenderTarget::create(), an implicit call to create() is made on rt. Therefore, if rt has a QRhiTexture color attachment texture, and one needs to make the texture a different size, the following is then valid:
QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget({ { texture } });
rt->create();
// ...
texture->setPixelSize(new_size);
texture->create();
cb->beginPass(rt, colorClear, dsClear); // this is ok, no explicit rt->create() is required beforeflags allow controlling certain advanced functionality. One commonly used flag is ExternalContents. This should be specified whenever beginExternal() will be called within the pass started by this function.
See also endPass() and BeginPassFlags.
void QRhiCommandBuffer::buildIndirect(QRhiIndirectCommandBuffer *icb, const QRhiIndirectCommandBufferBuildInfo &info)
Records populating the indirect command buffer icb from the buffer and parameters described by info.
This is the GPU-driven counterpart of recording draw() or drawIndexed() calls on the QRhiIndirectCommandBuffer: the commands come from info.sourceBuffer, which is typically written by a compute shader earlier in the frame. Any commands recorded on the CPU side are ignored from this point on.
info.topology and, for an indirect command buffer of type QRhiIndirectCommandBuffer::IndexedDraws, info.indexBuffer have to be specified because some backends need them in order to build their native indirect command buffer object, and neither is available outside of a render pass. They must match what is set on the command buffer when executeIndirect() is called.
info.commandCount is the number of commands to take from info.sourceBuffer, and becomes what QRhiIndirectCommandBuffer::commandCount() reports from here on. Leaving it at 0 means icb's QRhiIndirectCommandBuffer::maxCommandCount(); a larger value is clamped to that, with a warning. The size of info.sourceBuffer is not consulted. When info.countBuffer is set, info.commandCount becomes an upper bound instead, with the device-side count deciding how many commands are executed.
Note: This function must be called outside of any pass. That is the entire point: it gives backends that need to run a compute shader in order to build their native indirect command buffer a place to do so without having to interrupt and restart the render pass.
See also executeIndirect() and QRhiIndirectCommandBuffer.
void QRhiCommandBuffer::debugMarkBegin(const QByteArray &name)
Records a named debug group on the command buffer with the specified name. This is shown in graphics debugging tools such as RenderDoc and XCode. The end of the grouping is indicated by debugMarkEnd().
Note: Ignored when QRhi::DebugMarkers are not supported or QRhi::EnableDebugMarkers is not set.
Note: Can be called anywhere within the frame, both inside and outside of passes.
void QRhiCommandBuffer::debugMarkEnd()
Records the end of a debug group.
Note: Ignored when QRhi::DebugMarkers are not supported or QRhi::EnableDebugMarkers is not set.
Note: Can be called anywhere within the frame, both inside and outside of passes.
void QRhiCommandBuffer::debugMarkMsg(const QByteArray &msg)
Inserts a debug message msg into the command stream.
Note: Ignored when QRhi::DebugMarkers are not supported or QRhi::EnableDebugMarkers is not set.
Note: With some backends debugMarkMsg() is only supported inside a pass and is ignored when called outside a pass. With others it is recorded anywhere within the frame.
void QRhiCommandBuffer::dispatch(int x, int y, int z)
Records dispatching compute work items, with x, y, and z specifying the number of local workgroups in the corresponding dimension.
Note: This function can only be called inside a compute pass, meaning between a beginComputePass() and endComputePass() call.
Note: x, y, and z must fit the limits from the underlying graphics API implementation at run time. The maximum values are typically 65535.
Note: Watch out for possible limits on the local workgroup size as well. This is specified in the shader, for example: layout(local_size_x = 16, local_size_y = 16) in;. For example, with OpenGL the minimum value mandated by the specification for the number of invocations in a single local work group (the product of local_size_x, local_size_y, and local_size_z) is 1024, while with OpenGL ES (3.1) the value may be as low as 128. This means that the example given above may be rejected by some OpenGL ES implementations as the number of invocations is 256.
[since 6.13] void QRhiCommandBuffer::dispatchIndirect(QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset = 0)
Records an indirect compute dispatch.
The work group counts are read by the device from indirectBuffer at indirectBufferOffset, as a single QRhiDispatchIndirectCommand. indirectBuffer must have QRhiBuffer::IndirectBuffer usage and indirectBufferOffset must be 4-byte aligned.
Only one dispatch per call; no native multi-dispatch variant exists. Requires QRhi::DispatchIndirect.
Note: Only valid inside a compute pass.
This function was introduced in Qt 6.13.
void QRhiCommandBuffer::draw(quint32 vertexCount, quint32 instanceCount = 1, quint32 firstVertex = 0, quint32 firstInstance = 0)
Records a non-indexed draw.
The number of vertices is specified in vertexCount. For instanced drawing set instanceCount to a value other than 1. firstVertex is the index of the first vertex to draw. When drawing multiple instances, the first instance ID is specified by firstInstance.
Note: firstInstance may not be supported, and is ignored when the QRhi::BaseInstance feature is reported as not supported. The first instance ID is always 0 in that case. QRhi::BaseInstance is never supported with OpenGL ES, and therefore portable applications should not be designed to rely on this argument.
Note: Shaders that need to access the index of the current vertex or instance must use gl_VertexIndex and gl_InstanceIndex, i.e., the Vulkan-compatible built-in variables, instead of gl_VertexID and gl_InstanceID.
Note: When firstInstance is non-zero, gl_InstanceIndex will not include the base value with some of the underlying 3D APIs. This is indicated by the QRhi::InstanceIndexIncludesBaseInstance feature. If relying on a base instance value cannot be avoided, applications are advised to pass in the value as a uniform conditionally based on what that feature reports, and add it to gl_InstanceIndex in the shader.
Note: This function can only be called inside a render pass, meaning between a beginPass() and endPass() call.
void QRhiCommandBuffer::drawIndexed(quint32 indexCount, quint32 instanceCount = 1, quint32 firstIndex = 0, qint32 vertexOffset = 0, quint32 firstInstance = 0)
Records an indexed draw.
The number of vertices is specified in indexCount. firstIndex is the base index. The effective offset in the index buffer is given by indexOffset + firstIndex * n where n is 2 or 4 depending on the index element type. indexOffset is specified in setVertexInput().
Note: The effective offset in the index buffer must be 4 byte aligned with some backends (for example, Metal). With these backends the NonFourAlignedEffectiveIndexBufferOffset feature will be reported as not-supported.
vertexOffset (also called base vertex) is a signed value that is added to the element index before indexing into the vertex buffer. Support for this is not always available, and the value is ignored when the feature QRhi::BaseVertex is reported as unsupported.
For instanced drawing set instanceCount to a value other than 1. When drawing multiple instances, the first instance ID is specified by firstInstance.
Note: firstInstance may not be supported, and is ignored when the QRhi::BaseInstance feature is reported as not supported. The first instance ID is always 0 in that case. QRhi::BaseInstance is never supported with OpenGL ES, and therefore portable applications should not be designed to rely on this argument.
Note: Shaders that need to access the index of the current vertex or instance must use gl_VertexIndex and gl_InstanceIndex, i.e., the Vulkan-compatible built-in variables, instead of gl_VertexID and gl_InstanceID.
Note: When firstInstance is non-zero, gl_InstanceIndex will not include the base value with some of the underlying 3D APIs. This is indicated by the QRhi::InstanceIndexIncludesBaseInstance feature. If relying on a base instance value cannot be avoided, applications are advised to pass in the value as a uniform conditionally based on what that feature reports, and add it to gl_InstanceIndex in the shader.
Note: This function can only be called inside a render pass, meaning between a beginPass() and endPass() call.
[since 6.12] void QRhiCommandBuffer::drawIndexedIndirect(QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset, quint32 drawCount, quint32 stride = sizeof(QRhiIndexedIndirectDrawCommand))
Records an indexed, indirect draw.
The draw parameters are provided by the buffer specified in indirectBuffer, which must contain an array of elements of type QRhiIndexedIndirectDrawCommand. The parameters in QRhiIndexedIndirectDrawCommand have the same meaning as in drawIndexed().
The offset, in bytes, from which the parameters are read in the buffer is specified by indirectBufferOffset.
drawCount specifies the number of such draw commands to issue.
stride indicates the byte size of each individual draw command structure in the buffer. This allows interleaving custom data between commands if needed. The value must be a multiple of 4 and greater than or equal to sizeof(QRhiIndexedIndirectDrawCommand).
Note: A drawCount value greater than 1 is only natively supported if the QRhi::DrawIndirectMulti feature is reported as supported. Otherwise, this function emulates multi-draw by recording multiple draw calls, offering no performance benefit over repeated drawIndexed() calls.
Note: Leaving stride at its default is recommended whenever performance matters. With Direct 3D 12 a non-default stride prevents issuing a single native multi-draw, forcing the backend to record one command per draw instead. For a large drawCount this can be an order of magnitude slower, which defeats the purpose of the indirect draw. Vulkan, OpenGL, and Metal pass the stride on to their native multi-draw entry points and are not affected. Rather than interleaving custom data between the commands, keep that data in a separate buffer and index into it.
Note: With some backends a large drawCount is implemented by interrupting and then restarting the render pass internally due to launching a compute kernel to encode commands into an indirect command buffer. With Metal this happens above a certain drawCount (e.g., 128). This has consequences for the render targets: color attachment contents are preserved automatically, but a QRhiRenderBuffer serving as the depth-stencil buffer only keeps its contents if it was created with QRhiRenderBuffer::NoTransientBacking, which means that, with Metal, rendering errors may occur if the depth-stencil buffer is a QRhiRenderBuffer without the NoTransientBacking flag and the drawCount is above the threshold. Recording the same commands into a QRhiIndirectCommandBuffer and issuing them with executeIndirect() avoids this altogether: that never interrupts the pass.
Note: Therefore, portable applications should consider always using QRhiIndirectCommandBuffer and executeIndirect() instead of the draw*Indirect*() family of functions.
Note: This function can only be called inside a render pass, meaning between a beginPass() and endPass() call.
This function was introduced in Qt 6.12.
See also drawIndirect(), drawIndirectCount(), and drawIndexedIndirectCount().
[since 6.13] void QRhiCommandBuffer::drawIndexedIndirectCount(QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset, QRhiBuffer *countBuffer, quint32 countBufferOffset, quint32 maxDrawCount, quint32 stride = sizeof(QRhiIndexedIndirectDrawCommand))
Indexed variant of drawIndirectCount(). indirectBuffer contains, at byte offset indirectBufferOffset, QRhiIndexedIndirectDrawCommand entries, spaced stride bytes apart, and stride must be at least sizeof(QRhiIndexedIndirectDrawCommand). All other requirements, including how countBuffer, countBufferOffset and maxDrawCount are interpreted, are as described for drawIndirectCount().
Note: The render pass interruption described for drawIndirectCount() applies here as well.
Note: Therefore, portable applications should consider always using QRhiIndirectCommandBuffer and executeIndirect() instead of the draw*Indirect*() family of functions.
Note: Only valid inside a render pass.
This function was introduced in Qt 6.13.
See also drawIndirect(), drawIndexedIndirect(), and drawIndirectCount().
[since 6.12] void QRhiCommandBuffer::drawIndirect(QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset, quint32 drawCount, quint32 stride = sizeof(QRhiIndirectDrawCommand))
Records a non-indexed, indirect draw.
The draw parameters are provided by the buffer specified in indirectBuffer, which must contain an array of elements of type QRhiIndirectDrawCommand. The parameters in QRhiIndirectDrawCommand have the same meaning as in draw().
The offset, in bytes, from which the parameters are read in the buffer is specified by indirectBufferOffset.
drawCount specifies the number of such draw commands to issue.
stride indicates the byte size of each individual draw command structure in the buffer. This allows interleaving custom data between commands if needed. The value must be a multiple of 4 and greater than or equal to sizeof(QRhiIndirectDrawCommand).
Note: A drawCount value greater than 1 is only natively supported if the QRhi::DrawIndirectMulti feature is reported as supported. Otherwise, this function emulates multi-draw by recording multiple draw calls, offering no performance benefit over repeated draw() calls.
Note: Leaving stride at its default is recommended whenever performance matters. With Direct 3D 12 a non-default stride prevents issuing a single native multi-draw, forcing the backend to record one command per draw instead. For a large drawCount this can be an order of magnitude slower, which defeats the purpose of the indirect draw. Vulkan, OpenGL, and Metal pass the stride on to their native multi-draw entry points and are not affected. Rather than interleaving custom data between the commands, keep that data in a separate buffer and index into it.
Note: The render pass interruption and the render target consequences and limitations described for drawIndexedIndirect() apply here as well.
Note: Therefore, portable applications should consider always using QRhiIndirectCommandBuffer and executeIndirect() instead of the draw*Indirect*() family of functions.
Note: This function can only be called inside a render pass, meaning between a beginPass() and endPass() call.
This function was introduced in Qt 6.12.
See also drawIndexedIndirect(), drawIndirectCount(), and drawIndexedIndirectCount().
[since 6.13] void QRhiCommandBuffer::drawIndirectCount(QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset, QRhiBuffer *countBuffer, quint32 countBufferOffset, quint32 maxDrawCount, quint32 stride = sizeof(QRhiIndirectDrawCommand))
Records a non-indexed, indirect draw, with the draw count itself read from a buffer at execution time.
Draw parameters are read from indirectBuffer at byte offset indirectBufferOffset as an array of QRhiIndirectDrawCommand entries spaced stride bytes apart. The number of draws issued is the 32-bit unsigned integer stored at countBufferOffset in countBuffer, clamped to maxDrawCount.
Both buffers must have QRhiBuffer::IndirectBuffer usage. Offsets must be 4-byte aligned; stride must be 4-byte aligned and at least sizeof(QRhiIndirectDrawCommand).
Only available when QRhi::DrawIndirectCount is reported as supported. On other backends this is a no-op and a warning is logged. With Metal there are additional requirements, see QRhi::DrawIndirectCount.
Note: Unlike with drawIndirect(), a non-default stride does not prevent the use of a single native multi-draw here. With Direct 3D 12 it does mean that an additional command signature is created and cached for each distinct stride value, so sticking to one stride is still preferable.
Note: The value in countBuffer is read as a signed 32-bit integer by OpenGL, unlike the other backends. Counts above INT_MAX are therefore not portable, and neither is relying on any particular behavior for a count that exceeds maxDrawCount, beyond the clamping described above.
Note: With some backends, Metal in particular, the render pass is always interrupted and restarted internally because the draw commands have to be encoded on the GPU. Color attachment contents are preserved automatically, but a QRhiRenderBuffer serving as the depth-stencil buffer only keeps its contents if it was created with QRhiRenderBuffer::NoTransientBacking. Building a QRhiIndirectCommandBuffer with buildIndirect(), which happens before the pass begins, and issuing it with executeIndirect() avoids this: that never interrupts the pass, and supports a device-side count just the same.
Note: Therefore, portable applications should consider always using QRhiIndirectCommandBuffer and executeIndirect() instead of the draw*Indirect*() family of functions.
Note: maxDrawCount is not a free upper bound. With Metal it sizes the indirect command buffer that the draw commands are encoded into, and that buffer is shared, grows on demand, and is never shrunk again for the lifetime of the QRhi. It also determines how many encoding threads are dispatched every time. Passing the capacity of indirectBuffer instead of a realistic upper bound therefore has a real cost.
Note: Only valid inside a render pass.
This function was introduced in Qt 6.13.
See also drawIndirect(), drawIndexedIndirect(), and drawIndexedIndirectCount().
void QRhiCommandBuffer::endComputePass(QRhiResourceUpdateBatch *resourceUpdates = nullptr)
Records ending the current compute pass.
resourceUpdates, when not null, specifies a resource update batch that is to be committed and then released.
void QRhiCommandBuffer::endExternal()
To be called once the externally added commands are recorded to the command buffer or context.
Note: All QRhiCommandBuffer state must be assumed as invalid after calling this function. Pipelines, vertex and index buffers, and other state must be set again if more draw calls are recorded after the external commands.
See also beginExternal() and nativeHandles().
void QRhiCommandBuffer::endPass(QRhiResourceUpdateBatch *resourceUpdates = nullptr)
Records ending the current render pass.
resourceUpdates, when not null, specifies a resource update batch that is to be committed and then released.
See also beginPass().
void QRhiCommandBuffer::executeIndirect(QRhiIndirectCommandBuffer *icb, quint32 firstCommand = 0, quint32 commandCount = 0xFFFFFFFFu)
Records executing the commands held by the indirect command buffer icb, starting at firstCommand and executing at most commandCount of them. By default all commands are executed.
Everything else - the graphics pipeline, the vertex and index buffers, the shader resources, the viewport, the scissor - is taken from the current state of the command buffer, exactly like with drawIndirect().
The number of draws issued is qMin(commandCount, icb->commandCount() - firstCommand), so leaving commandCount at its default executes everything from firstCommand onwards. What QRhiIndirectCommandBuffer::commandCount() means depends on how icb was populated: it is the number of draw() and drawIndexed() calls recorded on it, or, after a buildIndirect(), the count resolved from QRhiIndirectCommandBufferBuildInfo::commandCount. Nothing is drawn when firstCommand is at or past that count.
When icb was populated by recording draw() or drawIndexed() calls on it, the recorded contents must have been flushed with QRhiResourceUpdateBatch::commitIndirectCommandBuffer() beforehand. When it was populated with buildIndirect(), and a count buffer was specified there, the device-side count reduces the number of draws further: the number actually executed is the smallest of that, commandCount, and what is left in icb after firstCommand.
Warning: With a count buffer some backends, Metal in particular, cannot combine the device-side count with a subrange. firstCommand and commandCount are then ignored, printing a warning, and all commands up to the device-side count are executed.
Note: An indirect command buffer that was populated by recording draw() or drawIndexed() calls on it can be executed any number of times, but within one frame all those executions must use the same topology, index buffer, index buffer offset and index format: some backends bake these into their native indirect command buffer at the first executeIndirect() of the frame. A mismatch is reported with a warning, and handled by falling back to ordinary draw calls.
Note: Unlike drawIndirect(), drawIndexedIndirect(), drawIndirectCount() and drawIndexedIndirectCount(), this never causes the render pass to be interrupted and restarted internally, whatever the number of commands. Commands built with buildIndirect() were prepared before the pass began, and CPU-recorded ones need no compute work to encode. The consequences described for those functions therefore do not apply here. Color attachment contents are not at risk, and a QRhiRenderBuffer serving as the depth-stencil buffer keeps its contents without needing QRhiRenderBuffer::NoTransientBacking.
Note: The CPU cost of this call is not constant for a CPU-recorded indirect command buffer. When the recorded contents changed since the last execution, some backends do their per-command native encoding here rather than in QRhiResourceUpdateBatch::commitIndirectCommandBuffer(), which for a large command set re-recorded every frame can dominate the time spent between beginPass() and endPass(). See QRhiIndirectCommandBuffer for how the cost of CPU recording scales.
Note: This function can only be called inside a render pass.
See also buildIndirect(), drawIndirect(), and QRhiIndirectCommandBuffer.
double QRhiCommandBuffer::lastCompletedGpuTime()
Returns the last available timestamp, in seconds, when QRhi::EnableTimestamps was enabled when creating the QRhi. The value indicates the elapsed time on the GPU during the last completed frame.
Note: Do not expect results other than 0 when the QRhi::Timestamps feature is not reported as supported, or when QRhi::EnableTimestamps was not passed to QRhi::create(). There are exceptions to this, because with some graphics APIs (Metal) timings are available without having to perform extra operations (timestamp queries), but portable applications should always consciously opt-in to timestamp collection when they know it is needed, and call this function accordingly.
Care must be exercised with the interpretation of the value, as its precision and granularity is often not controlled by Qt, and depends on the underlying graphics API and its implementation. In particular, comparing the values between different graphics APIs and hardware is discouraged and may be meaningless.
The timing values will likely become available asynchronously. The returned value may therefore be 0 (e.g., for the first 1-2 frames) or the last known value referring to some previous frame. The value my also become 0 again under certain conditions, such as when resizing the window. It can be expected that the most up-to-date available value is retrieved in beginFrame() and becomes queriable via this function once beginFrame() returns.
Note: Do not assume that the value refers to the previous (currently_recorded - 1) frame. It may refer to currently_recorded - 2 or currently_recorded - 3 as well. The exact behavior may depend on the graphics API and its implementation.
Watch out for the consequences of GPU frequency scaling and GPU clock changes, depending on the platform. For example, on Windows the returned timing may vary in a quite wide range between frames with modern graphics cards, even when submitting frames with a similar, or the same workload. This is out of scope for Qt to control and solve, generally speaking. However, the D3D12 backend automatically calls ID3D12Device::SetStablePowerState() whenever the environment variable QT_D3D_STABLE_POWER_STATE is set to a non-zero value. This can greatly stabilize the result. It can also have a non-insignificant effect on the CPU-side timings measured via QElapsedTimer for example, especially when offscreen frames are involved.
Note: Do not and never ship applications to production with QT_D3D_STABLE_POWER_STATE set. See the Windows API documentation for details.
See also QRhi::Timestamps and QRhi::EnableTimestamps.
const QRhiNativeHandles *QRhiCommandBuffer::nativeHandles()
Returns a pointer to a backend-specific QRhiNativeHandles subclass, such as QRhiVulkanCommandBufferNativeHandles. The returned value is nullptr when exposing the underlying native resources is not supported by, or not applicable to, the backend.
See also QRhiVulkanCommandBufferNativeHandles, QRhiMetalCommandBufferNativeHandles, beginExternal(), and endExternal().
[override virtual] QRhiResource::Type QRhiCommandBuffer::resourceType() const
Reimplements: QRhiResource::resourceType() const.
Returns the resource type.
void QRhiCommandBuffer::resourceUpdate(QRhiResourceUpdateBatch *resourceUpdates)
Sometimes committing resource updates is necessary or just more convenient without starting a render pass. Calling this function with resourceUpdates is an alternative to passing resourceUpdates to a beginPass() call (or endPass(), which would be typical in case of readbacks).
Note: Cannot be called inside a pass.
void QRhiCommandBuffer::setBlendConstants(const QColor &c)
Records setting the active blend constants to c.
This can only be called when the bound pipeline has QRhiGraphicsPipeline::UsesBlendConstants set.
Note: This function can only be called inside a render pass, meaning between a beginPass() and endPass() call.
void QRhiCommandBuffer::setComputePipeline(QRhiComputePipeline *ps)
Records setting a new compute pipeline ps.
Note: This function must be called before recording setShaderResources() or dispatch() commands on the command buffer.
Note: QRhi will optimize out unnecessary invocations within a pass, so therefore overoptimizing to avoid calls to this function is not necessary on the applications' side.
Note: This function can only be called inside a compute pass, meaning between a beginComputePass() and endComputePass() call.
void QRhiCommandBuffer::setGraphicsPipeline(QRhiGraphicsPipeline *ps)
Records setting a new graphics pipeline ps.
Note: This function must be called before recording other set or draw commands on the command buffer.
Note: QRhi will optimize out unnecessary invocations within a pass, so therefore overoptimizing to avoid calls to this function is not necessary on the applications' side.
Note: This function can only be called inside a render pass, meaning between a beginPass() and endPass() call.
Note: The new graphics pipeline ps must be a valid pointer.
Setting a graphics pipeline that does not have the UsesScissor flag will either disable scissoring, with graphics APIs where that is applicable, or set the scissor rectangle to match the viewport that was last set (with graphics APIs where scissoring is effectively always active), in order to ensure a uniform behavior across QRhi backends.
void QRhiCommandBuffer::setScissor(const QRhiScissor &scissor)
Records setting the active scissor rectangle specified in scissor.
This can only be called when the bound pipeline has UsesScissor set. When the flag is set on the active pipeline, this function must be called because scissor testing will get enabled and so a scissor rectangle must be provided.
Note: QRhi assumes OpenGL-style viewport coordinates, meaning x and y are bottom-left.
Note: This function can only be called inside a render pass, meaning between a beginPass() and endPass() call.
void QRhiCommandBuffer::setShaderResources(QRhiShaderResourceBindings *srb = nullptr, int dynamicOffsetCount = 0, const QRhiCommandBuffer::DynamicOffset *dynamicOffsets = nullptr)
Records binding a set of shader resources, such as, uniform buffers or textures, that are made visible to one or more shader stages.
srb can be null in which case the current graphics or compute pipeline's associated QRhiShaderResourceBindings is used. When srb is non-null, it must be layout-compatible, meaning the layout (number of bindings, the type and binding number of each binding) must fully match the QRhiShaderResourceBindings that was associated with the pipeline at the time of calling the pipeline's create().
There are cases when a seemingly unnecessary setShaderResources() call is mandatory: when rebuilding a resource referenced from srb, for example changing the size of a QRhiBuffer followed by a QRhiBuffer::create(), this is the place where associated native objects (such as descriptor sets in case of Vulkan) are updated to refer to the current native resources that back the QRhiBuffer, QRhiTexture, QRhiSampler objects referenced from srb. In this case setShaderResources() must be called even if srb is the same as in the last call.
When srb is not null, the QRhiShaderResourceBindings object the pipeline was built with in create() is guaranteed to be not accessed in any form. In fact, it does not need to be valid even at this point: destroying the pipeline's associated srb after create() and instead explicitly specifying another, layout compatible one in every setShaderResources() call is valid.
dynamicOffsets allows specifying buffer offsets for uniform buffers that were associated with srb via QRhiShaderResourceBinding::uniformBufferWithDynamicOffset(). This is different from providing the offset in the srb itself: dynamic offsets do not require building a new QRhiShaderResourceBindings for every different offset, can avoid writing the underlying descriptors (with backends where applicable), and so they may be more efficient. Each element of dynamicOffsets is a binding - offset pair. dynamicOffsetCount specifies the number of elements in dynamicOffsets.
Note: All offsets in dynamicOffsets must be byte aligned to the value returned from QRhi::ubufAlignment().
Note: Some backends may limit the number of supported dynamic offsets. Avoid using a dynamicOffsetCount larger than 8.
Note: QRhi will optimize out unnecessary invocations within a pass (taking the conditions described above into account), so therefore overoptimizing to avoid calls to this function is not necessary on the applications' side.
Note: This function can only be called inside a render or compute pass, meaning between a beginPass() and endPass(), or beginComputePass() and endComputePass().
[since 6.9] void QRhiCommandBuffer::setShadingRate(const QSize &coarsePixelSize)
Sets the shading rate for the following draw calls to coarsePixelSize.
The default is 1x1.
Functional only when the QRhi::VariableRateShading feature is reported as supported and the QRhiGraphicsPipeline(s) bound on the command buffer were declaring QRhiGraphicsPipeline::UsesShadingRate when creating them.
Call QRhi::supportedShadingRates() to check what shading rates are supported for a given sample count.
When both a QRhiShadingRateMap and this function are in use, the higher of the two shading rates is used for each tile. There is currently no control offered over the combiner behavior.
This function was introduced in Qt 6.9.
void QRhiCommandBuffer::setStencilRef(quint32 refValue)
Records setting the active stencil reference value to refValue.
This can only be called when the bound pipeline has QRhiGraphicsPipeline::UsesStencilRef set.
Note: This function can only be called inside a render pass, meaning between a beginPass() and endPass() call.
void QRhiCommandBuffer::setVertexInput(int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings, QRhiBuffer *indexBuf = nullptr, quint32 indexOffset = 0, QRhiCommandBuffer::IndexFormat indexFormat = IndexUInt16)
Records vertex input bindings.
The index buffer used by subsequent drawIndexed() commands is specified by indexBuf, indexOffset, and indexFormat. indexBuf can be set to null when indexed drawing is not needed.
Vertex buffer bindings are batched. startBinding specifies the first binding number. The recorded command then binds each buffer from bindings to the binding point startBinding + i where i is the index in bindings. Each element in bindings specifies a QRhiBuffer and an offset.
Note: Some backends may limit the number of vertex buffer bindings. Avoid using a bindingCount larger than 8.
Superfluous vertex input and index changes in the same pass are ignored automatically with most backends and therefore applications do not need to overoptimize to avoid calls to this function.
Note: This function can only be called inside a render pass, meaning between a beginPass() and endPass() call.
As a simple example, take a vertex shader with two inputs:
layout(location = 0) in vec4 position;
layout(location = 1) in vec3 color;and assume we have the data available in interleaved format, using only 2 floats for position (so 5 floats per vertex: x, y, r, g, b). A QRhiGraphicsPipeline for this shader can then be created using the input layout:
QRhiVertexInputLayout inputLayout;
inputLayout.setBindings({
{ 5 * sizeof(float) }
});
inputLayout.setAttributes({
{ 0, 0, QRhiVertexInputAttribute::Float2, 0 },
{ 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) }
});Here there is one buffer binding (binding number 0), with two inputs referencing it. When recording the pass, once the pipeline is set, the vertex bindings can be specified simply like the following, assuming vbuf is the QRhiBuffer with all the interleaved position+color data:
const QRhiCommandBuffer::VertexInput vbufBinding(vbuf, 0);
cb->setVertexInput(0, 1, &vbufBinding);void QRhiCommandBuffer::setViewport(const QRhiViewport &viewport)
Records setting the active viewport rectangle specified in viewport.
With backends where the underlying graphics API has scissoring always enabled, this function also sets the scissor to match the viewport whenever the active QRhiGraphicsPipeline does not have UsesScissor set.
Note: QRhi assumes OpenGL-style viewport coordinates, meaning x and y are bottom-left.
© 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.