aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvimene <vincent.menegaux@gmail.com>2025-12-20 21:24:02 +0100
committervimene <vincent.menegaux@gmail.com>2025-12-20 21:24:02 +0100
commit09411b34a4b2c3a235a5621110543744484d2a15 (patch)
treec3767cc5aba1c9fb2cc6e6f326e4ac6f3f85b1e5
parente3a465293b92ed30e220f2c70f67fb9adf3b0403 (diff)
downloadengine-09411b34a4b2c3a235a5621110543744484d2a15.tar.gz
added scores to improve physical device selection, and more refactoring
see e3a465293b for details about refactoring
-rw-r--r--src/engine.cpp234
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 = [&]() {