1. vulkan instance中初始化的instance是整个vulkan应用与vulkan库的全局上下文,管理着vulkan的所有资源、启用的扩展等等。

而本节,我们则是基于实例来选择具体的物理设备。

每个物理设备代表一个实际的GPU, 每个物理设备都有自己的特性和能力,例如支持的 Vulkan 版本、内存类型、队列族等。

选择物理设备的方法也很简单,枚举当前可用的物理设别,晒选择出符合要求的设备即可。从代码上看vulkan的风格还是很统一的

VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
 
uint32_t deviceCount = 0;
vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
if (deviceCount == 0) {
  throw std::runtime_error("Failed to find GPUs with Vulkan support!");
}
std::vector<VkPhysicalDevice> devices(deviceCount);
vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
// 遍历GPU,选择出最终使用的设备
for (const auto& device : devices) {
  if (isDeviceSuitable(device)) {
	physicalDevice = device;
	break;
  }
}
 
if (physicalDevice == VK_NULL_HANDLE) {
  throw std::runtime_error("failed to find a suitable GPU!");
}

这里的主要逻辑是对设备的选择,我们可以使用 vkGetPhysicalDeviceProperties来获取设备的基本属性,以及vkGetPhysicalDeviceFeatures来查看设备对可选的特性的支持情况。例如我们要使用一个支持几何着色器的独立显卡设备

bool isDeviceSuitable(VkPhysicalDevice device) { 
	VkPhysicalDeviceProperties deviceProperties; 
	VkPhysicalDeviceFeatures deviceFeatures;
	
	vkGetPhysicalDeviceProperties(device, &deviceProperties); 
	vkGetPhysicalDeviceFeatures(device, &deviceFeatures); 
	
	return deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && deviceFeatures.geometryShader; 
}

vulkan中几乎每个操作,都需要提交命令到到队列当中,而队列就来自queue family,每个queue family都支持不同的命令子集。例如一个queue family只支持处理计算命令,而另一个允许处理内存传输相关的命令。

我们选择设备之后,就可以获取这个设备的queue family信息,然后根据属性选择出自己需要使用的queue

uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount,
										 nullptr);
std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount,
										 queueFamilies.data());

遍历这些queue family,最终根据queue family的属性来决定要使用的queue family。