Vulkan Instance的创建
Vulkan Instance需要通过VkInstanceCreateInfo结构体进行创建,结构体成员如下:
typedef struct VkInstanceCreateInfo {
VkStructureType sType; // 指向结构体类型
const void* pNext; // 指向指定的拓展类型的结构体
VkInstanceCreateFlags flags; // 保留字段,未使用
const VkApplicationInfo* pApplicationInfo; //用于识别应用的额外信息
uint32_t enabledLayerCount; // 需要创建的layer的数目
const char* const* ppEnabledLayerNames; // 创建layer对应的名字
uint32_t enabledExtensionCount; // 需要创建拓展的数目
const char* const* ppEnabledExtensionNames; // 创建拓展的名字
} VkInstanceCreateInfo;
因此一个Vulkan Instance创建的过程可以用如下表示:
// 创建AppInfo结构体
VkApplicationInfo appInfo{};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pApplicationName = "Hello Triangle";
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.pEngineName = "No Engine";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = VK_API_VERSION_1_0;
VkInstanceCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
createInfo.pApplicationInfo = &appInfo;
auto extensions = getRequiredExtensions(); // 获取必要 Extensions Names
createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
createInfo.ppEnabledExtensionNames = extensions.data();
// Add validationlayers names to create info;
if(enableValidationLayers){
VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo;
createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
createInfo.ppEnabledLayerNames = validationLayers.data();
// 添加必要 DebugMessenger创建时的结构信息到pNext指针,从而hook上VulkanInstance的创建与析构过程
populateDebugMessengerCreateInfo(debugCreateInfo);
createInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*) & debugCreateInfo;
}else{
createInfo.enabledLayerCount = 0;
}
// 创建最终的指针
if(vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS){
throw std::runtime_error("failed to create instance");
}
可以看出,Vulkan的创建过程中需要的Extensions的名称列表,以及需要加载的layer列表,extensions与layer相关信息的获取将在接下来说明。
Extensions的生成可参考如下代码,首先 glfw库中取得glfw与vulkan交互所需的Extensions,其为一个const char**
指针,接着将其值赋给std::vector<const char*>
,该对象的size即为Extensions的数目。如果需要调用用于debug的Validation layer,再向其中加入VK_EXT_DEBUG_UTILS_EXTENSION_NAME。
std::vector<const char *> getRequiredExtensions() {
uint32_t glfwExtensionCount = 0;
const char **glfwExtensions;
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
std::vector<const char *> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
if (enableValidationLayers) {
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
}
return extensions;
}
另一方面,在添加Validation layers后,我们还可以为其注册我们自己实现的debugCallback,其依托于上面代码中 VK_EXT_debug_utils。我们需要创建一个VkDebugUtilsMessengerEXT对象 debugMessenger,该对象表现为Vulkan Instance下的一个object,其生命周期需要由我们的程序自行管理,即需要在VkInstance析构前销毁该对象。该对象的生成同样需要对应的CreateInfo,具体如下代码所示,相应变量作用请参考代码内注释。
void populateDebugMessengerCreateInfo(
VkDebugUtilsMessengerCreateInfoEXT &createInfo) {
createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
createInfo.messageSeverity =
VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
createInfo.messageType =
VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
createInfo.pfnUserCallback = debugCallback;
}
由于其为依托于我们创建的VkInstance实例下的Object,我们需要从Instance内获取对应的函数指针,获取函数指针并通过结构体创建debugMessenger方法如下:
VkResult CreateDebugUtilsMessengerEXT(
VkInstance instance,
const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkDebugUtilsMessengerEXT *pDebugMessenger
) {
// Get Vulkan Extension function address
auto func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance,
"vkCreateDebugUtilsMessengerEXT");
if (func != nullptr) {
return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
} else {
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
}
void setupDebugMessenger() {
if (!enableValidationLayers) return;
// First: fill the debug messenger creator info struct.
VkDebugUtilsMessengerCreateInfoEXT createInfo;
populateDebugMessengerCreateInfo(createInfo);
if (CreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger) != VK_SUCCESS) {
throw std::runtime_error("failed to set up debug messenger");
}
}
由于我们需要手动管理该对象,因此释放该对象的方法如下:
void DestroyDebugUtilsMessengerEXT(
VkInstance instance,
VkDebugUtilsMessengerEXT debugMessenger,
const VkAllocationCallbacks *pAllocator
) {
auto func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance,
"vkDestroyDebugUtilsMessengerEXT");
if (func != nullptr) {
func(instance, debugMessenger, pAllocator);
}
}
void cleanup() {
// destroy child object before release VkInstance
if (enableValidationLayers) {
DestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr);
}
vkDestroyInstance(instance, nullptr);
glfwDestroyWindow(window);
glfwTerminate();
}