From b4253cf33ff171ac6bcb8c67dab095254815ec5f Mon Sep 17 00:00:00 2001 From: vimene Date: Sat, 13 Dec 2025 22:48:46 +0100 Subject: added physical device selection --- src/engine.cpp | 171 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 166 insertions(+), 5 deletions(-) diff --git a/src/engine.cpp b/src/engine.cpp index 1d17ec2..0e29d60 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #define GLFW_INCLUDE_VULKAN #include @@ -292,10 +293,17 @@ static int main_term() { #define SCREEN_WIDTH 640 #define SCREEN_HEIGHT 480 -const std::vector validation_layers = { +static const std::vector validation_layers = { "VK_LAYER_KHRONOS_validation" }; +static const std::vector device_exts = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + VK_KHR_SPIRV_1_4_EXTENSION_NAME, + VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME, + VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME, +}; + #ifdef NDEBUG const bool enable_validation_layers = false; #else @@ -327,11 +335,12 @@ static bool check_validation_layer_support() { return true; } +// TODO: remove [[maybe_unused]] static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback( - VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, - VkDebugUtilsMessageTypeFlagsEXT message_type, + [[maybe_unused]] VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, + [[maybe_unused]] VkDebugUtilsMessageTypeFlagsEXT message_type, const VkDebugUtilsMessengerCallbackDataEXT* callback_data, - void* user_data) { + [[maybe_unused]] void* user_data) { std::cerr << "validation layer: " << callback_data->pMessage << std::endl; return VK_FALSE; } @@ -369,7 +378,7 @@ static int main_graphical() { app_info.applicationVersion = VK_MAKE_VERSION(1, 0, 0); app_info.pEngineName = "engine"; app_info.engineVersion = VK_MAKE_VERSION(1, 0, 0); - app_info.apiVersion = VK_API_VERSION_1_0; + app_info.apiVersion = VK_API_VERSION_1_4; std::vector extensions; @@ -437,6 +446,158 @@ static int main_graphical() { create_debug_messenger(instance, &msger_create_info, nullptr, &debug_messenger); } + // select physical device + uint32_t physical_devices_count; + vkEnumeratePhysicalDevices(instance, &physical_devices_count, nullptr); + std::vector physical_devices(physical_devices_count); + vkEnumeratePhysicalDevices(instance, &physical_devices_count, physical_devices.data()); + + if (physical_devices.empty()) { + std::cerr << "failed to find physical devices with Vulkan support" << std::endl; + std::exit(EXIT_FAILURE); + } + + VkPhysicalDevice device; + bool found = false; + for (const auto& physical_device : physical_devices) { + VkPhysicalDeviceProperties2 properties{}; + properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + vkGetPhysicalDeviceProperties2(physical_device, &properties); + + VkPhysicalDeviceFeatures2 features{}; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + vkGetPhysicalDeviceFeatures2(physical_device, &features); + + uint32_t queue_family_properties_count; + vkGetPhysicalDeviceQueueFamilyProperties2(physical_device, &queue_family_properties_count, nullptr); + std::vector queue_family_properties(queue_family_properties_count); + vkGetPhysicalDeviceQueueFamilyProperties2(physical_device, &queue_family_properties_count, queue_family_properties.data()); + + // TODO: found a better name, too confusing with device_exts + uint32_t ext_props_count; + vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &ext_props_count, nullptr); + std::vector ext_props(ext_props_count); + vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &ext_props_count, ext_props.data()); + + std::cout << "structure type: " << string_VkStructureType(properties.sType) << std::endl; + std::cout << "pNext: " << properties.pNext << std::endl; + std::cout << "apiVersion: (variant " << VK_API_VERSION_VARIANT(properties.properties.apiVersion) << ") " + << VK_API_VERSION_MAJOR(properties.properties.apiVersion) + << "." << VK_API_VERSION_MINOR(properties.properties.apiVersion) + << "." << VK_API_VERSION_PATCH(properties.properties.apiVersion) + << std::endl; + std::cout << "driverVersion: " << properties.properties.driverVersion << std::endl; + std::cout << "vendorID: " << properties.properties.vendorID << std::endl; + std::cout << "deviceID: " << properties.properties.deviceID << std::endl; + std::cout << "deviceType: " << string_VkPhysicalDeviceType(properties.properties.deviceType) << std::endl; + std::cout << "deviceName: " << properties.properties.deviceName << std::endl; + // pipelineCacheUUID[VK_UUID_SIZE] + // limits + std::cout << "sparseProperties:" << std::endl; + std::cout << std::boolalpha; + std::cout << " residencyStandard2DBlockShape: " << static_cast(properties.properties.sparseProperties.residencyStandard2DBlockShape) << std::endl; + std::cout << " residencyStandard2DMultisampleBlockShape: " + << static_cast(properties.properties.sparseProperties.residencyStandard2DMultisampleBlockShape) << std::endl; + std::cout << " residencyStandard3DBlockShape: " << static_cast(properties.properties.sparseProperties.residencyStandard3DBlockShape) << std::endl; + std::cout << " residencyAlignedMipSize: " << static_cast(properties.properties.sparseProperties.residencyAlignedMipSize) << std::endl; + std::cout << " residencyNonResidentStrict: " << static_cast(properties.properties.sparseProperties.residencyNonResidentStrict) << std::endl; + std::cout << std::noboolalpha; + std::cout << "features:" << std::endl; + std::cout << std::boolalpha; + std::cout << " robustBufferAccess: " << static_cast(features.features.robustBufferAccess) << std::endl; + std::cout << " fullDrawIndexUint32: " << static_cast(features.features.fullDrawIndexUint32) << std::endl; + std::cout << " imageCubeArray: " << static_cast(features.features.imageCubeArray) << std::endl; + std::cout << " independentBlend: " << static_cast(features.features.independentBlend) << std::endl; + std::cout << " geometryShader: " << static_cast(features.features.geometryShader) << std::endl; + std::cout << " tessellationShader: " << static_cast(features.features.tessellationShader) << std::endl; + std::cout << " sampleRateShading: " << static_cast(features.features.sampleRateShading) << std::endl; + std::cout << " dualSrcBlend: " << static_cast(features.features.dualSrcBlend) << std::endl; + std::cout << " logicOp: " << static_cast(features.features.logicOp) << std::endl; + std::cout << " multiDrawIndirect: " << static_cast(features.features.multiDrawIndirect) << std::endl; + std::cout << " drawIndirectFirstInstance: " << static_cast(features.features.drawIndirectFirstInstance) << std::endl; + std::cout << " depthClamp: " << static_cast(features.features.depthClamp) << std::endl; + std::cout << " depthBiasClamp: " << static_cast(features.features.depthBiasClamp) << std::endl; + std::cout << " fillModeNonSolid: " << static_cast(features.features.fillModeNonSolid) << std::endl; + std::cout << " depthBounds: " << static_cast(features.features.depthBounds) << std::endl; + std::cout << " wideLines: " << static_cast(features.features.wideLines) << std::endl; + std::cout << " largePoints: " << static_cast(features.features.largePoints) << std::endl; + std::cout << " alphaToOne: " << static_cast(features.features.alphaToOne) << std::endl; + std::cout << " multiViewport: " << static_cast(features.features.multiViewport) << std::endl; + std::cout << " samplerAnisotropy: " << static_cast(features.features.samplerAnisotropy) << std::endl; + std::cout << " textureCompressionETC2: " << static_cast(features.features.textureCompressionETC2) << std::endl; + std::cout << " textureCompressionASTC_LDR: " << static_cast(features.features.textureCompressionASTC_LDR) << std::endl; + std::cout << " textureCompressionBC: " << static_cast(features.features.textureCompressionBC) << std::endl; + std::cout << " occlusionQueryPrecise: " << static_cast(features.features.occlusionQueryPrecise) << std::endl; + std::cout << " pipelineStatisticsQuery: " << static_cast(features.features.pipelineStatisticsQuery) << std::endl; + std::cout << " vertexPipelineStoresAndAtomics: " << static_cast(features.features.vertexPipelineStoresAndAtomics) << std::endl; + std::cout << " fragmentStoresAndAtomics: " << static_cast(features.features.fragmentStoresAndAtomics) << std::endl; + std::cout << " shaderTessellationAndGeometryPointSize: " << static_cast(features.features.shaderTessellationAndGeometryPointSize) << std::endl; + std::cout << " shaderImageGatherExtended: " << static_cast(features.features.shaderImageGatherExtended) << std::endl; + std::cout << " shaderStorageImageExtendedFormats: " << static_cast(features.features.shaderStorageImageExtendedFormats) << std::endl; + std::cout << " shaderStorageImageMultisample: " << static_cast(features.features.shaderStorageImageMultisample) << std::endl; + std::cout << " shaderStorageImageReadWithoutFormat: " << static_cast(features.features.shaderStorageImageReadWithoutFormat) << std::endl; + std::cout << " shaderStorageImageWriteWithoutFormat: " << static_cast(features.features.shaderStorageImageWriteWithoutFormat) << std::endl; + std::cout << " shaderUniformBufferArrayDynamicIndexing: " << static_cast(features.features.shaderUniformBufferArrayDynamicIndexing) << std::endl; + std::cout << " shaderSampledImageArrayDynamicIndexing: " << static_cast(features.features.shaderSampledImageArrayDynamicIndexing) << std::endl; + std::cout << " shaderStorageBufferArrayDynamicIndexing: " << static_cast(features.features.shaderStorageBufferArrayDynamicIndexing) << std::endl; + std::cout << " shaderStorageImageArrayDynamicIndexing: " << static_cast(features.features.shaderStorageImageArrayDynamicIndexing) << std::endl; + std::cout << " shaderClipDistance: " << static_cast(features.features.shaderClipDistance) << std::endl; + std::cout << " shaderCullDistance: " << static_cast(features.features.shaderCullDistance) << std::endl; + std::cout << " shaderFloat64: " << static_cast(features.features.shaderFloat64) << std::endl; + std::cout << " shaderInt64: " << static_cast(features.features.shaderInt64) << std::endl; + std::cout << " shaderInt16: " << static_cast(features.features.shaderInt16) << std::endl; + std::cout << " shaderResourceResidency: " << static_cast(features.features.shaderResourceResidency) << std::endl; + std::cout << " shaderResourceMinLod: " << static_cast(features.features.shaderResourceMinLod) << std::endl; + std::cout << " sparseBinding: " << static_cast(features.features.sparseBinding) << std::endl; + std::cout << " sparseResidencyBuffer: " << static_cast(features.features.sparseResidencyBuffer) << std::endl; + std::cout << " sparseResidencyImage2D: " << static_cast(features.features.sparseResidencyImage2D) << std::endl; + std::cout << " sparseResidencyImage3D: " << static_cast(features.features.sparseResidencyImage3D) << std::endl; + std::cout << " sparseResidency2Samples: " << static_cast(features.features.sparseResidency2Samples) << std::endl; + std::cout << " sparseResidency4Samples: " << static_cast(features.features.sparseResidency4Samples) << std::endl; + std::cout << " sparseResidency8Samples: " << static_cast(features.features.sparseResidency8Samples) << std::endl; + std::cout << " sparseResidency16Samples: " << static_cast(features.features.sparseResidency16Samples) << std::endl; + std::cout << " sparseResidencyAliased: " << static_cast(features.features.sparseResidencyAliased) << std::endl; + std::cout << " variableMultisampleRate: " << static_cast(features.features.variableMultisampleRate) << std::endl; + std::cout << " inheritedQueries: " << static_cast(features.features.inheritedQueries) << std::endl; + std::cout << std::noboolalpha; + std::cout << "extensions:" << std::endl; + for (const auto& ext : ext_props) { + std::cout + << (std::ranges::find_if(device_exts, [ext_name=ext.extensionName](const auto& device_ext) { return strcmp(ext_name, device_ext) == 0; }) + != device_exts.end() ? "*" : " "); + std::cout << " " << ext.extensionName << std::endl; + } + + bool is_suitable = [&properties, &queue_family_properties, &ext_props]() { + if (VK_API_VERSION_VARIANT(properties.properties.apiVersion) != 0 + || properties.properties.apiVersion < VK_API_VERSION_1_4) + return false; + if (std::ranges::find_if(queue_family_properties, [](const auto& prop) { + return (prop.queueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT) != static_cast(0); + }) == queue_family_properties.end()) + return false; + if (std::ranges::find_if_not(device_exts, [&ext_props](const auto& device_ext) { + return std::ranges::find_if(ext_props, + [device_ext](const auto& ext_prop) { return strcmp(ext_prop.extensionName, device_ext) == 0; }) + != ext_props.end(); + }) != device_exts.end()) + return false; + return true; + }(); + std::cout << "is_suitable: " << std::boolalpha << is_suitable << std::noboolalpha; + if (!found && is_suitable) { + found = true; + std::cout << " (picking this one)"; + device = physical_device; + } + std::cout << std::endl; + } + + if (!found) { + std::cerr << "no suitable physical device found" << std::endl; + std::exit(EXIT_FAILURE); + } + // main loop while (!glfwWindowShouldClose(window)) { glfwPollEvents(); -- cgit v1.2.3