在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。