diff options
| author | vimene <vincent.menegaux@gmail.com> | 2025-12-20 21:24:02 +0100 |
|---|---|---|
| committer | vimene <vincent.menegaux@gmail.com> | 2025-12-20 21:24:02 +0100 |
| commit | 09411b34a4b2c3a235a5621110543744484d2a15 (patch) | |
| tree | c3767cc5aba1c9fb2cc6e6f326e4ac6f3f85b1e5 /src | |
| parent | e3a465293b92ed30e220f2c70f67fb9adf3b0403 (diff) | |
| download | engine-09411b34a4b2c3a235a5621110543744484d2a15.tar.gz | |
added scores to improve physical device selection, and more refactoring
see e3a465293b for details about refactoring
Diffstat (limited to 'src')
| -rw-r--r-- | src/engine.cpp | 234 |
1 files changed, 146 insertions, 88 deletions
diff --git a/src/engine.cpp b/src/engine.cpp index fa5814f..aa9c644 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -19,6 +19,7 @@ #include <array> #include <ios> #include <fstream> +#include <map> #define GLFW_INCLUDE_VULKAN #include <GLFW/glfw3.h> @@ -315,6 +316,14 @@ const bool enable_validation_layers = false; const bool enable_validation_layers = true; #endif +struct PhysicalDeviceEntry { + uint32_t idx; + VkPhysicalDevice physical_device; + const char* name; + uint32_t graphics_queue_family_index, present_queue_family_index; + VkPhysicalDeviceFeatures2 features; +}; + static bool check_validation_layer_support() { uint32_t layer_count; if (VkResult res = vkEnumerateInstanceLayerProperties(&layer_count, nullptr); res != VK_SUCCESS) { @@ -472,35 +481,37 @@ static int main_graphical() { .apiVersion = VK_API_VERSION_1_4, }; - std::vector<const char*> extensions; - - { - uint32_t glfw_extension_count; - const char** glfw_extensions; - glfw_extensions = glfwGetRequiredInstanceExtensions(&glfw_extension_count); - extensions.insert(extensions.end(), glfw_extensions, glfw_extensions + glfw_extension_count); - } - - if (enable_validation_layers) { - extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); - } + auto instance_exts = [&]() { + std::vector<const char*> instance_exts; + { + uint32_t glfw_extension_count; + const char** glfw_extensions = glfwGetRequiredInstanceExtensions(&glfw_extension_count); + instance_exts.insert(instance_exts.end(), glfw_extensions, glfw_extensions + glfw_extension_count); + } + if (enable_validation_layers) + instance_exts.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + return instance_exts; + }(); - uint32_t extension_count; - if (VkResult res = vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr); res != VK_SUCCESS) { - std::cerr << "failed to enumerate instance extension properties, error code: " << string_VkResult(res) << std::endl; - std::exit(EXIT_FAILURE); - } - std::vector<VkExtensionProperties> available_extensions(extension_count); - if (VkResult res = vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, available_extensions.data()); res != VK_SUCCESS) { - std::cerr << "failed to enumerate instance extension properties, error code: " << string_VkResult(res) << std::endl; - std::exit(EXIT_FAILURE); - } + auto avail_instance_exts = [&]() { + uint32_t avail_instance_exts_count; + if (VkResult res = vkEnumerateInstanceExtensionProperties(nullptr, &avail_instance_exts_count, nullptr); res != VK_SUCCESS) { + std::cerr << "failed to enumerate instance extension properties, error code: " << string_VkResult(res) << std::endl; + std::exit(EXIT_FAILURE); + } + std::vector<VkExtensionProperties> avail_instance_exts(avail_instance_exts_count); + if (VkResult res = vkEnumerateInstanceExtensionProperties(nullptr, &avail_instance_exts_count, avail_instance_exts.data()); res != VK_SUCCESS) { + std::cerr << "failed to enumerate instance extension properties, error code: " << string_VkResult(res) << std::endl; + std::exit(EXIT_FAILURE); + } + return avail_instance_exts; + }(); std::cout << "required instance extensions:\n"; - for (const auto& extension_name : extensions) { - std::cout << (std::ranges::find_if(available_extensions, [&](const auto& avail_ext) { + for (const auto& extension_name : instance_exts) { + std::cout << (std::ranges::find_if(avail_instance_exts, [&](const auto& avail_ext) { return strcmp(avail_ext.extensionName, extension_name) == 0; - }) == available_extensions.end() ? "!" : " "); + }) == avail_instance_exts.end() ? "!" : " "); std::cout << " " << extension_name << "\n"; } @@ -511,8 +522,8 @@ static int main_graphical() { .pApplicationInfo = &app_info, .enabledLayerCount = {}, .ppEnabledLayerNames = {}, - .enabledExtensionCount = static_cast<uint32_t>(extensions.size()), - .ppEnabledExtensionNames = extensions.data(), + .enabledExtensionCount = static_cast<uint32_t>(instance_exts.size()), + .ppEnabledExtensionNames = instance_exts.data(), }; VkDebugUtilsMessengerCreateInfoEXT inst_msger_ci{}; @@ -556,20 +567,21 @@ static int main_graphical() { // select physical device and queues auto [physical_device, graphics_queue_family_index, present_queue_family_index, device_features] = [&]() { - std::optional<VkPhysicalDevice> physical_device; - uint32_t res_graphics_queue_family_index, res_presentation_queue_family_index; - VkPhysicalDeviceFeatures2 res_features; + std::multimap<unsigned, PhysicalDeviceEntry> physical_devices; - uint32_t physical_devices_count; - if (VkResult res = vkEnumeratePhysicalDevices(instance, &physical_devices_count, nullptr); res != VK_SUCCESS) { - std::cerr << "failed to enumerate physical devices, error code: " << string_VkResult(res) << std::endl; - std::exit(EXIT_FAILURE); - } - std::vector<VkPhysicalDevice> avail_physical_devices(physical_devices_count); - if (VkResult res = vkEnumeratePhysicalDevices(instance, &physical_devices_count, avail_physical_devices.data()); res != VK_SUCCESS) { - std::cerr << "failed to enumerate physical devices, error code: " << string_VkResult(res) << std::endl; - std::exit(EXIT_FAILURE); - } + auto avail_physical_devices = [&]() { + uint32_t avail_physical_devices_count; + if (VkResult res = vkEnumeratePhysicalDevices(instance, &avail_physical_devices_count, nullptr); res != VK_SUCCESS) { + std::cerr << "failed to enumerate physical devices, error code: " << string_VkResult(res) << std::endl; + std::exit(EXIT_FAILURE); + } + std::vector<VkPhysicalDevice> avail_physical_devices(avail_physical_devices_count); + if (VkResult res = vkEnumeratePhysicalDevices(instance, &avail_physical_devices_count, avail_physical_devices.data()); res != VK_SUCCESS) { + std::cerr << "failed to enumerate physical devices, error code: " << string_VkResult(res) << std::endl; + std::exit(EXIT_FAILURE); + } + return avail_physical_devices; + }(); if (avail_physical_devices.empty()) { std::cerr << "failed to find physical devices with Vulkan support" << std::endl; @@ -578,44 +590,62 @@ static int main_graphical() { std::cout << "devices:" << std::endl; - for (const auto& avail_physical_device : avail_physical_devices) { - VkPhysicalDeviceProperties2 properties{}; - properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; - vkGetPhysicalDeviceProperties2(avail_physical_device, &properties); + for (uint32_t i = 0; i < avail_physical_devices.size(); i++) { + const auto& avail_physical_device = avail_physical_devices[i]; + + PhysicalDeviceEntry physical_device_entry; + physical_device_entry.physical_device = avail_physical_device; - std::cout << " " << properties.properties.deviceName << ":" << std::endl; - std::cout << " apiVersion: " << engine::myvk::api { properties.properties.apiVersion } << std::endl; + auto physical_device_props = [&]() { + VkPhysicalDeviceProperties2 physical_device_props{}; + physical_device_props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + vkGetPhysicalDeviceProperties2(avail_physical_device, &physical_device_props); + return physical_device_props; + }(); - VkPhysicalDeviceFeatures2 features{}; - features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - vkGetPhysicalDeviceFeatures2(avail_physical_device, &features); + std::cout << " " << (i + 1) << ". " << physical_device_props.properties.deviceName << ":" << std::endl; + std::cout << " apiVersion: " << engine::myvk::api { physical_device_props.properties.apiVersion } << std::endl; - // TODO: found a better name, too confusing with device_exts - uint32_t ext_props_count; - if (VkResult res = vkEnumerateDeviceExtensionProperties(avail_physical_device, nullptr, &ext_props_count, nullptr); res != VK_SUCCESS) { - std::cerr << "failed to enumerate physical device extension properties, error code: " << string_VkResult(res) << std::endl; - std::exit(EXIT_FAILURE); - } - std::vector<VkExtensionProperties> ext_props(ext_props_count); - if (VkResult res = vkEnumerateDeviceExtensionProperties(avail_physical_device, nullptr, &ext_props_count, ext_props.data()); res != VK_SUCCESS) { - std::cerr << "failed to enumerate physical device extension properties, error code: " << string_VkResult(res) << std::endl; - std::exit(EXIT_FAILURE); - } + physical_device_entry.features = [&]() { + VkPhysicalDeviceFeatures2 physical_device_features{}; + physical_device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + vkGetPhysicalDeviceFeatures2(avail_physical_device, &physical_device_features); + return physical_device_features; + }(); + + auto physical_device_ext_props = [&]() { + uint32_t physical_device_ext_props_count; + if (VkResult res = vkEnumerateDeviceExtensionProperties(avail_physical_device, nullptr, + &physical_device_ext_props_count, nullptr); res != VK_SUCCESS) { + std::cerr << "failed to enumerate physical device extension properties, error code: " << string_VkResult(res) << std::endl; + std::exit(EXIT_FAILURE); + } + std::vector<VkExtensionProperties> physical_device_ext_props(physical_device_ext_props_count); + if (VkResult res = vkEnumerateDeviceExtensionProperties(avail_physical_device, nullptr, + &physical_device_ext_props_count, physical_device_ext_props.data()); res != VK_SUCCESS) { + std::cerr << "failed to enumerate physical device extension properties, error code: " << string_VkResult(res) << std::endl; + std::exit(EXIT_FAILURE); + } + return physical_device_ext_props; + }(); std::cout << " required physical device extensions:" << std::endl; for (const auto& ext : device_exts) { - std::cout << " " << (std::ranges::find_if(ext_props, [&](const auto& avail_ext) { + std::cout << " " << (std::ranges::find_if(physical_device_ext_props, [&](const auto& avail_ext) { return strcmp(avail_ext.extensionName, ext) == 0; - }) == ext_props.end() ? "!" : " "); + }) == physical_device_ext_props.end() ? "!" : " "); std::cout << " " << ext << std::endl; } - uint32_t queue_family_properties_count; - vkGetPhysicalDeviceQueueFamilyProperties2(avail_physical_device, &queue_family_properties_count, nullptr); - std::vector<VkQueueFamilyProperties2> queue_family_properties(queue_family_properties_count); - for (auto& elt : queue_family_properties) - elt.sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2; - vkGetPhysicalDeviceQueueFamilyProperties2(avail_physical_device, &queue_family_properties_count, queue_family_properties.data()); + auto queue_family_properties = [&]() { + uint32_t queue_family_properties_count; + vkGetPhysicalDeviceQueueFamilyProperties2(avail_physical_device, &queue_family_properties_count, nullptr); + std::vector<VkQueueFamilyProperties2> queue_family_properties(queue_family_properties_count); + for (auto& elt : queue_family_properties) + elt.sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2; + vkGetPhysicalDeviceQueueFamilyProperties2(avail_physical_device, &queue_family_properties_count, queue_family_properties.data()); + return queue_family_properties; + }(); auto [graphics_queue_family_index, present_queue_family_index] = find_queue_family_indices(avail_physical_device, queue_family_properties, surface); std::cout << " graphics queue family index: "; @@ -631,40 +661,68 @@ static int main_graphical() { std::cout << "none"; std::cout << std::endl; - bool is_suitable = [&]() { - if (VK_API_VERSION_VARIANT(properties.properties.apiVersion) != 0 - || properties.properties.apiVersion < VK_API_VERSION_1_4) - return false; + auto score = [&]() { + if (VK_API_VERSION_VARIANT(physical_device_props.properties.apiVersion) != 0 + || physical_device_props.properties.apiVersion < VK_API_VERSION_1_4) + return std::optional<unsigned> {}; if (!graphics_queue_family_index || !present_queue_family_index) - return false; + return std::optional<unsigned> {}; if (std::ranges::find_if_not(device_exts, [&](const auto& device_ext) { - return std::ranges::find_if(ext_props, + return std::ranges::find_if(physical_device_ext_props, [&](const auto& ext_prop) { return strcmp(ext_prop.extensionName, device_ext) == 0; }) - != ext_props.end(); + != physical_device_ext_props.end(); }) != device_exts.end()) - return false; - return true; + return std::optional<unsigned> {}; + + unsigned score = 0; + if (*graphics_queue_family_index == *present_queue_family_index) + score += 5; + switch (physical_device_props.properties.deviceType) { + case VK_PHYSICAL_DEVICE_TYPE_OTHER: + score += 0; + break; + case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: + score += 2; + break; + case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: + score += 10; + break; + case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: + score += 5; + break; + case VK_PHYSICAL_DEVICE_TYPE_CPU: + score += 1; + break; + default: + // TODO: make it better, because if in the future vulkan add more device types, + // it can crash + std::unreachable(); + } + return std::optional<unsigned> { score }; }(); - std::cout << " is_suitable: " << std::boolalpha << is_suitable << std::noboolalpha; - if (!physical_device && is_suitable) { - std::cout << " (picking this one)"; - physical_device = avail_physical_device; - res_graphics_queue_family_index = *graphics_queue_family_index; - res_presentation_queue_family_index = *present_queue_family_index; - res_features = features; + std::cout << " is suitable: " << std::boolalpha << static_cast<bool>(score) << std::noboolalpha << std::endl; + + if (score) { + physical_device_entry.graphics_queue_family_index = *graphics_queue_family_index; + physical_device_entry.present_queue_family_index = *present_queue_family_index; + physical_device_entry.name = physical_device_props.properties.deviceName; + physical_devices.insert({ *score, physical_device_entry }); } - std::cout << std::endl; } std::cout << std::endl; - if (!physical_device) { + if (physical_devices.empty()) { std::cerr << "no suitable physical device found" << std::endl; std::exit(EXIT_FAILURE); } - return std::tuple<VkPhysicalDevice, uint32_t, uint32_t, VkPhysicalDeviceFeatures2> - { *physical_device, res_graphics_queue_family_index, res_presentation_queue_family_index, res_features }; + auto best = physical_devices.crbegin(); + + std::cout << "picking: " << (best->second.idx + 1) << ". " << best->second.name << " (score: " << best->first << ")" << std::endl; + + return std::tuple { best->second.physical_device, best->second.graphics_queue_family_index, + best->second.present_queue_family_index, best->second.features }; }(); auto device = [&]() { |
