Vulkan-Hpp Documentation

repository·main·Indexed 25 days ago

https://github.com/khronosgroup/vulkan-hpp

Header-only C++ bindings for the Vulkan C API. Vulkan-Hpp provides type safety, STL support, and RAII-based resource management (including vk::raii types) without runtime CPU overhead. It supports C++11 through C++23, with the generator requiring C++20. The library can be installed via the LunarG Vulkan SDK, vcpkg, or Conan, and offers extensive configuration via macros to manage exceptions, dispatchers, and enhanced mode.

Tokens
13.3K
Snippets
24
Records
67
Agent score
87%

What's inside Vulkan-Hpp

  1. Overview of Vulkan-Hpp

    main

    Vulkan-Hpp provides header-only C++ bindings for the Vulkan C API. It is designed to improve developer experience without introducing run-time CPU costs. Key features include:

    • Type safety: Enhanced safety for enumerations and bit-fields.
    • STL support: Integration with STL containers.
    • Exception support: Ability to use C++ exceptions.
    • RAII handles: Various varieties of RAII-capable types, including vk::raii types that offer object-oriented semantics for Vulkan handles (similar to std::unique_ptr or std::shared_ptr).
  2. Understand Vulkan-Hpp naming conventions

    main

    Vulkan-Hpp renames C API symbols to follow C++ conventions.

    Functions and Structs:

    • The Vk or vk prefix is removed.
    • Function names start with a lowercase letter.
    • Example: vkCreateInstance becomes vk::createInstance; VkImageCreateInfo becomes vk::ImageCreateInfo.

    Enums (Scoped enum class):

    • The VK_ prefix and type infix are removed.
    • An e prefix is added to values, using CamelCase.
    • Extension suffixes are removed from enum values, but preserved in the enum type name.
    • Example: VK_IMAGETYPE_2D becomes vk::ImageType::e2D; VK_COLOR_SPACE_SRGB_NONLINEAR_KHR becomes vk::ColorSpaceKHR::eSrgbNonlinear.

    Flags:

    • Similar to enums, but the _BIT suffix is removed.
  3. Understand the vulkan_raii.hpp RAII approach

    main

    The vulkan_raii.hpp header provides a C++ layer on top of vulkan.hpp based on the Resource Acquisition Is Initialization (RAII) principle.

    Key differences from standard vulkan.hpp:

    • Resource Management: Instead of calling vk*Create or vk*Allocate and manually calling vk*Destroy or vk*Free, you use constructors for vk::raii wrapper classes. The resource is automatically destroyed when the wrapper object goes out of scope.
    • Ownership: vk::raii objects own the underlying Vulkan resource. Consequently, most vk::raii objects are movable but not copyable. Some objects, like vk::raii::PhysicalDevice, remain copyable.
    • API Style: Functions related to non-dispatchable handles are members of the corresponding vk::raii object rather than being members of a vk::Device or global functions. For example, instead of calling device.bindBufferMemory(...), you call buffer.bindMemory(...).
  4. Understand the benefits of the vk::raii namespace

    main

    The vk::raii namespace provides a complete set of Vulkan handle wrapper classes that follow the Resource Acquisition Is Initialization (RAII) paradigm.

    Key benefits include:

    • Automatic Lifetime Management: Handles can be assigned to smart pointers, ensuring destruction is never missed.
    • Automatic Function Pointer Dispatch: vk::raii::Context, vk::raii::Instance, and vk::raii::Device handle function pointer management automatically. This ensures you always use the correct device-specific functions, even when managing multiple devices.

    Important Note: Certain classes, such as vk::raii::CommandPool and vk::raii::DescriptorSet, require special handling that deviates from the standard C-API or the non-RAII vk namespace wrappers.

  5. Use the Builder pattern with setters

    main

    If constructors are disabled (e.g., when using designated initializers), you can use setter member functions for all struct members. This allows for a fluent interface.

    Note: This feature can be disabled with VULKAN_HPP_NO_STRUCT_SETTERS.

    std::array<uint32_t, 2> const queueFamilies = { 1U, 2U };
    auto ci = vk::ImageCreateInfo{
      .imageType = vk::ImageType::e2D,
      .format = vk::Format::eR8G8B8A8Unorm,
      .extent = { width, height, 1 },
      .mipLevels = 1,
      .arrayLayers = 1,
      .samples = vk::SampleCountFlagBits::e1,
      .tiling = vk::ImageTiling::eOptimal,
      .usage = vk::ImageUsageFlagBits::eColorAttachment,
      .sharingMode = vk::SharingMode::eExclusive,
      .initialLayout = vk::ImageLayout::eUndefined
    }.setQueueFamilyIndices(queueFamilies); // Uses ArrayProxyNoTemporaries
  6. Create and manage vk::raii objects

    main

    You can create vk::raii objects using constructors or creation functions.

    Constructor Approach

    Pass the parent object and the creation info to the constructor. The object will be automatically destroyed when it leaves scope.

    Creation Function Approach

    Alternatively, use creation functions provided by the parent object. This is the required method if you have defined VULKAN_HPP_NO_EXCEPTIONS and are compiling for C++23, as constructors might throw exceptions.

    Using std::expected (C++23 + VULKAN_HPP_NO_EXCEPTIONS)

    When exceptions are disabled, creation functions return a std::expected<vk::raii::Object, vk::Result>. You must check if the value exists before moving it into your object.

    // Constructor approach
    // create a vk::raii::Device, given a vk::raii::PhysicalDevice physicalDevice and a vk::DeviceCreateInfo deviceCreateInfo
    vk::raii::Device device( physicalDevice, deviceCreateInfo );
    
    // Creation function approach
    // create a vk::raii::Device, given a vk::raii::PhysicalDevice physicalDevice and a vk::DeviceCreateInfo deviceCreateInfo
    vk::raii::Device device = physicalDevice.createDevice( deviceCreateInfo );
    
    // C++23 + VULKAN_HPP_NO_EXCEPTIONS approach
    // when VULKAN_HPP_NO_EXCEPTIONS is defined and your using at least C++23
    auto deviceExpected = physicalDevice.createDevice( deviceCreateInfo );
    if ( deviceExpected.has_value() )
    {
    	device = std::move( *deviceExpected );
    }
  7. Compile Vulkan-Hpp modules manually (Non-CMake)

    main

    To use modules without CMake, you must pre-compile the standard library module and the Vulkan-Hpp module, then compile your source code referencing those pre-compiled modules.

    # Clang example
    clang++ -std=c++23 -stdlib=libc++ --precompile -o std.pcm /path/to/std.cppm
    clang++ -std=c++23 -stdlib=libc++ -fmodule-file=std=std.pcm --precompile -o vulkan.pcm -isystem "<path/to/Vulkan-Hpp>/Vulkan-Headers/include" -isystem "<path/to/Vulkan-Hpp>/vulkan" <path/to/Vulkan-Hpp>/vulkan/vulkan.cppm
    clang++ -std=c++23 -stdlib=libc++ -fmodule-file=std=std.pcm -fmodule-file=vulkan=vulkan.pcm main.cpp -o main
  8. Use RAII-style handles in `vk::raii` namespace

    main

    The vk::raii namespace provides handles that follow the RAII (Resource Acquisition Is Initialization) idiom. A vk::raii::Handle acquires the underlying C handle in its constructor and releases it in its destructor.

    Comparison with other handles:

    • vk::UniqueHandle: Mimics std::unique_ptr.
    • vk::SharedHandle: Mimics std::shared_ptr (includes parent ownership).
    • vk::raii::Handle: A dedicated RAII class.

    Key Differences:

    • Dispatchers: vk::UniqueHandle, vk::SharedHandle, and standard vk::Handle types use the same global dispatcher. However, vk::raii types use a custom dispatcher and maintain their own.
    • Multi-device support: Because vk::raii types maintain their own dispatchers, member function calls are guaranteed to be device-specific, which is highly useful in applications with multiple devices.
  9. Initialize vk::raii::Context

    main

    The first step in using the vk::raii namespace is to instantiate a vk::raii::Context. This class acts as a handle to global Vulkan functions that are not bound to a specific VkInstance or VkDevice (e.g., enumerating the API version).

    // instantiate a vk::raii::Context
    vk::raii::Context context;
    
    // get the API version, using that context
    uint32_t apiVersion = context.enumerateInstanceVersion();
  10. Minimum compiler requirements for Vulkan-Hpp

    main

    The generator requires a toolchain that supports C++20. Samples and tests can be compiled with at least C++11, with support for up to C++23.

    Known working compilers:

    • Visual Studio ≥ 2015
    • GCC ≥ 4.8.2
    • Clang ≥ 3.3

    Note: Compiling the C++ named module requires the most recent compiler toolchains possible.