看 Vulkan Sample 的话,创建 PhysicalDevice 和 Surface 的包装思路是
void VulkanRenderer::SelectPhysicalDeviceAndSurface()
{
vk::raii::PhysicalDevices gpus(*m_vulkan_instance);
bool found_graphics_queue_index = false;
for (size_t i = 0; i < gpus.size() && !found_graphics_queue_index; i++)
{
std::vector<vk::QueueFamilyProperties> queue_family_properties = gpus[i].getQueueFamilyProperties();
if (queue_family_properties.empty())
{
throw std::runtime_error("No queue family found.");
}
VkSurfaceKHR surface = m_window.lock()->CreateSurface((**m_vulkan_instance));
if (!surface)
{
throw std::runtime_error("Failed to create window surface.");
}
// delete old surface if old surface exists
m_surface.reset(new vk::raii::SurfaceKHR(*m_vulkan_instance, surface));
for (uint32_t j = 0; j < queue_family_properties.size(); j++)
{
vk::Bool32 supports_present = gpus[i].getSurfaceSupportKHR(j, surface);
// Find a queue family which supports graphics and presentation.
if ((queue_family_properties[j].queueFlags & vk::QueueFlagBits::eGraphics) && supports_present)
{
m_graphics_queue_index = j;
found_graphics_queue_index = true;
m_gpu = std::make_unique<vk::raii::PhysicalDevice>(gpus[i]);
break;
}
}
}
if (!found_graphics_queue_index)
{
RUNTIME_ERROR("Did not find suitable queue which supports graphics and presentation.");
}
}
主要就是找第一个支持 graphics 和 presentation queue family 的 device
另外一种方式是对每一个 device 评分,选择评分最高的那个 device
uint32_t ScorePhysicalDevice(const VkPhysicalDevice& device)
{
uint32_t score = 0;
// Checks if the requested extensions are supported.
uint32_t extension_property_count;
vkEnumerateDeviceExtensionProperties(device, nullptr, &extension_property_count, nullptr);
std::vector<VkExtensionProperties> extension_properties(extension_property_count);
vkEnumerateDeviceExtensionProperties(device, nullptr, &extension_property_count, extension_properties.data());
// Iterates through all extensions requested.
for (const char* currentExtension : LogicalDevice::DeviceExtensions)
{
bool extensionFound = false;
// Checks if the extension is in the available extensions.
for (const auto& extension : extension_properties)
{
if (strcmp(currentExtension, extension.extensionName) == 0)
{
extensionFound = true;
break;
}
}
// Returns a score of 0 if this device is missing a required extension.
if (!extensionFound)
return 0;
}
// Obtain the device features and properties of the current device being rateds.
VkPhysicalDeviceProperties physical_device_properties;
VkPhysicalDeviceFeatures physical_device_features;
vkGetPhysicalDeviceProperties(device, &physical_device_properties);
vkGetPhysicalDeviceFeatures(device, &physical_device_features);
#ifdef MEOW_DEBUG
LogVulkanDevice(physical_device_properties, extension_properties);
#endif
// Adds a large score boost for discrete GPUs (dedicated graphics cards).
if (physical_device_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
score += 1000;
// Gives a higher score to devices with a higher maximum texture size.
score += physical_device_properties.limits.maxImageDimension2D;
return score;
}
void VulkanRenderer::CreatePhysicalDevice()
{
vk::raii::PhysicalDevices gpus(*m_vulkan_instance);
// Maps to hold devices and sort by rank.
std::multimap<uint32_t, vk::raii::PhysicalDevices> rankedDevices;
auto where = rankedDevices.end();
// Iterates through all devices and rate their suitability.
for (const auto& gpu : gpus)
where = rankedDevices.insert(where, {ScorePhysicalDevice(*gpu), gpu});
// Checks to make sure the best candidate scored higher than 0 rbegin points to last element of ranked
// devices(highest rated), first is its rating.
if (rankedDevices.rbegin()->first > 0)
m_gpu = std::make_unique<vk::raii::PhysicalDevice>(rankedDevices.rbegin()->second);
}
Surface 的话