Rether / docs
engine/apis/vulkan/Vulkan logical device
gardenThe software interface to the chosen GPU

Vulkan logical device

updated 2026.08.29created 2026.08.29~2 min

The concept

This is the final step of initialization. If the Vulkan physical device is the hardware graphics card, the logical device is the software interface we use to communicate with it. This is where we enable the specific features we need.

Gamegine activates modern Vulkan 1.3 features, including dynamic rendering (which eliminates the need for heavy RenderPass objects).

Feature configuration

Vulkan uses a chain of pointers (pNext) to extend configuration structures. Here, we chain the structures to activate Vulkan 1.1, 1.3, and extension features.

// cpp
// Setup Features - explicitly enable features if supported
vk::PhysicalDeviceVulkan13Features vk13Features{};

if (supportedVk13Features.dynamicRendering) {
    vk13Features.dynamicRendering = VK_TRUE;
}

if (supportedVk13Features.synchronization2) {
    vk13Features.synchronization2 = VK_TRUE;
}

vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT
            extendedDynamicState{};
const auto& supportedExtendedDynamicState =
    supportedFeatures
        .get<vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>();
if (supportedExtendedDynamicState.extendedDynamicState) {
    extendedDynamicState.extendedDynamicState = VK_TRUE;
}

// Setup base features (samplerAnisotropy)
vk::PhysicalDeviceFeatures2 baseFeatures{};
if (supportedFeatures.get<vk::PhysicalDeviceFeatures2>()
        .features.samplerAnisotropy) {
    baseFeatures.features.samplerAnisotropy = VK_TRUE;
}

// Manually set up the pNext chain to ensure it's correct
extendedDynamicState.pNext = nullptr;
vk13Features.pNext         = &extendedDynamicState;
vk::PhysicalDeviceVulkan11Features vk11Features{};
vk11Features.pNext = &vk13Features;
baseFeatures.pNext = &vk11Features;

Device creation

Finally, we create the device by providing it with the list of required device extensions (such as swapchain, see Vulkan physical device) and information about the queue found in Vulkan queue families.

// cpp
// Setup Device Info
vk::DeviceCreateInfo deviceCreateInfo{};
deviceCreateInfo.pNext                 = &baseFeatures;
deviceCreateInfo.queueCreateInfoCount  = 1;
deviceCreateInfo.pQueueCreateInfos     = &queueCreateInfo;
deviceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(
    deviceExtensions.size());
deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions.data();

d_device        = vk::raii::Device(d_physicalDevice, deviceCreateInfo);
d_graphicsQueue = vk::raii::Queue(d_device,
                                  d_graphicsQueueFamilyIndex,
                                  0);

What comes next

Now that our logical device is created and our graphics queue is ready to receive commands, the GPU is technically capable of rendering images. However, we still have a major problem: where do we put these rendered images so the user can see them?

The Vulkan surface we created earlier is just an abstract connection to the window; it does not hold any actual pixels. To display a continuous stream of frames without tearing or flickering, we need an infrastructure that manages a queue of images waiting to be displayed on the screen. That infrastructure is the Swapchain — the bridge that takes finished frames from our logical device and presents them to the surface.

Keyboard

search this vault⌘K / /
step the sidebarjk
open selected↵
switch browse mode123
switch vaultgv
toggle themet
close / clearesc
this help?
esc to close