Skip to content

KDGpu::RenderPassCommandRecorder

Module: Public API

Records rendering commands within a render pass. More...

#include <KDGpu/render_pass_command_recorder.h>

Public Functions

Name
~RenderPassCommandRecorder()
RenderPassCommandRecorder(RenderPassCommandRecorder && other)
RenderPassCommandRecorder & operator=(RenderPassCommandRecorder && other)
RenderPassCommandRecorder(const RenderPassCommandRecorder & ) =delete
RenderPassCommandRecorder & operator=(const RenderPassCommandRecorder & ) =delete
const Handle< RenderPassCommandRecorder_t > & handle() const
bool isValid() const
operator Handle< RenderPassCommandRecorder_t >() const
void setPipeline(const RequiredHandle< GraphicsPipeline_t > & pipeline)
Binds a graphics pipeline for subsequent draw commands.
void setVertexBuffer(uint32_t index, const RequiredHandle< Buffer_t > & buffer, DeviceSize offset =0)
Binds a vertex buffer to a binding index.
void setIndexBuffer(const RequiredHandle< Buffer_t > & buffer, DeviceSize offset =0, IndexType indexType =IndexType::Uint32)
Binds an index buffer for indexed draw commands.
void setBindGroup(uint32_t group, const RequiredHandle< BindGroup_t > & bindGroup, const OptionalHandle< PipelineLayout_t > & pipelineLayout =Handle< PipelineLayout_t >(), std::span< const uint32_t > dynamicBufferOffsets ={})
Binds a descriptor set (bind group) for shader resource access.
void setViewport(const Viewport & viewport)
Sets the viewport transformation.
void setScissor(const Rect2D & scissor)
Sets the scissor rectangle for fragment clipping.
void setStencilReference(StencilFaceFlags faceMask, int reference)
Sets the stencil reference value for stencil testing.
void draw(const DrawCommand & drawCommand)
Draws non-indexed geometry.
void draw(std::span< const DrawCommand > drawCommands)
Draws multiple non-indexed primitives in a single call.
void drawIndexed(const DrawIndexedCommand & drawCommand)
Draws indexed geometry.
void drawIndexed(std::span< const DrawIndexedCommand > drawCommands)
Draws multiple indexed primitives in a single call.
void drawIndirect(const DrawIndirectCommand & drawCommand)
Draws geometry with parameters in a GPU buffer (indirect rendering)
void drawIndirect(std::span< const DrawIndirectCommand > drawCommands)
void drawIndexedIndirect(const DrawIndexedIndirectCommand & drawCommand)
Draws indexed geometry with parameters in a GPU buffer.
void drawIndexedIndirect(std::span< const DrawIndexedIndirectCommand > drawCommands)
void drawMeshTasks(const DrawMeshCommand & drawCommand)
Dispatches mesh shader work groups.
void drawMeshTasks(std::span< const DrawMeshCommand > drawCommands)
void drawMeshTasksIndirect(const DrawMeshIndirectCommand & drawCommand)
Dispatches mesh shader work groups with GPU-driven parameters.
void drawMeshTasksIndirect(std::span< const DrawMeshIndirectCommand > drawCommands)
void pushConstant(const PushConstantRange & constantRange, const void * data, const OptionalHandle< PipelineLayout_t > & pipelineLayout ={})
Uploads small data directly to shaders without buffers.
void pushBindGroup(uint32_t group, std::span< const BindGroupEntry > bindGroupEntries, const Handle< PipelineLayout_t > & pipelineLayout =Handle< PipelineLayout_t >())
Dynamically creates and binds a temporary descriptor set.
void nextSubpass()
Advances to the next subpass (legacy render passes only)
void setInputAttachmentMapping(std::span< const std::optional< uint32_t > > colorAttachmentIndices, std::optional< uint32_t > depthAttachmentIndex, std::optional< uint32_t > stencilAttachmentIndex)
Remaps render target attachments to shader input attachment indices (e.g RenderTarget Color[0] -> Input[2])
void setOutputAttachmentMapping(std::span< const std::optional< uint32_t > > remappedOutputs)
Remaps fragment shader outputs to attachment indices (e.g RenderTarget Color[0] -> Output[2])
void end()
Ends the render pass and finalizes recorded commands.

Friends

Name
class CommandRecorder

Detailed Description

1
class KDGpu::RenderPassCommandRecorder;

Records rendering commands within a render pass.

RenderPassCommandRecorder is used to record GPU drawing commands that render to one or more attachments (textures). It cannot be created directly: instances are obtained by calling CommandRecorder::beginRenderPass() with appropriate options.

Overview

A render pass defines:

  • Color attachments (render targets)
  • Optional depth/stencil attachment
  • Load/store operations for each attachment
  • MSAA configuration and resolve targets
  • Multi-view configuration for VR/stereo rendering

Creation

RenderPassCommandRecorder cannot be instantiated directly. It must be created via CommandRecorder::beginRenderPass() using one of three option structs:

The legacy VkRenderPass/VkFramebuffer model (via RenderPassCommandRecorderOptions or RenderPassCommandRecorderWithRenderPassOptions) has been marked as deprecated in Vulkan 1.3 in favor of dynamic rendering. On desktop platforms, new code should use RenderPassCommandRecorderWithDynamicRenderingOptions.

Usage

Basic usage:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
        // Using dynamic rendering (modern approach, promoted to Vulkan 1.3 core)
        KDGpu::RenderPassCommandRecorderWithDynamicRenderingOptions renderOptions{
            // Configure color attachment (e.g., swapchain image)
            .colorAttachments = {
                    KDGpu::ColorAttachment{
                            .view = colorView.handle(),
                            .loadOperation = KDGpu::AttachmentLoadOperation::Clear,
                            .storeOperation = KDGpu::AttachmentStoreOperation::Store,
                            .clearValue = { 0.1f, 0.2f, 0.3f, 1.0f }, // Clear to dark blue
                            .initialLayout = KDGpu::TextureLayout::Undefined,
                            .layout = KDGpu::TextureLayout::ColorAttachmentOptimal,
                            .finalLayout = KDGpu::TextureLayout::PresentSrc,
                    },
            },
            // Configure depth attachment
            .depthStencilAttachment = KDGpu::DepthStencilAttachment{
                    .view = depthView,
                    .depthLoadOperation = KDGpu::AttachmentLoadOperation::Clear,
                    .depthStoreOperation = KDGpu::AttachmentStoreOperation::DontCare,
                    .depthClearValue = 1.0f,
                    .initialLayout = KDGpu::TextureLayout::Undefined,
                    .layout = KDGpu::TextureLayout::DepthStencilAttachmentOptimal,
            },
        };

        // Begin render pass
        auto renderPass = commandRecorder->beginRenderPass(renderOptions);

        // Record rendering commands...
        renderPass.setPipeline(pipeline);
        renderPass.setVertexBuffer(0, vertexBuffer);
        renderPass.setIndexBuffer(indexBuffer);
        renderPass.setBindGroup(0, bindGroup);
        renderPass.drawIndexed({ .indexCount = 36 });

        // End the render pass
        renderPass.end();

Filename: kdgpu_doc_snippets.cpp

Dynamic Pipeline State:

Before drawing, you can configure the dynamic states of the pipeline:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
        auto renderPass = commandRecorder->beginRenderPass(renderOptions);

        // Set dynamic viewport
        KDGpu::Viewport viewport{
            .x = 0.0f,
            .y = 0.0f,
            .width = 1920.0f,
            .height = 1080.0f,
            .minDepth = 0.0f,
            .maxDepth = 1.0f,
        };
        renderPass.setViewport(viewport);

        // Set scissor rectangle (can be smaller than viewport for clipping)
        KDGpu::Rect2D scissor{
            .offset = { 100, 100 },
            .extent = { 800, 600 },
        };
        renderPass.setScissor(scissor);

        renderPass.end();

Filename: kdgpu_doc_snippets.cpp

Drawing:

Multiple draw command variants are available:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
        auto renderPass = commandRecorder->beginRenderPass(renderOptions);
        renderPass.setPipeline(pipeline);

        // Simple draw (non-indexed)
        KDGpu::DrawCommand drawCmd{
            .vertexCount = 3, // 3 vertices for a triangle
            .instanceCount = 1,
            .firstVertex = 0,
            .firstInstance = 0,
        };
        renderPass.draw(drawCmd);

        // Indexed draw (most common)
        KDGpu::DrawIndexedCommand indexedCmd{
            .indexCount = 36, // 36 indices for a cube
            .instanceCount = 1,
            .firstIndex = 0,
            .vertexOffset = 0,
            .firstInstance = 0,
        };
        renderPass.drawIndexed(indexedCmd);

        // Instanced rendering
        KDGpu::DrawIndexedCommand instancedCmd{
            .indexCount = 36,
            .instanceCount = 100, // Draw 100 instances
            .firstIndex = 0,
            .vertexOffset = 0,
            .firstInstance = 0,
        };
        renderPass.drawIndexed(instancedCmd);

        renderPass.end();

Filename: kdgpu_doc_snippets.cpp

Push Constants:

Small amounts of data can be uploaded efficiently via push constants:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
        auto renderPass = commandRecorder->beginRenderPass(renderOptions);
        renderPass.setPipeline(pipeline);

        // Upload small amounts of data directly to shaders (faster than UBO for small data)
        struct PushConstants {
            glm::mat4 transform;
            glm::vec4 color;
        } pushData;

        pushData.transform = glm::mat4(1.0f);
        pushData.color = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f);

        KDGpu::PushConstantRange range{
            .offset = 0,
            .size = sizeof(PushConstants),
            .shaderStages = KDGpu::ShaderStageFlagBits::VertexBit | KDGpu::ShaderStageFlagBits::FragmentBit,
        };

        renderPass.pushConstant(range, &pushData);
        renderPass.drawIndexed({ .indexCount = 36 });

        renderPass.end();

Filename: kdgpu_doc_snippets.cpp

Advanced Features

Multiple Render Targets (MRT):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
        // Multiple render targets (MRT) for deferred rendering
        KDGpu::RenderPassCommandRecorderWithDynamicRenderingOptions mrtOptions{
            .colorAttachments = {
                    // Attachment 0: Albedo/diffuse color
                    KDGpu::ColorAttachment{
                            .view = colorView,
                            .loadOperation = KDGpu::AttachmentLoadOperation::Clear,
                            .storeOperation = KDGpu::AttachmentStoreOperation::Store,
                    },

                    // Attachment 1: Normals
                    KDGpu::ColorAttachment{
                            .view = colorView,
                            .loadOperation = KDGpu::AttachmentLoadOperation::Clear,
                            .storeOperation = KDGpu::AttachmentStoreOperation::Store,
                    },

                    // Attachment 2: Material properties (roughness, metallic, etc.)
                    KDGpu::ColorAttachment{
                            .view = colorView,
                            .loadOperation = KDGpu::AttachmentLoadOperation::Clear,
                            .storeOperation = KDGpu::AttachmentStoreOperation::Store,
                    },
            },
        };

        auto mrtRenderPass = commandRecorder->beginRenderPass(mrtOptions);
        // Fragment shader outputs to multiple render targets
        mrtRenderPass.end();

Filename: kdgpu_doc_snippets.cpp

Load Operations:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
        KDGpu::RenderPassCommandRecorderWithDynamicRenderingOptions loadOptions{};

        KDGpu::ColorAttachment attachment{
            .view = colorView,
            // Clear: Discard previous contents, initialize with clearValue
            // Use when you'll draw to the entire attachment
            .loadOperation = KDGpu::AttachmentLoadOperation::Clear,
            .initialLayout = KDGpu::TextureLayout::Undefined, // Don't care about previous contents
        };

        // Load: Preserve previous contents
        // Use for incremental rendering or UI overlays
        // attachment.loadOperation = KDGpu::AttachmentLoadOperation::Load;
        // attachment.initialLayout = KDGpu::TextureLayout::ColorAttachmentOptimal; // Must match actual layout

        // DontCare: Undefined behavior but may be faster
        // Use when you know you'll overwrite all pixels
        // attachment.loadOperation = KDGpu::AttachmentLoadOperation::DontCare;
        // attachment.initialLayout = KDGpu::TextureLayout::Undefined;

        loadOptions.colorAttachments.push_back(attachment);

Filename: kdgpu_doc_snippets.cpp

Stencil Operations:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
        auto renderPass = commandRecorder->beginRenderPass(renderOptions);
        renderPass.setPipeline(pipeline.handle());

        // Set stencil reference value dynamically (for stencil masking/testing)
        renderPass.setStencilReference(
                KDGpu::StencilFaceFlags(KDGpu::StencilFaceFlagBits::FrontAndBack),
                42 // Reference value
        );

        renderPass.end();

Filename: kdgpu_doc_snippets.cpp

Lifecycle

  1. Create via CommandRecorder::beginRenderPass()
  2. Set pipeline state (pipeline, vertex buffers, bind groups, viewport, etc.)
  3. Issue draw commands
  4. Call end() to finish the render pass
  5. The RenderPassCommandRecorder is no longer valid after end()

Vulkan mapping:

See also:

CommandRecorder, RenderPassCommandRecorderWithDynamicRenderingOptions, RenderPassCommandRecorderOptions, RenderPassCommandRecorderWithRenderPassOptions

ColorAttachment, DepthStencilAttachment, GraphicsPipeline

Public Functions Documentation

function ~RenderPassCommandRecorder

1
~RenderPassCommandRecorder()

function RenderPassCommandRecorder

1
2
3
RenderPassCommandRecorder(
    RenderPassCommandRecorder && other
)

function operator=

1
2
3
RenderPassCommandRecorder & operator=(
    RenderPassCommandRecorder && other
)

function RenderPassCommandRecorder

1
2
3
RenderPassCommandRecorder(
    const RenderPassCommandRecorder & 
) =delete

function operator=

1
2
3
RenderPassCommandRecorder & operator=(
    const RenderPassCommandRecorder & 
) =delete

function handle

1
inline const Handle< RenderPassCommandRecorder_t > & handle() const

function isValid

1
inline bool isValid() const

function operator Handle< RenderPassCommandRecorder_t >

1
inline operator Handle< RenderPassCommandRecorder_t >() const

function setPipeline

1
2
3
void setPipeline(
    const RequiredHandle< GraphicsPipeline_t > & pipeline
)

Binds a graphics pipeline for subsequent draw commands.

Parameters:

  • pipeline The graphics pipeline to bind

All subsequent draw commands will use this pipeline's shaders, blend state, depth/stencil state, etc. Must be called before drawing.

Vulkan: vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS)

function setVertexBuffer

1
2
3
4
5
void setVertexBuffer(
    uint32_t index,
    const RequiredHandle< Buffer_t > & buffer,
    DeviceSize offset =0
)

Binds a vertex buffer to a binding index.

Parameters:

  • index Vertex buffer binding index (must match vertex input in pipeline)
  • buffer The vertex buffer to bind
  • offset Byte offset into the buffer (default 0)

Subsequent draw commands will read vertex data from this buffer.

Vulkan: vkCmdBindVertexBuffers()

function setIndexBuffer

1
2
3
4
5
void setIndexBuffer(
    const RequiredHandle< Buffer_t > & buffer,
    DeviceSize offset =0,
    IndexType indexType =IndexType::Uint32
)

Binds an index buffer for indexed draw commands.

Parameters:

  • buffer The index buffer to bind
  • offset Byte offset into the buffer (default 0)
  • indexType Index format: Uint16 or Uint32 (default Uint32)

Required for drawIndexed() and drawIndexedIndirect() commands.

Vulkan: vkCmdBindIndexBuffer()

function setBindGroup

1
2
3
4
5
6
void setBindGroup(
    uint32_t group,
    const RequiredHandle< BindGroup_t > & bindGroup,
    const OptionalHandle< PipelineLayout_t > & pipelineLayout =Handle< PipelineLayout_t >(),
    std::span< const uint32_t > dynamicBufferOffsets ={}
)

Binds a descriptor set (bind group) for shader resource access.

Parameters:

  • group Binding index (must match layout in pipeline)
  • bindGroup The bind group containing resources (textures, buffers, samplers)
  • pipelineLayout Optional pipeline layout (can be inferred from pipeline if omitted)
  • dynamicBufferOffsets Offsets for dynamic uniform/storage buffers

Shaders access resources through bind groups. Each bind group corresponds to a set in GLSL/HLSL shader code.

Vulkan: vkCmdBindDescriptorSets()

function setViewport

1
2
3
void setViewport(
    const Viewport & viewport
)

Sets the viewport transformation.

Parameters:

  • viewport Viewport rectangle and depth range

Transforms normalized device coordinates to framebuffer coordinates. Can be set dynamically if the pipeline was created with dynamic viewport state.

Vulkan: vkCmdSetViewport()

function setScissor

1
2
3
void setScissor(
    const Rect2D & scissor
)

Sets the scissor rectangle for fragment clipping.

Parameters:

  • scissor Scissor rectangle in framebuffer coordinates

Fragments outside the scissor rectangle are discarded. Useful for UI clipping or rendering to sub-regions.

Vulkan: vkCmdSetScissor()

function setStencilReference

1
2
3
4
void setStencilReference(
    StencilFaceFlags faceMask,
    int reference
)

Sets the stencil reference value for stencil testing.

Parameters:

  • faceMask Which faces to update (Front, Back, or FrontAndBack)
  • reference The stencil reference value (0-255)

Used with stencil operations for masking and stencil-based effects.

Vulkan: vkCmdSetStencilReference()

function draw

1
2
3
void draw(
    const DrawCommand & drawCommand
)

Draws non-indexed geometry.

Parameters:

  • drawCommand Draw parameters (vertex count, instance count, etc.)

Draws vertices directly from vertex buffers without an index buffer.

Vulkan: vkCmdDraw()

function draw

1
2
3
void draw(
    std::span< const DrawCommand > drawCommands
)

Draws multiple non-indexed primitives in a single call.

Parameters:

  • drawCommands Array of draw commands to execute

More efficient than issuing multiple draw() calls separately.

Vulkan: Multiple vkCmdDraw() calls

function drawIndexed

1
2
3
void drawIndexed(
    const DrawIndexedCommand & drawCommand
)

Draws indexed geometry.

Parameters:

  • drawCommand Draw parameters (index count, instance count, etc.)

Most commonly used draw command. Reads indices from the bound index buffer which reference vertices in vertex buffers.

Vulkan: vkCmdDrawIndexed()

function drawIndexed

1
2
3
void drawIndexed(
    std::span< const DrawIndexedCommand > drawCommands
)

Draws multiple indexed primitives in a single call.

Parameters:

  • drawCommands Array of indexed draw commands

Vulkan: Multiple vkCmdDrawIndexed() calls

function drawIndirect

1
2
3
void drawIndirect(
    const DrawIndirectCommand & drawCommand
)

Draws geometry with parameters in a GPU buffer (indirect rendering)

Parameters:

  • drawCommand Indirect draw parameters

Draw parameters are read from a GPU buffer, enabling GPU-driven rendering.

Vulkan: vkCmdDrawIndirect()

function drawIndirect

1
2
3
void drawIndirect(
    std::span< const DrawIndirectCommand > drawCommands
)

function drawIndexedIndirect

1
2
3
void drawIndexedIndirect(
    const DrawIndexedIndirectCommand & drawCommand
)

Draws indexed geometry with parameters in a GPU buffer.

Parameters:

  • drawCommand Indirect indexed draw parameters

Vulkan: vkCmdDrawIndexedIndirect()

function drawIndexedIndirect

1
2
3
void drawIndexedIndirect(
    std::span< const DrawIndexedIndirectCommand > drawCommands
)

function drawMeshTasks

1
2
3
void drawMeshTasks(
    const DrawMeshCommand & drawCommand
)

Dispatches mesh shader work groups.

Parameters:

  • drawCommand Mesh shader dispatch parameters

Requires mesh shading pipeline and VK_EXT_mesh_shader support. Mesh shaders replace the traditional vertex/geometry shader stages.

Vulkan: vkCmdDrawMeshTasksEXT()

function drawMeshTasks

1
2
3
void drawMeshTasks(
    std::span< const DrawMeshCommand > drawCommands
)

function drawMeshTasksIndirect

1
2
3
void drawMeshTasksIndirect(
    const DrawMeshIndirectCommand & drawCommand
)

Dispatches mesh shader work groups with GPU-driven parameters.

Parameters:

  • drawCommand Indirect mesh shader dispatch

Vulkan: vkCmdDrawMeshTasksIndirectEXT()

function drawMeshTasksIndirect

1
2
3
void drawMeshTasksIndirect(
    std::span< const DrawMeshIndirectCommand > drawCommands
)

function pushConstant

1
2
3
4
5
void pushConstant(
    const PushConstantRange & constantRange,
    const void * data,
    const OptionalHandle< PipelineLayout_t > & pipelineLayout ={}
)

Uploads small data directly to shaders without buffers.

Parameters:

  • constantRange Push constant range (offset, size, shader stages)
  • data Pointer to data to upload
  • pipelineLayout Optional pipeline layout

Push constants provide fast access to small amounts of frequently-updated data (typically up to 128 bytes). Much faster than updating uniform buffers.

Vulkan: vkCmdPushConstants()

function pushBindGroup

1
2
3
4
5
void pushBindGroup(
    uint32_t group,
    std::span< const BindGroupEntry > bindGroupEntries,
    const Handle< PipelineLayout_t > & pipelineLayout =Handle< PipelineLayout_t >()
)

Dynamically creates and binds a temporary descriptor set.

Parameters:

  • group Binding index
  • bindGroupEntries Resources to bind
  • pipelineLayout Pipeline layout

Convenience function for binding resources without pre-creating a BindGroup.

Vulkan: vkCmdPushDescriptorSetKHR() (requires VK_KHR_push_descriptor)

function nextSubpass

1
void nextSubpass()

Advances to the next subpass (legacy render passes only)

Deprecated:

Subpasses are part of the legacy VkRenderPass model

Only valid when using RenderPassCommandRecorderWithRenderPassOptions. Not applicable to dynamic rendering.

Vulkan: vkCmdNextSubpass()

function setInputAttachmentMapping

1
2
3
4
5
void setInputAttachmentMapping(
    std::span< const std::optional< uint32_t > > colorAttachmentIndices,
    std::optional< uint32_t > depthAttachmentIndex,
    std::optional< uint32_t > stencilAttachmentIndex
)

Remaps render target attachments to shader input attachment indices (e.g RenderTarget Color[0] -> Input[2])

Parameters:

  • colorAttachmentIndices Color attachment remapping
  • depthAttachmentIndex Depth attachment remapping
  • stencilAttachmentIndex Stencil attachment remapping

Advanced feature for reading from render targets as input attachments. Used for tile-based deferred rendering on mobile GPUs.

function setOutputAttachmentMapping

1
2
3
void setOutputAttachmentMapping(
    std::span< const std::optional< uint32_t > > remappedOutputs
)

Remaps fragment shader outputs to attachment indices (e.g RenderTarget Color[0] -> Output[2])

Parameters:

  • remappedOutputs Output index remapping

Advanced feature for custom attachment output ordering.

function end

1
void end()

Ends the render pass and finalizes recorded commands.

Must be called to finish the render pass. After calling end(), this RenderPassCommandRecorder is no longer valid and should not be used.

Vulkan: vkCmdEndRendering() or vkCmdEndRenderPass()

Friends

friend CommandRecorder

1
2
3
friend class CommandRecorder(
    CommandRecorder 
);

Updated on 2026-03-31 at 00:02:07 +0000