创建逻辑设备
填写好前面两个结构体后,我们可以开始填写VkDeviceCreateInfo结构体。
VkDeviceCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
将VkDeviceCreateInfo结构体的pQueueCreateInfos指针指向queueCreateInfo的地址,pEnabledFeatures指针指向deviceFeatures的地址:
createInfo.pQueueCreateInfos = &queueCreateInfo;
createInfo.queueCreateInfoCount = 1;
createInfo.pEnabledFeatures = &deviceFeatures;
结构体的其余成员和VkInstanceCreateInfo类似,不同的是这次的设置是针对设备的。
VK_KHR_swapchain就是一个设备特定扩展的例子,这一扩展使得我们可以将渲染的图像在窗口上显示出来。看起来似乎应该所有支持Vulkan的设备都应该支持这一扩展,然而,实际上有的Vulkan设备只支持计算指令,不支持这一图形相关扩展。在之后的章节,我们会对交换链进行更加深入地说明。
之前提到,我们可以对设备和Vulkan实例使用相同地校验层,不需要额外的扩展支持:
createInfo.enabledExtensionCount = 0;
if (enableValidationLayers) {
createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
createInfo.ppEnabledLayerNames = validationLayers.data();
} else {
createInfo.enabledLayerCount = 0;
}
现在,我们可以调用vkCreateDevice函数创建逻辑设备了。
if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) {
throw std::runtime_error("failed to create logical device!");
}
vkCreateDevice函数的参数包括我们创建的逻辑设备进行交互的物理设备对象,我们刚刚在结构体中指定的需要使用的队列信息,可选的分配器回调,以及用来存储返回的逻辑设备对象的内存地址。和Vulkan实例对象的创建函数类似,这一函数调用在请求的设备需求不被满足时返回错误代码。
逻辑设备对象创建后,应用程序结束前,需要我们自己在cleanup函数中调用vkDestroyDevice函数来清除它:
void cleanup() {
vkDestroyDevice(device, nullptr);
...
}
逻辑设备并不直接与Vulkan实例交互,所以创建逻辑设备时不需要使用Vulkan实例作为参数。