在创建完成Vulkan后,我们需要在设备上寻找一个支持所需特性的物理设备,或者同时调用多个设备。选中 物理设备将被存储到 VkPhysicalDevice 的句柄中,并称为一个新的需要管理的成员类,该对象的销毁无需我们手动进行管理。查找可选的Devices的过程与Extensions的过程类似。
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
void pickPhysicalDevice() {
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());
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");
}
}
Device对象的suitability检查
bool isDeviceSuitable(VkPhysicalDevice device) {
VkPhysicalDeviceProperties deviceProperties;
vkGetPhysicalDeviceProperties(device, &deviceProperties);
VkPhysicalDeviceFeatures deviceFeatures;
vkGetPhysicalDeviceFeatures(device, &deviceFeatures);
return deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && deviceFeatures.geometryShader;
}
void pickPhysicalDevice() {
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());
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");
}
VkPhysicalDeviceProperties deviceProperties;
vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties);
std::cout << "Selected GPU: " << deviceProperties.deviceName << std::endl;
}
可以根据各个Device拥有的特性选择最合适的那个Device。
Queue familie
在Vulkan中,从不同的queue families中衍生出了不同种类的queues并且不同家族的queues只会允许一个子类的命令。例如有些queue family只允许处理compute commands,而有些只能执行memory transfer related commands。
我们需要检查那些queue familes是能够被设备支持的,以及哪些指令是我们需要用到的。因此,我们可以创建一个新的function ‘findQueueFamilies’ 来查找那些我们需要用到的queue families。