Skip to content

KDGpu::Swapchain

Module: Public API

Manages presentation images for displaying rendered content to a window. More...

#include <KDGpu/swapchain.h>

Public Functions

Name
Swapchain()
~Swapchain()
Swapchain(Swapchain && other)
Swapchain & operator=(Swapchain && other)
Swapchain(const Swapchain & ) =delete
Swapchain & operator=(const Swapchain & ) =delete
const Handle< Swapchain_t > & handle() const
bool isValid() const
operator Handle< Swapchain_t >() const
const std::vector< Texture > & textures() const
AcquireImageResult getNextImageIndex(uint32_t & imageIndex, const Handle< GpuSemaphore_t > & semaphore =Handle< GpuSemaphore_t >())

Friends

Name
class Device

Detailed Description

1
class KDGpu::Swapchain;

Manages presentation images for displaying rendered content to a window.

Vulkan equivalent:VkSwapchainKHR

Swapchain owns a collection of presentable images (textures) that are displayed to a Surface. It manages double/triple buffering and handles image acquisition and presentation.

Key features:

  • Multiple presentation images for buffering
  • Automatic image rotation and synchronization
  • Format and resolution configuration
  • VSync and presentation modes

Lifetime: Swapchains are created by Device from a Surface and should remain valid while presenting. They use RAII and clean up automatically.

Usage

Creating a swapchain:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
    KDGpu::Surface surface = instance.createSurface(surfaceOptions);
    KDGpu::Adapter *adapter = instance.selectAdapter(KDGpu::AdapterDeviceType::Default);

    // Query surface capabilities
    auto swapchainProps = adapter->swapchainProperties(surface);

    KDGpu::Swapchain swapchain = device.createSwapchain(KDGpu::SwapchainOptions{
            .surface = surface,
            .format = swapchainProps.formats[0].format, // Choose first available
            .minImageCount = 3, // Triple buffering
            .imageExtent = { windowWidth, windowHeight },
            .imageUsageFlags = KDGpu::TextureUsageFlagBits::ColorAttachmentBit,
    });

Filename: kdgpu_doc_snippets.cpp

Accessing swapchain images:

1
2
3
4
5
6
7
    const std::vector<KDGpu::Texture> &images = swapchain.textures();

    // Create views for rendering
    std::vector<KDGpu::TextureView> imageViews;
    for (const auto &image : images) {
        imageViews.push_back(image.createView());
    }

Filename: kdgpu_doc_snippets.cpp

Render loop with swapchain:

 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
38
39
40
41
42
43
44
45
46
47
    KDGpu::GpuSemaphore imageAvailable = device.createGpuSemaphore();
    KDGpu::GpuSemaphore renderComplete = device.createGpuSemaphore();
    KDGpu::CommandRecorder recorder = device.createCommandRecorder();

    while (rendering) {
        // Acquire next image to render to
        uint32_t imageIndex;
        const KDGpu::AcquireImageResult result = swapchain.getNextImageIndex(imageIndex, imageAvailable);

        if (result != KDGpu::AcquireImageResult::Success) {
            // Handle swapchain out of date (window resize, etc.)
            continue;
        }

        // Record rendering commands to swapchain image
        auto renderPass = recorder.beginRenderPass(KDGpu::RenderPassCommandRecorderOptions{
                .colorAttachments = {
                        {
                                .view = imageViews[imageIndex],
                                .loadOperation = KDGpu::AttachmentLoadOperation::Clear,
                                .storeOperation = KDGpu::AttachmentStoreOperation::Store,
                                .clearValue = { 0.1f, 0.1f, 0.1f, 1.0f },
                        },
                },
        });
        // ... render commands ...
        renderPass.end();
        KDGpu::CommandBuffer cmdBuffer = recorder.finish();

        // Submit rendering
        queue.submit(KDGpu::SubmitOptions{
                .commandBuffers = { cmdBuffer },
                .waitSemaphores = { imageAvailable.handle() },
                .signalSemaphores = { renderComplete.handle() },
        });

        // Present the rendered image
        queue.present(KDGpu::PresentOptions{
                .waitSemaphores = { renderComplete.handle() },
                .swapchainInfos = {
                        {
                                .swapchain = swapchain.handle(),
                                .imageIndex = imageIndex,
                        },
                },
        });
    }

Filename: kdgpu_doc_snippets.cpp

Handling window resize:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
    // Wait for GPU to finish using swapchain
    device.waitUntilIdle();

    // Destroy old image views
    imageViews.clear();

    // Recreate swapchain with new size
    swapchain = device.createSwapchain(KDGpu::SwapchainOptions{
            .surface = surface,
            .format = surfaceFormat,
            .minImageCount = 3,
            .imageExtent = { newWidth, newHeight },
            .imageUsageFlags = KDGpu::TextureUsageFlagBits::ColorAttachmentBit,
    });

    // Recreate views
    for (const KDGpu::Texture &image : swapchain.textures()) {
        imageViews.push_back(image.createView());
    }

Filename: kdgpu_doc_snippets.cpp

Choosing presentation mode:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
    // Find best presentation mode
    KDGpu::PresentMode presentMode = KDGpu::PresentMode::Fifo; // VSync (always available)

    for (const auto &mode : swapchainProps.presentModes) {
        if (mode == KDGpu::PresentMode::Mailbox) {
            // Triple buffering without tearing
            presentMode = mode;
            break;
        } else if (mode == KDGpu::PresentMode::Immediate) {
            // No VSync, potential tearing
            presentMode = mode;
        }
    }

    KDGpu::Swapchain swapchainWithMode = device.createSwapchain(KDGpu::SwapchainOptions{
            .surface = surface.handle(),
            .format = surfaceFormat,
            .imageExtent = { newWidth, newHeight },
            .presentMode = presentMode,
    });

Filename: kdgpu_doc_snippets.cpp

Getting swapchain optimal format:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
    auto props = adapter->swapchainProperties(surface.handle());

    // Find SRGB format if available
    KDGpu::Format chosenFormat = props.formats[0].format;
    for (const auto &formatInfo : props.formats) {
        if (formatInfo.format == KDGpu::Format::B8G8R8A8_SRGB) {
            chosenFormat = formatInfo.format;
            break;
        }
    }

Filename: kdgpu_doc_snippets.cpp

Vulkan mapping:

See also:

Surface, Texture, Queue, Device

KDGpu API Overview

KDGpu to Vulkan API Mapping

Public Functions Documentation

function Swapchain

1
Swapchain()

function ~Swapchain

1
~Swapchain()

function Swapchain

1
2
3
Swapchain(
    Swapchain && other
)

function operator=

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

function Swapchain

1
2
3
Swapchain(
    const Swapchain & 
) =delete

function operator=

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

function handle

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

function isValid

1
inline bool isValid() const

function operator Handle< Swapchain_t >

1
inline operator Handle< Swapchain_t >() const

function textures

1
inline const std::vector< Texture > & textures() const

function getNextImageIndex

1
2
3
4
AcquireImageResult getNextImageIndex(
    uint32_t & imageIndex,
    const Handle< GpuSemaphore_t > & semaphore =Handle< GpuSemaphore_t >()
)

Friends

friend Device

1
2
3
friend class Device(
    Device 
);

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