Skip to content

KDGpu::DynamicRenderPassCommandRecorder

Module: Public API

Records rendering commands using modern dynamic rendering (Vulkan 1.3 core) More...

#include <KDGpu/dynamic_render_pass_command_recorder.h>

Inherits from KDGpu::RenderPassCommandRecorderBase

Public Functions

Name
~DynamicRenderPassCommandRecorder()
DynamicRenderPassCommandRecorder(DynamicRenderPassCommandRecorder && other)
DynamicRenderPassCommandRecorder & operator=(DynamicRenderPassCommandRecorder && other)
DynamicRenderPassCommandRecorder(const DynamicRenderPassCommandRecorder & ) =delete
DynamicRenderPassCommandRecorder & operator=(const DynamicRenderPassCommandRecorder & ) =delete
const Handle< DynamicRenderPassCommandRecorder_t > & handle() const
bool isValid() const
operator Handle< DynamicRenderPassCommandRecorder_t >() const
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])

Friends

Name
class CommandRecorder

Additional inherited members

Public Functions inherited from KDGpu::RenderPassCommandRecorderBase

Name
virtual ~RenderPassCommandRecorderBase() =default
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 end()
Ends the render pass and finalizes recorded commands.

Protected Functions inherited from KDGpu::RenderPassCommandRecorderBase

Name
RenderPassCommandRecorderBase() =default
RenderPassCommandRecorderBase(GraphicsApi * api, const Handle< Device_t > & device)

Protected Attributes inherited from KDGpu::RenderPassCommandRecorderBase

Name
GraphicsApi * m_api
Handle< Device_t > m_device

Detailed Description

1
class KDGpu::DynamicRenderPassCommandRecorder;

Records rendering commands using modern dynamic rendering (Vulkan 1.3 core)

DynamicRenderPassCommandRecorder is the recommended modern API for recording GPU drawing commands that render to one or more attachments (textures). It uses VK_KHR_dynamic_rendering which was promoted to Vulkan 1.3 core.

It cannot be created directly: instances are obtained by calling CommandRecorder::beginRenderPass() with RenderPassCommandRecorderWithDynamicRenderingOptions.

Overview

Dynamic rendering allows you to specify render targets directly when beginning a render pass, without pre-creating VkRenderPass and VkFramebuffer objects. This approach offers:

  • Simpler API: No need to create RenderPass objects upfront
  • More flexible: Easily change attachments between frames
  • Better performance: Eliminates RenderPass compatibility checks
  • Modern standard: Vulkan 1.3 core feature

Creation

DynamicRenderPassCommandRecorder cannot be instantiated directly. It must be created via CommandRecorder::beginRenderPass() using 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
        KDGpu::DynamicRenderPassCommandRecorder 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
        KDGpu::DynamicRenderPassCommandRecorder 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
        KDGpu::DynamicRenderPassCommandRecorder 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
        KDGpu::DynamicRenderPassCommandRecorder 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,
                    },
            },
        };

        KDGpu::DynamicRenderPassCommandRecorder 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

MSAA with Automatic Resolve:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
        // Multi-sample anti-aliasing with automatic resolve

        KDGpu::RenderPassCommandRecorderWithDynamicRenderingOptions msaaOptions{
            .colorAttachments = {
                    KDGpu::ColorAttachment{
                            .view = msaaColorView, // MSAA texture view
                            .resolveView = colorView, // Single-sample texture to resolve to
                            .loadOperation = KDGpu::AttachmentLoadOperation::Clear,
                            .storeOperation = KDGpu::AttachmentStoreOperation::DontCare, // MSAA buffer not needed after resolve
                            .clearValue = { 0.0f, 0.0f, 0.0f, 1.0f },
                    },
            },
            .samples = KDGpu::SampleCountFlagBits::Samples4Bit,
        };

        KDGpu::DynamicRenderPassCommandRecorder msaaRenderPass = commandRecorder->beginRenderPass(msaaOptions);
        // Render with MSAA...
        msaaRenderPass.end();

Filename: kdgpu_doc_snippets.cpp

Multi-View Rendering:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
        // Multi-view rendering for VR/stereo (renders to both eyes in a single pass)
        KDGpu::RenderPassCommandRecorderWithDynamicRenderingOptions multiviewOptions{
            .colorAttachments = {
                    KDGpu::ColorAttachment{
                            .view = arrayColorView, // Array texture with 2 layers
                            .loadOperation = KDGpu::AttachmentLoadOperation::Clear,
                            .storeOperation = KDGpu::AttachmentStoreOperation::Store,
                    },
            },
            .viewCount = 2, // Render to 2 views simultaneously
        };

        KDGpu::DynamicRenderPassCommandRecorder multiviewRenderPass = commandRecorder->beginRenderPass(multiviewOptions);
        // The vertex shader will run once per view using gl_ViewIndex
        multiviewRenderPass.end();

Filename: kdgpu_doc_snippets.cpp

Lifecycle

  1. Create via CommandRecorder::beginRenderPass() with RenderPassCommandRecorderWithDynamicRenderingOptions
  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 DynamicRenderPassCommandRecorder is no longer valid after end()

Vulkan mapping:

See also:

CommandRecorder, RenderPassCommandRecorderWithDynamicRenderingOptions

RenderPassCommandRecorder (legacy VkRenderPass-based API)

ColorAttachment, DepthStencilAttachment, GraphicsPipeline

Public Functions Documentation

function ~DynamicRenderPassCommandRecorder

1
~DynamicRenderPassCommandRecorder()

function DynamicRenderPassCommandRecorder

1
2
3
DynamicRenderPassCommandRecorder(
    DynamicRenderPassCommandRecorder && other
)

function operator=

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

function DynamicRenderPassCommandRecorder

1
2
3
DynamicRenderPassCommandRecorder(
    const DynamicRenderPassCommandRecorder & 
) =delete

function operator=

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

function handle

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

function isValid

1
inline bool isValid() const

function operator Handle< DynamicRenderPassCommandRecorder_t >

1
inline operator Handle< DynamicRenderPassCommandRecorder_t >() const

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.

Friends

friend CommandRecorder

1
2
3
friend class CommandRecorder(
    CommandRecorder 
);

Updated on 2026-11-07 at 00:01:27 +0000