當前位置: 妍妍網 > 碼農

Vulkan 例項(Instance)

2024-07-16碼農

一文對比了 Vulkan 和 OpenGL 的特點,重點介紹了 Vulkan 的優勢體現在哪裏,本文將接著介紹 Vulkan 的一些重要概念。

例項(Instance)

Vulkan 例項 是 Vulkan API中的一個基本概念,它是連線 Vulkan 庫和應用程式之間的橋梁,用於初始化Vulkan 庫。 建立 Vulkan 例項涉及到向驅動程式提供應用程式的一些細節,如應用程式資訊和引擎資訊等。

在Vulkan中,例項(VkInstance)是儲存所有每個套用狀態的物件,應用程式必須在執行任何其他 Vulkan 操作之前建立一個 Vulkan 例項。

這個 類似於 OpenGL 的上下文概念 ,一個例項代表一整 Vulkan 環境(或上下文)。不同的 Vulkan環境能夠獲取到不同的 Vulkan 功能特性。

建立 VkInstance

Vulkan 編程中 ,建立一個 Vulkan 元件有一個固定的規則,首先需要設定一個建立元件資訊的結構體 VkxxxCreateInfo,然後呼叫建立元件的 API VkCreatexxx 。

VkInstanceCreateInfo

typedefstructVkInstanceCreateInfo {
VkStructureType sType;
constvoid* pNext;
VkInstanceCreateFlags flags;
const VkApplicationInfo* pApplicationInfo;
uint32_t enabledLayerCount;
constcharconst* ppEnabledLayerNames;
uint32_t enabledExtensionCount;
constcharconst* ppEnabledExtensionNames;
} VkInstanceCreateInfo;

  • sType 是該結構體的型別列舉值, 必須 是 VkStructureType::VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO 。

  • pNext 要麽是 nullptr 要麽指向其他結構體來擴充套件該結構體。

  • flags 是 VkInstanceCreateFlagBits 所表示的位域值,用於設定 VkInstance 的行為。

  • pApplicationInfo 要麽是 nullptr, 要麽指向套用資訊結構體,用於套用細節設定。

  • enabledLayerCount 啟用的 layer 數量。

  • ppEnabledLayerNames 指向數量為 enabledLayerCount 的 layer 字串陣列,用於設定要啟用的 layer。

  • enabledExtensionCount 啟用 instance 擴充套件的數量。

  • ppEnabledExtensionNames 指向數量為 enabledExtensionCount 的擴充套件字串陣列,用於設定要啟用的 instance 擴充套件。

  • 重點講下 VkApplicationInfo、Layer 和 Extension

    VkApplicationInfo

    VkApplicationInfo appInfo = {
    .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
    .pNext = nullptr,
    .pApplicationName = "my_vulkan_app",
    .applicationVersion = VK_MAKE_VERSION(100),
    .pEngineName = "vulkan_tutorial",
    .engineVersion = VK_MAKE_VERSION(100),
    .apiVersion = VK_MAKE_VERSION(100),
    };

  • sType 是該結構體的型別列舉值, 必須 是 VkStructureType::VK_STRUCTURE_TYPE_APPLICATION_INFO 。

  • pNext 要麽是 NULL 要麽指向其他結構體來擴充套件該結構體。

  • pApplicationName 要麽是 NULL 要麽指向一個以空字元為結尾的 UTF-8 字串,用於表示使用者自訂套用名稱。

  • applicationVersion 一個無符號整型,用於使用者自訂套用版本。

  • pEngineName 要麽是 nullptr 要麽指向一個以空字元為結尾的 UTF-8 字串,用於表示使用者自訂引擎名稱。

  • engineVersion 一個無符號整型,用於使用者自訂引擎版本。

  • apiVersion 是 套用打算使用的 Vulkan 的最高 核心 版本,並且忽略 apiVersion 的 patch 版本

  • 其中 pApplicationName 、 applicationVersion 、 pEngineName 和 engineVersion 這幾個值隨便設定,甚至可以不設定,賦為空都可以,這些參數不影響例項的建立。


    而 apiVersion 參數是最為重要的核心參數 ,當建立例項時,該參數用於指定此例項環境中 Vulkan 的 核心 版本 。

    如果你 Vulkan 版本設定錯了,可能沒法使用一些特性。

    Vulkan API 的最新版本是 1.3,目前 Vulkan 有 4 個版本:

  • Vulkan 1.0 主要提供光柵化圖形和平行計算的功能。對應 VK_API_VERSION_1_0 。

  • Vulkan 1.1 主要為 Vulkan 1.0 不完善的地方進行補全。對應 VK_API_VERSION_1_1 。

  • Vulkan 1.2 主要提供硬體光追的功能。對應 VK_API_VERSION_1_2 。

  • Vulkan 1.3 主要提供動態光柵化圖形的功能。對應 VK_API_VERSION_1_3 。

  • 每個 Vulkan 新版本的釋出不單單提供基本功能,還會提供一系列擴充套件功能,並且會將之前版本中的一些擴充套件功能提升囊括至核心版本中

    Layer

    Vulkan 的 Layer(層)是一種重要的機制,允許開發者在 Vulkan API 的核心功能上插入額外的功能和工具

    Layer 主要的特點是模組化,可以根據需要載入和解除安裝,開發者可以選擇在應用程式初始化時啟用哪些層。


    常用作正確性驗證檢查。 比如你添加了驗證層 VK_LAYER_KHRONOS_validation ,如果在執行階段發生了使用錯誤, Layer 會輸出錯誤資訊,幫助開發者定位錯誤

    目前 Vulkan 支持的 層 如下:

  • VK_LAYER_KHRON OS_validation Vulkan API 驗證和錯誤檢查。

  • VK_LAYER_LUNARG_gfxreconstruct 使用 GFXReconstruct 捕獲套用的 Vulkan 指令。

  • VK_LAYER_LUNARG_api_dump 輸出呼叫的 API 和傳入的參數。

  • VK_LAYER_KHRONOS_profiles 幫助測試硬體的效能,而不需要物理接觸每個裝置。該 層 將會覆蓋從 GPU 查詢到的數據。

  • VK_LAYER_LUNARG_monitor 在套用界面的標題處顯示幀率。

  • VK_LAYER_LUNARG_screenshot 將顯示的畫面幀輸出到一個圖片檔中。

  • VK_LAYER_KHRONOS_synchronization2 使用系統實作的 VK_KHR_synchronization2 擴充套件,而不是驅動實作的。

  • VK_LAYER_KHRONOS_shader_object 使用系統實作的 VK_EXT_shader_object 擴充套件,而不是驅動實作的。

  • 可以透過 vkEnumerateInstanceLayerProperties函式獲取系統中 Vulkan 支持的 Layer

    uint32_t layer_property_count = 0;
    vkEnumerateInstanceLayerProperties(&layer_property_count, nullptr);
    std::vector<VkLayerProperties> layer_properties(layer_property_count);
    vkEnumerateInstanceLayerProperties(&layer_property_count, layer_properties.data());

    思考:vkEnumerateInstanceLayerProperties 這個函式為什麽呼叫了 2 次?
    其中 VkLayerProperties 定義如下

    // 由 VK_VERSION_1_0 提供
    typedefstructVkLayerProperties {
    char layerName[VK_MAX_EXTENSION_NAME_SIZE];
    uint32_t specVersion;
    uint32_t implementationVersion;
    char description[VK_MAX_DESCRIPTION_SIZE];
    } VkLayerProperties;

    Extension

    Vulkan Extensions(擴充套件)是對 Vulkan API 的功能擴充套件,它們允許硬體制造商、平台開發者和第三方提供額外的功能和特性,這些功能和特性不包含在核心 Vulkan 規範中。

    在 Vulkan 中有兩類擴充套件:

  • Instance 擴充套件 與使用哪一個 GPU 裝置無關,與 Vulkan 環境有關。 VkInstanceCreateInfo 中的 enabledExtensionCount 和 ppEnabledExtensionNames 就是用於配置此類 Instance 擴充套件 。

  • Device 擴充套件 與使用哪一個 GPU 裝置有關。不同廠家的 GPU 裝置會支持不同的裝置擴充套件。這將會在之後的章節展開。

  • VkInstance 支持的例項擴充套件可以透過 vkEnumerateInstanceExtensionProperties 函式獲取

    // 由 VK_VERSION_1_0 提供
    VkResult vkEnumerateInstanceExtensionProperties(
    constchar* pLayerName,
    uint32_t* pPropertyCount,
    VkExtensionProperties* pProperties)
    ;

    要想獲取全部的擴充套件,該函式的呼叫與 vkEnumerateInstanceLayerProperties(...) 類似,呼叫兩遍,第一遍 pProperties 為 nullptr ,第二遍為有效值即可:

    uint32_t extension_property_count = 0;
    vkEnumerateInstanceExtensionProperties(nullptr, &extension_property_count, nullptr);
    std::vector<VkExtensionProperties> extension_properties(extension_property_count);
    vkEnumerateInstanceExtensionProperties(nullptr, &extension_property_count, extension_properties.data());

    其中 VkExtensionProperties 定義如下

    // 由 VK_VERSION_1_0 提供
    typedefstructVkExtensionProperties {
    char extensionName[VK_MAX_EXTENSION_NAME_SIZE];//副檔名稱
    uint32_t specVersion;//版本
    } VkExtensionProperties;

    有一些例項擴充套件我們需要重點關註一下

  • VK_KHR_surface 代表視窗通用平面擴充套件。

  • VK_{vender}_{platform}_surface 代表各個平台各自的視窗平面(各自平台適配到通用平面)。

  • 比如

  • VK_KHR_win32_surface 為 Windows 平台,供應商為 Khronos 。

  • VK_OHOS_surface 為 OpenHarmony 平台,供應商為 華為 。

  • VK_KHR_android_surface 為 Android 平台,供應商為 Khronos 。

  • VK_KHR_[wayland/xcb/xlib]_surface 為 Linux 平台(其中 [wayland/xcb/xlib] 表示三者其一),供應商為 Khronos 。

  • 建立 Instance 範例

    VkInstance instance = nullptr;
    std::vector<constchar*> instance_extensions;
    instance_extensions.push_back("VK_KHR_surface");
    instance_extensions.push_back("VK_KHR_android_surface");//Android
    //如果是 WIndow 平台使用 VK_KHR_win32_surface
    std::vector<constchar *> instance_layers;
    instance_layers.push_back("VK_LAYER_KHRONOS_validation");//添加驗證層
    VkApplicationInfo appInfo = {
    .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
    .pNext = nullptr,
    .pApplicationName = "my_vulkan_app",
    .applicationVersion = VK_MAKE_VERSION(100),
    .pEngineName = "example",
    .engineVersion = VK_MAKE_VERSION(100),
    .apiVersion = VK_MAKE_VERSION(100),
    };
    VkInstanceCreateInfo instanceCreateInfo{
    .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
    .pNext = nullptr,
    .pApplicationInfo = appInfo,
    .enabledLayerCount = 
    static_cast<uint32_t>(instance_layers.size()),
    .ppEnabledLayerNames = instance_layers.data(),
    .enabledExtensionCount =
    static_cast<uint32_t>(instance_extensions.size()),
    .ppEnabledExtensionNames = instance_extensions.data(),
    };
    VkResult result = vkCreateInstance(&instanceCreateInfo, nullptr, &instance);
    if (result != VK_SUCCESS)
    {
    //VkInstance 建立失敗
    }
    // 開啟 Vulkan 編程 ...
    vkDestroyInstance(instance, nullptr);//透過 vkDestroyInstance 函式銷毀 instance





    -- END --

    進技術交流群, 掃碼添加我的微信:Byte-Flow

    獲取相關資料和源碼

    學習音視訊、OpenGL ES、Vulkan 、Metal、影像濾鏡、視訊特效及相關渲染技術的付費社群,面試指導,1v1 簡歷服務,職業規劃。

    我的付費社群