Vulkan Cookbook 第一章 4 準備載入Vulkan API函式
準備載入Vulkan API函式
當我們想在我們的應用程式中使用Vulkan API時,我們需要獲取Vulkan文件中指定的過程。為了做到這一點,我們可以向Vulkan Loader庫新增一個依賴項,在我們的專案中靜態連結它,並使用vulkan.h標頭檔案中定義的函式原型。第二種方法是禁用vulkan.h標頭檔案中定義的函式原型,並在我們的應用程式中動態載入函式指標。 第一種方法稍微容易一點,但它使用Vulkan Loader庫中直接定義的函式。當我們在給定裝置上執行操作時,Vulkan Loader需要根據我們提供的裝置控制代碼將函式呼叫重定向到正確的實現。此重定向需要一些時間,因此會影響效能。 第二個選項需要在應用程式端進行更多工作,但允許我們跳過前面的重定向(跳轉)並儲存一些效能。它是通過直接從我們想要使用的裝置載入功能來執行的。這樣,如果我們不需要它們,我們也可以只選擇Vulkan函式的子集。 在本書中,介紹了第二種方法,因為這使開發人員可以更好地控制應用程式中的內容。要從Vulkan Loader庫動態載入函式,可以方便地將所有Vulkan API函式的名稱包裝到一組簡單的巨集中,並將宣告定義和函式載入分成多個檔案。
怎麼做...
1.在專案中定義VK_NO_PROTOTYPES前處理器定義:在專案屬性中執行此操作(使用Microsoft Visual Studio或Qt Creator等開發環境時),或者在包含vulkan.h檔案之前使用#define VK_NO_PROTOTYPES前處理器指令 在我們的應用程式的原始碼中。 2.建立一個名為ListOfVulkanFunctions.inl的新檔案。 3.在檔案中鍵入以下內容:
#ifndef EXPORTED_VULKAN_FUNCTION #define EXPORTED_VULKAN_FUNCTION( function ) #endif #undef EXPORTED_VULKAN_FUNCTION // #ifndef GLOBAL_LEVEL_VULKAN_FUNCTION #define GLOBAL_LEVEL_VULKAN_FUNCTION( function ) #endif #undef GLOBAL_LEVEL_VULKAN_FUNCTION // #ifndef INSTANCE_LEVEL_VULKAN_FUNCTION #define INSTANCE_LEVEL_VULKAN_FUNCTION( function ) #endif #undef INSTANCE_LEVEL_VULKAN_FUNCTION // #ifndef INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION #define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION( function, #endif #undef INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION // #ifndef DEVICE_LEVEL_VULKAN_FUNCTION #define DEVICE_LEVEL_VULKAN_FUNCTION( function ) #endif #undef DEVICE_LEVEL_VULKAN_FUNCTION // #ifndef DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION #define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION( function, extension ) #endif #undef DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION
4.建立一個新檔名為VulkanFunctions.h。 5.將以下內容插入到檔案中:
#include "vulkan.h" namespace VulkanCookbook { #define EXPORTED_VULKAN_FUNCTION( name ) extern PFN_##name name; #define GLOBAL_LEVEL_VULKAN_FUNCTION( name ) extern PFN_##name name; #define INSTANCE_LEVEL_VULKAN_FUNCTION( name ) extern PFN_##name name; #define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION( name, extension ) extern PFN_##name name; #define DEVICE_LEVEL_VULKAN_FUNCTION( name ) extern PFN_##name name; #define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION( name, extension ) extern PFN_##name name; #include "ListOfVulkanFunctions.inl" } // namespace VulkanCookbook
6.建立一個名為VulkanFunctions.cpp.原始碼檔案。 7.在檔案中插入以下內容:
#include "VulkanFunctions.h"
namespace VulkanCookbook {
#define EXPORTED_VULKAN_FUNCTION( name ) PFN_##name name;
#define GLOBAL_LEVEL_VULKAN_FUNCTION( name ) PFN_##name name;
#define INSTANCE_LEVEL_VULKAN_FUNCTION( name ) PFN_##name name;
#define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION( name, extension ) PFN_##name name;
#define DEVICE_LEVEL_VULKAN_FUNCTION( name ) PFN_##name name;
#define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION( name, extension ) PFN_##name name;
#include "ListOfVulkanFunctions.inl"
} // namespace VulkanCookbook
這個怎麼運作...
VulkanFunctions.h和VulkanFunctions.cpp的巨集定義似乎是不必要的,也的確不是不必要的。這兩個檔案應該用於宣告和定義變數,但為了減少拼寫錯誤,函式名稱會在ListOfVulkanFunctions.inl中使用巨集定義新增,不需要在多個地方多次重複函式的名稱,我們將在其中儲存指向Vulkan API函式的指標。
我們如何知道用於儲存指向Vulkan API函式的指標的變數型別? 這很簡單。 每個函式原型的型別直接來自函式的名稱。 當函式名為<name>時,其型別為PFN_<name>。 例如,建立影象的函式稱為vkCreateImage(),因此該函式的型別為PFN_vkCreateImage。 這就是為什麼在VulkanFunctions.h和VulkanFunctions.cpp中定義的巨集只有一個函做為作為引數,這可以很容易的拼出型別。
提示:將包含Vulkan API函式指標的變數的宣告和定義放在結構,類或名稱空間中。
現在我們已經準備好了,我們可以開始載入Vulkan函數了。