volk

repository·master·Indexed 23 days ago

https://github.com/zeux/volk

A meta-loader for Vulkan that enables dynamic loading of entrypoints. volk simplifies extension management and allows applications to skip the standard Vulkan loader to reduce overhead and avoid direct linking to vulkan-1.dll. It supports multiple integration methods including direct source, CMake, and header-only patterns, and provides mechanisms to optimize device calls via volkLoadDevice and VolkDeviceTable.

Tokens
1.2K
Snippets
2
Records
6
Agent score
34%

What's inside volk

  1. Optimize device calls to reduce dispatch overhead

    master

    By default, device-related calls (like vkCmdDraw) go through the Vulkan loader dispatch, which can incur up to 7% overhead. You can optimize this using two methods:

    1. Single Device Applications: If you only use one VkDevice, call volkLoadDevice(device) to load entrypoints directly from the driver. This overwrites global function pointers with device-specific versions.
    2. Multi-Device Applications: If you use multiple VkDevice objects, use volkLoadDeviceTable(table, device) to load entrypoints into a VolkDeviceTable. You must store one table per device and call functions from that table instead of the global pointers.

    Note: If you use volkLoadDevice or the table-based approach, you can use volkLoadInstanceOnly() instead of volkLoadInstance() to avoid loading device-specific functions into the global namespace.

  2. Configure volk via CMake

    master

    volk provides several CMake targets depending on your integration method:

    • volk: A static library. Use VOLK_STATIC_DEFINES to pass platform defines.
    • volk_headers: An interface target for header-only usage.

    To use volk as a submodule or local directory:

    add_subdirectory(volk)
    target_link_library(my_application PRIVATE volk)

    To use volk as an installed package (enable via -DVOLK_INSTALL=ON during volk's build), use:

    find_package(volk CONFIG REQUIRED)
    target_link_library(my_application PRIVATE volk::volk)
    # Or for header-only:
    target_link_library(my_application PRIVATE volk::volk_headers)
    if (WIN32)
       set(VOLK_STATIC_DEFINES VK_USE_PLATFORM_WIN32_KHR)
    endif()
    add_subdirectory(volk)
    target_link_library(my_application PRIVATE volk)
  3. Basic usage of volk

    master

    To use volk, you must include volk.h instead of vulkan/vulkan.h.

    Important: If other files in your application include vulkan/vulkan.h without volk.h, you may encounter symbol conflicts. To prevent this, define VK_NO_PROTOTYPES when compiling code that uses Vulkan. Additionally, ensure vulkan-1 is not linked into your application to avoid symbol name conflicts.

    Initialization Workflow:

    1. Call volkInitialize() to load the Vulkan loader from the system. If it returns VK_SUCCESS, proceed to create your VkInstance.
    2. After creating the VkInstance, call volkLoadInstance(instance) to load all required Vulkan entrypoints and extensions.
  4. Integrate volk into your project

    master

    There are three ways to integrate volk into your build system:

    1. Direct Source: Add volk.c to your build. You must pass platform-specific preprocessor defines (e.g., VK_USE_PLATFORM_WIN32_KHR, VK_USE_PLATFORM_XLIB_KHR, VK_USE_PLATFORM_MACOS_MVK) to the compiler.
    2. CMake: Use the provided CMake targets (see CMake support section).
    3. Header-only: Include volk.h in your project. In exactly one source file, define VOLK_IMPLEMENTATION before including volk.h. Do not build volk.c when using this method, but ensure volk.c remains in the same directory as volk.h.
    /* Header-only implementation pattern */
    #define VOLK_IMPLEMENTATION
    #include "volk.h"
  5. Configure volk symbols and namespaces

    master

    You can customize how volk exposes symbols using the following configuration options:

    • VOLK_NAMESPACE: When enabled (via CMake option or preprocessor define), all volk symbols are placed in the volk:: namespace. This requires compiling volk.c in C++ mode (automatic when using CMake). This helps prevent symbol conflicts with other libraries linking to Vulkan.
    • VOLK_NO_DEVICE_PROTOTYPES: Defining this hides device-level function prototypes. This is useful when using volkLoadInstanceOnly or volkLoadDeviceTable, as it allows the compiler to catch mistakes where device-specific functions are called globally.
  6. volk API Reference

    master

    The following functions are used to manage Vulkan entrypoint loading:

    • VkResult volkInitialize(): Attempts to load the Vulkan loader from the system. Returns VK_SUCCESS if successful.
    • void volkLoadInstance(VkInstance instance): Loads all required Vulkan entrypoints and extensions for the provided instance.
    • void volkLoadInstanceOnly(void): Loads instance-level entrypoints but leaves device-specific functions as NULL. Useful when using device tables or volkLoadDevice.
    • void volkLoadDevice(VkDevice device): Loads device-related entrypoints directly from the driver, overwriting global function pointers. Best for single-device applications.
    • void volkLoadDeviceTable(struct VolkDeviceTable* table, VkDevice device): Loads device-related entrypoints into a specific VolkDeviceTable. Required for multi-device applications.