diff --git a/src/graphics/presentation/window/vulkanWindow.cpp b/src/graphics/presentation/window/vulkanWindow.cpp index 824943eaa..a143f66d9 100644 --- a/src/graphics/presentation/window/vulkanWindow.cpp +++ b/src/graphics/presentation/window/vulkanWindow.cpp @@ -137,11 +137,13 @@ static uint32_t VulkanFindQueueFamily(vk::PhysicalDevice device, vk::SurfaceKHR return static_cast(-1); } +// On failure out_device is null and out_rejections says why each device was skipped. // NOLINTNEXTLINE(readability-function-cognitive-complexity) static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surface, const std::vector& device_extensions, SurfaceCapabilities& out_capabilities, - vk::PhysicalDevice& out_device, uint32_t& out_queue_family) { + vk::PhysicalDevice& out_device, uint32_t& out_queue_family, + std::string& out_rejections) { EXIT_IF(instance == nullptr); EXIT_IF(surface == nullptr); @@ -170,14 +172,22 @@ static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surfa vk::PhysicalDeviceProperties device_properties {}; device.getProperties(&device_properties); + const auto reject = [&](const std::string& reason) { + LOGF("%s\n", reason.c_str()); + out_rejections += + skip_device ? "; " : fmt::format("\n {}: ", device_properties.deviceName.data()); + out_rejections += reason; + skip_device = true; + }; + LOGF("Vulkan device: %s\n", device_properties.deviceName.data()); if (device_properties.apiVersion < VULKAN_TARGET_API_VERSION) { - LOGF("Vulkan %u.%u is required, but device supports only %u.%u.%u\n", - VK_VERSION_MAJOR(VULKAN_TARGET_API_VERSION), - VK_VERSION_MINOR(VULKAN_TARGET_API_VERSION), - VK_VERSION_MAJOR(device_properties.apiVersion), - VK_VERSION_MINOR(device_properties.apiVersion), - VK_VERSION_PATCH(device_properties.apiVersion)); + reject(fmt::format("Vulkan {}.{} is required, but device supports only {}.{}.{}", + VK_VERSION_MAJOR(VULKAN_TARGET_API_VERSION), + VK_VERSION_MINOR(VULKAN_TARGET_API_VERSION), + VK_VERSION_MAJOR(device_properties.apiVersion), + VK_VERSION_MINOR(device_properties.apiVersion), + VK_VERSION_PATCH(device_properties.apiVersion))); continue; } @@ -203,7 +213,7 @@ static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surfa fragment_barycentric.pNext = &depth_clip_control; features12.pNext = &fragment_barycentric; #endif - features13.pNext = &features12; + features13.pNext = &features12; device_features2.pNext = &features13; device.getFeatures2(&device_features2); @@ -212,151 +222,82 @@ static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surfa const auto queue_family = VulkanFindQueueFamily(device, surface); if (queue_family == static_cast(-1)) { - LOGF("No universal graphics, compute, and presentation queue\n"); - skip_device = true; + reject("No universal graphics, compute, and presentation queue"); } + const auto check_feature = [&](vk::Bool32 supported, const char* name, + vk::Bool32 required = VK_TRUE) { + if (required == VK_TRUE && supported != VK_TRUE) { + reject(fmt::format("{} is not supported", name)); + } + }; + +#if defined(__APPLE__) if (color_write_ext.colorWriteEnable != VK_TRUE) { LOGF("colorWriteEnable is not supported\n"); -#if !defined(__APPLE__) - skip_device = true; + } +#else + check_feature(color_write_ext.colorWriteEnable, "colorWriteEnable"); #endif - } - if (image_view_min_lod.minLod != VK_TRUE) { - LOGF("image view minLod is not supported\n"); - skip_device = true; - } + check_feature(image_view_min_lod.minLod, "image view minLod"); - if (depth_clip_control.depthClipControl != VK_TRUE) { - LOGF("depthClipControl is not supported\n"); - skip_device = true; - } + check_feature(depth_clip_control.depthClipControl, "depthClipControl"); +#if defined(__APPLE__) if (depth_clip_enable.depthClipEnable != VK_TRUE) { LOGF("depthClipEnable is not supported\n"); -#if !defined(__APPLE__) - skip_device = true; + } +#else + check_feature(depth_clip_enable.depthClipEnable, "depthClipEnable"); #endif - } #if !defined(__APPLE__) - if (device_features2.features.depthClamp != VK_TRUE) { - LOGF("depthClamp is not supported\n"); - skip_device = true; - } - if (fragment_barycentric.fragmentShaderBarycentric != VK_TRUE) { - LOGF("fragmentShaderBarycentric is not supported\n"); - skip_device = true; - } + check_feature(device_features2.features.depthClamp, "depthClamp"); + check_feature(fragment_barycentric.fragmentShaderBarycentric, "fragmentShaderBarycentric"); #endif - if (required_features12.samplerMirrorClampToEdge == VK_TRUE && - features12.samplerMirrorClampToEdge != VK_TRUE) { - LOGF("samplerMirrorClampToEdge is not supported\n"); - skip_device = true; - } - if (required_features12.timelineSemaphore == VK_TRUE && - features12.timelineSemaphore != VK_TRUE) { - LOGF("timelineSemaphore is not supported\n"); - skip_device = true; - } - if (required_features12.shaderOutputLayer == VK_TRUE && - features12.shaderOutputLayer != VK_TRUE) { - LOGF("shaderOutputLayer is not supported\n"); - skip_device = true; - } - if (required_features12.shaderOutputViewportIndex == VK_TRUE && - features12.shaderOutputViewportIndex != VK_TRUE) { - LOGF("shaderOutputViewportIndex is not supported\n"); - skip_device = true; - } - if (required_features12.bufferDeviceAddress == VK_TRUE && - features12.bufferDeviceAddress != VK_TRUE) { - LOGF("bufferDeviceAddress is not supported\n"); - skip_device = true; - } - if (required_features12.shaderBufferInt64Atomics == VK_TRUE && - features12.shaderBufferInt64Atomics != VK_TRUE) { - LOGF("shaderBufferInt64Atomics is not supported\n"); - skip_device = true; - } - if (features13.robustImageAccess != VK_TRUE) { - LOGF("robustImageAccess is not supported\n"); - skip_device = true; - } - if (required_features13.dynamicRendering == VK_TRUE && - features13.dynamicRendering != VK_TRUE) { - LOGF("dynamicRendering is not supported\n"); - skip_device = true; - } - if (required_features13.synchronization2 == VK_TRUE && - features13.synchronization2 != VK_TRUE) { - LOGF("synchronization2 is not supported\n"); - skip_device = true; - } - if (device_features2.features.sampleRateShading != VK_TRUE) { - LOGF("sampleRateShading is not supported\n"); - skip_device = true; - } - if (device_features2.features.depthBiasClamp != VK_TRUE) { - LOGF("depthBiasClamp is not supported\n"); - skip_device = true; - } - if (device_features2.features.shaderClipDistance != VK_TRUE) { - LOGF("shaderClipDistance is not supported\n"); - skip_device = true; - } - if (device_features2.features.shaderCullDistance != VK_TRUE) { - LOGF("shaderCullDistance is not supported\n"); - skip_device = true; - } - if (device_features2.features.largePoints != VK_TRUE) { - LOGF("largePoints is not supported\n"); - skip_device = true; - } - if (device_features2.features.multiViewport != VK_TRUE) { - LOGF("multiViewport is not supported\n"); - skip_device = true; - } - if (device_features2.features.fillModeNonSolid != VK_TRUE) { - LOGF("fillModeNonSolid is not supported\n"); - skip_device = true; - } - if (device_features2.features.fragmentStoresAndAtomics != VK_TRUE) { - LOGF("fragmentStoresAndAtomics is not supported\n"); - skip_device = true; - } + check_feature(features12.samplerMirrorClampToEdge, "samplerMirrorClampToEdge", + required_features12.samplerMirrorClampToEdge); + check_feature(features12.timelineSemaphore, "timelineSemaphore", + required_features12.timelineSemaphore); + check_feature(features12.shaderOutputLayer, "shaderOutputLayer", + required_features12.shaderOutputLayer); + check_feature(features12.shaderOutputViewportIndex, "shaderOutputViewportIndex", + required_features12.shaderOutputViewportIndex); + check_feature(features12.bufferDeviceAddress, "bufferDeviceAddress", + required_features12.bufferDeviceAddress); + check_feature(features12.shaderBufferInt64Atomics, "shaderBufferInt64Atomics", + required_features12.shaderBufferInt64Atomics); + check_feature(features13.robustImageAccess, "robustImageAccess"); + check_feature(features13.dynamicRendering, "dynamicRendering", + required_features13.dynamicRendering); + check_feature(features13.synchronization2, "synchronization2", + required_features13.synchronization2); + check_feature(device_features2.features.sampleRateShading, "sampleRateShading"); + check_feature(device_features2.features.depthBiasClamp, "depthBiasClamp"); + check_feature(device_features2.features.shaderClipDistance, "shaderClipDistance"); + check_feature(device_features2.features.shaderCullDistance, "shaderCullDistance"); + check_feature(device_features2.features.largePoints, "largePoints"); + check_feature(device_features2.features.multiViewport, "multiViewport"); + check_feature(device_features2.features.fillModeNonSolid, "fillModeNonSolid"); + check_feature(device_features2.features.fragmentStoresAndAtomics, + "fragmentStoresAndAtomics"); - if (device_features2.features.samplerAnisotropy != VK_TRUE) { - LOGF("samplerAnisotropy is not supported\n"); - skip_device = true; - } - if (device_features2.features.robustBufferAccess != VK_TRUE) { - LOGF("robustBufferAccess is not supported\n"); - skip_device = true; - } + check_feature(device_features2.features.samplerAnisotropy, "samplerAnisotropy"); + check_feature(device_features2.features.robustBufferAccess, "robustBufferAccess"); +#if defined(__APPLE__) if (device_features2.features.depthBounds != VK_TRUE) { LOGF("depthBounds is not supported\n"); -#if !defined(__APPLE__) - skip_device = true; + } +#else + check_feature(device_features2.features.depthBounds, "depthBounds"); #endif - } - if (device_features2.features.shaderStorageImageWriteWithoutFormat != VK_TRUE) { - LOGF("shaderStorageImageWriteWithoutFormat is not supported\n"); - skip_device = true; - } + check_feature(device_features2.features.shaderStorageImageWriteWithoutFormat, + "shaderStorageImageWriteWithoutFormat"); - if (device_features2.features.shaderImageGatherExtended != VK_TRUE) { - LOGF("shaderImageGatherExtended is not supported\n"); - skip_device = true; - } + check_feature(device_features2.features.shaderImageGatherExtended, + "shaderImageGatherExtended"); - if (device_features2.features.independentBlend != VK_TRUE) { - LOGF("independentBlend is not supported\n"); - skip_device = true; - } - if (device_features2.features.tessellationShader != VK_TRUE) { - LOGF("tessellationShader is not supported\n"); - skip_device = true; - } + check_feature(device_features2.features.independentBlend, "independentBlend"); + check_feature(device_features2.features.tessellationShader, "tessellationShader"); if (!skip_device) { auto available_extensions = EnumerateVulkan( @@ -368,8 +309,7 @@ static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surfa for (const char* ext: device_extensions) { if (!HasExtension(available_extensions, ext)) { - skip_device = true; - break; + reject(fmt::format("{} is not supported", ext)); } } @@ -387,86 +327,46 @@ static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surfa if (!(candidate_capabilities.capabilities.supportedUsageFlags & vk::ImageUsageFlagBits::eTransferDst)) { - LOGF("Surface cannot be destination of blit\n"); - skip_device = true; + reject("Surface cannot be destination of blit"); } } - if (!skip_device && !CheckFormat(device, vk::Format::eD32Sfloat, true, - vk::FormatFeatureFlagBits::eDepthStencilAttachment)) { - LOGF("Format vk::Format::eD32Sfloat cannot be used as depth buffer\n"); - skip_device = true; - } - - if (!skip_device && !CheckFormat(device, vk::Format::eD32SfloatS8Uint, true, - vk::FormatFeatureFlagBits::eDepthStencilAttachment)) { - LOGF("Format vk::Format::eD32SfloatS8Uint cannot be used as depth buffer\n"); - skip_device = true; - } - - if (!skip_device && !CheckFormat(device, vk::Format::eD16Unorm, true, - vk::FormatFeatureFlagBits::eDepthStencilAttachment)) { - LOGF("Format vk::Format::eD16Unorm cannot be used as depth buffer\n"); - skip_device = true; - } - - if (!skip_device && !CheckFormat(device, vk::Format::eBc3SrgbBlock, true, - vk::FormatFeatureFlagBits::eSampledImage | - vk::FormatFeatureFlagBits::eTransferDst)) { - LOGF("Format vk::Format::eBc3SrgbBlock cannot be used as texture\n"); - skip_device = true; - } - - if (!skip_device && !CheckFormat(device, vk::Format::eR8G8B8A8Srgb, true, - vk::FormatFeatureFlagBits::eSampledImage | - vk::FormatFeatureFlagBits::eTransferDst)) { - LOGF("Format vk::Format::eR8G8B8A8Srgb cannot be used as texture\n"); - skip_device = true; - } - - if (!skip_device && !CheckFormat(device, vk::Format::eR8Unorm, true, - vk::FormatFeatureFlagBits::eSampledImage | - vk::FormatFeatureFlagBits::eTransferDst)) { - LOGF("Format vk::Format::eR8Unorm cannot be used as texture\n"); - skip_device = true; - } - - if (!skip_device && !CheckFormat(device, vk::Format::eR8G8Unorm, true, - vk::FormatFeatureFlagBits::eSampledImage | - vk::FormatFeatureFlagBits::eTransferDst)) { - LOGF("Format vk::Format::eR8G8Unorm cannot be used as texture\n"); - skip_device = true; - } - - if (!skip_device && !CheckFormat(device, vk::Format::eR8G8B8A8Srgb, true, - vk::FormatFeatureFlagBits::eStorageImage | - vk::FormatFeatureFlagBits::eTransferDst)) { - LOGF("Format vk::Format::eR8G8B8A8Srgb cannot be used as texture\n"); - - if (!skip_device && !CheckFormat(device, vk::Format::eR8G8B8A8Unorm, true, - vk::FormatFeatureFlagBits::eStorageImage | - vk::FormatFeatureFlagBits::eTransferDst)) { - LOGF("Format vk::Format::eR8G8B8A8Unorm cannot be used as texture\n"); - skip_device = true; + const auto check_format = [&](vk::Format format, vk::FormatFeatureFlags features, + const char* usage) { + if (!skip_device && !CheckFormat(device, format, true, features)) { + reject(fmt::format("Format vk::Format::e{} cannot be used as {}", + vk::to_string(format), usage)); } + }; + + const auto depth_features = vk::FormatFeatureFlagBits::eDepthStencilAttachment; + const auto texture_features = + vk::FormatFeatureFlagBits::eSampledImage | vk::FormatFeatureFlagBits::eTransferDst; + const auto storage_features = + vk::FormatFeatureFlagBits::eStorageImage | vk::FormatFeatureFlagBits::eTransferDst; + + check_format(vk::Format::eD32Sfloat, depth_features, "depth buffer"); + check_format(vk::Format::eD32SfloatS8Uint, depth_features, "depth buffer"); + check_format(vk::Format::eD16Unorm, depth_features, "depth buffer"); + check_format(vk::Format::eBc3SrgbBlock, texture_features, "texture"); + check_format(vk::Format::eR8G8B8A8Srgb, texture_features, "texture"); + check_format(vk::Format::eR8Unorm, texture_features, "texture"); + check_format(vk::Format::eR8G8Unorm, texture_features, "texture"); + + if (!skip_device && + !CheckFormat(device, vk::Format::eR8G8B8A8Srgb, true, storage_features)) { + LOGF("Format vk::Format::eR8G8B8A8Srgb cannot be used as storage image\n"); + check_format(vk::Format::eR8G8B8A8Unorm, storage_features, "storage image"); } - if (!skip_device && !CheckFormat(device, vk::Format::eB8G8R8A8Srgb, true, - vk::FormatFeatureFlagBits::eStorageImage | - vk::FormatFeatureFlagBits::eTransferDst)) { - LOGF("Format vk::Format::eB8G8R8A8Srgb cannot be used as texture\n"); - - if (!skip_device && !CheckFormat(device, vk::Format::eB8G8R8A8Unorm, true, - vk::FormatFeatureFlagBits::eStorageImage | - vk::FormatFeatureFlagBits::eTransferDst)) { - LOGF("Format vk::Format::eB8G8R8A8Unorm cannot be used as texture\n"); - skip_device = true; - } + if (!skip_device && + !CheckFormat(device, vk::Format::eB8G8R8A8Srgb, true, storage_features)) { + LOGF("Format vk::Format::eB8G8R8A8Srgb cannot be used as storage image\n"); + check_format(vk::Format::eB8G8R8A8Unorm, storage_features, "storage image"); } if (!skip_device && device_properties.limits.maxSamplerAnisotropy < 16.0f) { - LOGF("maxSamplerAnisotropy < 16.0f"); - skip_device = true; + reject("maxSamplerAnisotropy < 16.0f"); } if (skip_device) { @@ -1024,11 +924,13 @@ void WindowContext::CreateVulkan() { } #endif + std::string rejected_devices; VulkanFindPhysicalDevice(graphic_ctx.instance, surface, device_extensions, surface_capabilities, - graphic_ctx.physical_device, graphic_ctx.queue_family); + graphic_ctx.physical_device, graphic_ctx.queue_family, + rejected_devices); if (graphic_ctx.physical_device == nullptr) { - EXIT("Could not find suitable device"); + EXIT("Could not find suitable device:%s", rejected_devices.c_str()); } vk::PhysicalDevicePushDescriptorProperties push_descriptor_properties {};