LCOV - code coverage report
Current view: top level - xenolith/backend/vk - XLVkInstance.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 287 408 70.3 %
Date: 2024-05-12 00:16:13 Functions: 22 23 95.7 %

          Line data    Source code
       1             : /**
       2             :  Copyright (c) 2020-2022 Roman Katuntsev <sbkarr@stappler.org>
       3             :  Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
       4             : 
       5             : Permission is hereby granted, free of charge, to any person obtaining a copy
       6             : of this software and associated documentation files (the "Software"), to deal
       7             : in the Software without restriction, including without limitation the rights
       8             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       9             : copies of the Software, and to permit persons to whom the Software is
      10             : furnished to do so, subject to the following conditions:
      11             : 
      12             : The above copyright notice and this permission notice shall be included in
      13             : all copies or substantial portions of the Software.
      14             : 
      15             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      18             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      20             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      21             : THE SOFTWARE.
      22             : **/
      23             : 
      24             : #include "XLVkInstance.h"
      25             : #include "XLVkLoop.h"
      26             : #include "XLCoreDevice.h"
      27             : 
      28             : #if MODULE_XENOLITH_FONT
      29             : #include "backend/vk/XLVkFontQueue.h"
      30             : #endif
      31             : 
      32             : #if MODULE_XENOLITH_BACKEND_VKGUI
      33             : #include "XLVkGuiPlatform.h"
      34             : #endif
      35             : 
      36             : namespace STAPPLER_VERSIONIZED stappler::xenolith::vk {
      37             : 
      38          42 : SPUNUSED static VkResult s_createDebugUtilsMessengerEXT(VkInstance instance, const PFN_vkGetInstanceProcAddr getInstanceProcAddr, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pDebugMessenger) {
      39          42 :         auto func = (PFN_vkCreateDebugUtilsMessengerEXT) getInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
      40          42 :         if (func != nullptr) {
      41          42 :                 return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
      42             :         } else {
      43           0 :                 return VK_ERROR_EXTENSION_NOT_PRESENT;
      44             :         }
      45             : }
      46             : 
      47      303450 : SPUNUSED static VKAPI_ATTR VkBool32 VKAPI_CALL s_debugMessageCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
      48             :                 VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) {
      49      303450 :         if (pCallbackData->pMessageIdName && strcmp(pCallbackData->pMessageIdName, "VUID-VkSwapchainCreateInfoKHR-imageExtent-01274") == 0) {
      50             :                 // this is normal for multithreaded engine
      51           0 :                 messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
      52             :         }
      53      303450 :         if (pCallbackData->pMessageIdName && strcmp(pCallbackData->pMessageIdName, "Loader Message") == 0) {
      54      303450 :                 if (messageSeverity <= VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) {
      55      303408 :                         if (StringView(pCallbackData->pMessage).starts_with("Instance Extension: ")
      56      303408 :                                         || StringView(pCallbackData->pMessage).starts_with("Device Extension: ")) {
      57      302652 :                                 return VK_FALSE;
      58             :                         }
      59         756 :                         log::verbose("Vk-Validation-Verbose", "[", pCallbackData->pMessageIdName, "] ", pCallbackData->pMessage);
      60          42 :                 } else if (messageSeverity <= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) {
      61           0 :                         log::info("Vk-Validation-Info", "[", pCallbackData->pMessageIdName, "] ", pCallbackData->pMessage);
      62          42 :                 } else if (messageSeverity <= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
      63          42 :                         log::warn("Vk-Validation-Warning", "[", pCallbackData->pMessageIdName, "] ", pCallbackData->pMessage);
      64           0 :                 } else if (messageSeverity <= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
      65           0 :                         log::error("Vk-Validation-Error", "[", pCallbackData->pMessageIdName, "] ", pCallbackData->pMessage);
      66             :                 }
      67         798 :                 return VK_FALSE;
      68             :         } else {
      69           0 :                 if (messageSeverity < XL_VK_MIN_MESSAGE_SEVERITY) {
      70           0 :                         return VK_FALSE;
      71             :                 }
      72             : 
      73           0 :                 if (messageSeverity <= VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) {
      74           0 :                         if (StringView(pCallbackData->pMessage).starts_with("Device Extension: ")) {
      75           0 :                                 return VK_FALSE;
      76             :                         }
      77           0 :                         log::verbose("Vk-Validation-Verbose", "[",
      78           0 :                                 pCallbackData->pMessageIdName ? pCallbackData->pMessageIdName : "(null)",
      79           0 :                                 "] ", pCallbackData->pMessage);
      80           0 :                 } else if (messageSeverity <= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) {
      81           0 :                         log::info("Vk-Validation-Info", "[",
      82           0 :                                 pCallbackData->pMessageIdName ? pCallbackData->pMessageIdName : "(null)",
      83           0 :                                 "] ", pCallbackData->pMessage);
      84           0 :                 } else if (messageSeverity <= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
      85           0 :                         log::warn("Vk-Validation-Warning", "[",
      86           0 :                                 pCallbackData->pMessageIdName ? pCallbackData->pMessageIdName : "(null)",
      87           0 :                                 "] ", pCallbackData->pMessage);
      88           0 :                 } else if (messageSeverity <= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
      89           0 :                         log::error("Vk-Validation-Error", "[",
      90           0 :                                 pCallbackData->pMessageIdName ? pCallbackData->pMessageIdName : "(null)",
      91           0 :                                 "] ", pCallbackData->pMessage);
      92             :                 }
      93           0 :                 return VK_FALSE;
      94             :         }
      95             : }
      96             : 
      97          42 : Instance::Instance(VkInstance inst, const PFN_vkGetInstanceProcAddr getInstanceProcAddr, uint32_t targetVersion,
      98          42 :                 Vector<StringView> &&optionals, Dso &&vulkanModule, TerminateCallback &&terminate, PresentSupportCallback &&present, bool validationEnabled, Rc<Ref> &&userdata)
      99          42 : : core::Instance(move(vulkanModule), move(terminate), move(userdata)), InstanceTable(getInstanceProcAddr, inst),  _instance(inst)
     100          42 : , _version(targetVersion)
     101          42 : , _optionals(move(optionals))
     102         126 : , _checkPresentSupport(move(present)) {
     103          42 :         if (validationEnabled) {
     104          42 :                 VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo = { };
     105          42 :                 debugCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
     106          42 :                 debugCreateInfo.pNext = nullptr;
     107          42 :                 debugCreateInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
     108          42 :                 debugCreateInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
     109             : 
     110          42 :                 debugCreateInfo.pfnUserCallback = s_debugMessageCallback;
     111          42 :                 debugCreateInfo.pUserData = this;
     112             : 
     113          42 :                 if (s_createDebugUtilsMessengerEXT(_instance, vkGetInstanceProcAddr, &debugCreateInfo, nullptr, &debugMessenger) != VK_SUCCESS) {
     114           0 :                         log::warn("Vk", "failed to set up debug messenger!");
     115             :                 }
     116             :         }
     117             : 
     118          42 :         uint32_t deviceCount = 0;
     119          42 :         vkEnumeratePhysicalDevices(_instance, &deviceCount, nullptr);
     120             : 
     121          42 :         if (deviceCount) {
     122          42 :                 Vector<VkPhysicalDevice> devices(deviceCount);
     123          42 :                 vkEnumeratePhysicalDevices(_instance, &deviceCount, devices.data());
     124             : 
     125         168 :                 for (auto &device : devices) {
     126         126 :                         auto &it = _devices.emplace_back(getDeviceInfo(device));
     127             : 
     128         252 :                         _availableDevices.emplace_back(core::DeviceProperties{
     129         126 :                                 String(it.properties.device10.properties.deviceName),
     130         126 :                                 it.properties.device10.properties.apiVersion,
     131         126 :                                 it.properties.device10.properties.driverVersion,
     132         126 :                                 it.supportsPresentation()
     133             :                         });
     134             :                 }
     135          42 :         }
     136          42 : }
     137             : 
     138          84 : Instance::~Instance() {
     139             :         if constexpr (s_enableValidationLayers) {
     140          42 :                 if (debugMessenger != VK_NULL_HANDLE) {
     141          42 :                         vkDestroyDebugUtilsMessengerEXT(_instance, debugMessenger, nullptr);
     142             :                 }
     143             :         }
     144          42 :         vkDestroyInstance(_instance, nullptr);
     145          84 : }
     146             : 
     147          42 : Rc<core::Loop> Instance::makeLoop(core::LoopInfo &&info) const {
     148          84 :         return Rc<vk::Loop>::create(Rc<Instance>(const_cast<Instance *>(this)), move(info));
     149             : }
     150             : 
     151          42 : Rc<Device> Instance::makeDevice(const core::LoopInfo &info) const {
     152          42 :         auto data = info.platformData.cast<LoopData>().get();
     153          42 :         if (!data) {
     154           0 :                 log::error("vk::Instance", "Fail to create device: loop platform data is not defined");
     155           0 :                 return nullptr;
     156             :         }
     157             : 
     158          42 :         auto isDeviceSupported = [&] (const DeviceInfo &dev) {
     159          42 :                 if (data->deviceSupportCallback) {
     160          42 :                         if (!data->deviceSupportCallback(dev)) {
     161           0 :                                 return false;
     162             :                         }
     163             :                 } else {
     164           0 :                         if (!dev.supportsPresentation()) {
     165           0 :                                 return false;
     166             :                         }
     167             :                 }
     168          42 :                 return true;
     169          42 :         };
     170             : 
     171          42 :         auto getDeviceExtensions = [&] (const DeviceInfo &dev) {
     172          42 :                 Vector<StringView> requiredExtensions;
     173          42 :                 if (data->deviceExtensionsCallback) {
     174          21 :                         requiredExtensions = data->deviceExtensionsCallback(dev);
     175             :                 }
     176             : 
     177         126 :                 for (auto &ext : s_requiredDeviceExtensions) {
     178          84 :                         if (ext && !isPromotedExtension(dev.properties.device10.properties.apiVersion, StringView(ext))) {
     179           0 :                                 requiredExtensions.emplace_back(ext);
     180             :                         }
     181             :                 }
     182             : 
     183          84 :                 for (auto &ext : dev.optionalExtensions) {
     184          42 :                         requiredExtensions.emplace_back(ext);
     185             :                 }
     186             : 
     187         420 :                 for (auto &ext : dev.promotedExtensions) {
     188         378 :                         if (!isPromotedExtension(dev.properties.device10.properties.apiVersion, ext)) {
     189           0 :                                 requiredExtensions.emplace_back(ext);
     190             :                         }
     191             :                 }
     192             : 
     193          42 :                 return requiredExtensions;
     194           0 :         };
     195             : 
     196          42 :         auto isExtensionsSupported = [&] (const DeviceInfo &dev, const Vector<StringView> &requiredExtensions) {
     197          42 :                 if (!requiredExtensions.empty()) {
     198          42 :                         bool found = true;
     199         105 :                         for (auto &req : requiredExtensions) {
     200          63 :                                 auto iit = std::find(dev.availableExtensions.begin(), dev.availableExtensions.end(), req);
     201          63 :                                 if (iit == dev.availableExtensions.end()) {
     202           0 :                                         found = false;
     203           0 :                                         break;
     204             :                                 }
     205             :                         }
     206          42 :                         if (!found) {
     207           0 :                                 return false;
     208             :                         }
     209             :                 }
     210          42 :                 return true;
     211             :         };
     212             : 
     213          42 :         auto buildFeaturesList = [&] (const DeviceInfo &dev, DeviceInfo::Features &features) {
     214          42 :                 if (data->deviceFeaturesCallback) {
     215           0 :                         features = data->deviceFeaturesCallback(dev);
     216             :                 }
     217             : 
     218          42 :                 features.enableFromFeatures(DeviceInfo::Features::getRequired());
     219             : 
     220          42 :                 if (!dev.features.canEnable(features, dev.properties.device10.properties.apiVersion)) {
     221           0 :                         return false;
     222             :                 }
     223             : 
     224          42 :                 features.enableFromFeatures(DeviceInfo::Features::getOptional());
     225          42 :                 features.disableFromFeatures(dev.features);
     226          42 :                 features.flags = dev.features.flags;
     227          42 :                 return true;
     228          42 :         };
     229             : 
     230          42 :         if (info.deviceIdx == DefaultDevice) {
     231          42 :                 for (auto &it : _devices) {
     232          42 :                         if (!isDeviceSupported(it)) {
     233           0 :                                 continue;
     234             :                         }
     235             : 
     236          42 :                         auto requiredExtensions = getDeviceExtensions(it);
     237          42 :                         if (!isExtensionsSupported(it, requiredExtensions)) {
     238           0 :                                 continue;
     239             :                         }
     240             : 
     241          42 :                         DeviceInfo::Features targetFeatures;
     242          42 :                         if (!buildFeaturesList(it, targetFeatures)) {
     243           0 :                                 continue;
     244             :                         }
     245             : 
     246          42 :                         if (it.features.canEnable(targetFeatures, it.properties.device10.properties.apiVersion)) {
     247          84 :                                 return Rc<vk::Device>::create(this, DeviceInfo(it), targetFeatures, requiredExtensions);
     248             :                         }
     249          42 :                 }
     250           0 :         } else if (info.deviceIdx < _devices.size()) {
     251           0 :                 auto &dev = _devices[info.deviceIdx];
     252           0 :                 if (!isDeviceSupported(dev)) {
     253           0 :                         return nullptr;
     254             :                 }
     255             : 
     256           0 :                 auto requiredExtensions = getDeviceExtensions(dev);
     257           0 :                 if (!isExtensionsSupported(dev, requiredExtensions)) {
     258           0 :                         return nullptr;
     259             :                 }
     260             : 
     261           0 :                 DeviceInfo::Features targetFeatures;
     262           0 :                 if (!buildFeaturesList(dev, targetFeatures)) {
     263           0 :                         return nullptr;
     264             :                 }
     265             : 
     266           0 :                 if (dev.features.canEnable(targetFeatures, dev.properties.device10.properties.apiVersion)) {
     267           0 :                         return Rc<vk::Device>::create(this, DeviceInfo(dev), targetFeatures, requiredExtensions);
     268             :                 }
     269           0 :         }
     270           0 :         return nullptr;
     271             : }
     272             : 
     273         126 : static core::PresentMode getGlPresentMode(VkPresentModeKHR presentMode) {
     274         126 :         switch (presentMode) {
     275          42 :         case VK_PRESENT_MODE_IMMEDIATE_KHR: return core::PresentMode::Immediate; break;
     276           0 :         case VK_PRESENT_MODE_MAILBOX_KHR: return core::PresentMode::Mailbox; break;
     277          42 :         case VK_PRESENT_MODE_FIFO_KHR: return core::PresentMode::Fifo; break;
     278          42 :         case VK_PRESENT_MODE_FIFO_RELAXED_KHR: return core::PresentMode::FifoRelaxed; break;
     279           0 :         default: return core::PresentMode::Unsupported; break;
     280             :         }
     281             : }
     282             : 
     283          42 : core::SurfaceInfo Instance::getSurfaceOptions(VkSurfaceKHR surface, VkPhysicalDevice device) const {
     284          42 :         core::SurfaceInfo ret;
     285             : 
     286          42 :         uint32_t formatCount = 0;
     287          42 :         vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
     288             : 
     289          42 :         uint32_t presentModeCount = 0;
     290          42 :         vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);
     291             : 
     292          42 :         if (formatCount != 0) {
     293          42 :                 Vector<VkSurfaceFormatKHR> formats; formats.resize(formatCount);
     294             : 
     295          42 :                 vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, formats.data());
     296             : 
     297          42 :                 ret.formats.reserve(formatCount);
     298         126 :                 for (auto &it : formats) {
     299          84 :                         ret.formats.emplace_back(core::ImageFormat(it.format), core::ColorSpace(it.colorSpace));
     300             :                 }
     301          42 :         }
     302             : 
     303          42 :         if (presentModeCount != 0) {
     304          42 :                 ret.presentModes.reserve(presentModeCount);
     305          42 :                 Vector<VkPresentModeKHR> modes; modes.resize(presentModeCount);
     306             : 
     307          42 :                 vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, modes.data());
     308             : 
     309         168 :                 for (auto &it : modes) {
     310         126 :                         ret.presentModes.emplace_back(getGlPresentMode(it));
     311             :                 }
     312             : 
     313          42 :                 std::sort(ret.presentModes.begin(), ret.presentModes.end(), [&] (core::PresentMode l, core::PresentMode r) {
     314         168 :                         return toInt(l) > toInt(r);
     315             :                 });
     316          42 :         }
     317             : 
     318             :         VkSurfaceCapabilitiesKHR caps;
     319          42 :         vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &caps);
     320             : 
     321          42 :         ret.minImageCount = caps.minImageCount;
     322          42 :         ret.maxImageCount = caps.maxImageCount;
     323          42 :         ret.currentExtent = Extent2(caps.currentExtent.width, caps.currentExtent.height);
     324          42 :         ret.minImageExtent = Extent2(caps.minImageExtent.width, caps.minImageExtent.height);
     325          42 :         ret.maxImageExtent = Extent2(caps.maxImageExtent.width, caps.maxImageExtent.height);
     326          42 :         ret.maxImageArrayLayers = caps.maxImageArrayLayers;
     327          42 :         ret.supportedTransforms = core::SurfaceTransformFlags(caps.supportedTransforms);
     328          42 :         ret.currentTransform = core::SurfaceTransformFlags(caps.currentTransform);
     329          42 :         ret.supportedCompositeAlpha = core::CompositeAlphaFlags(caps.supportedCompositeAlpha);
     330          42 :         ret.supportedUsageFlags = core::ImageUsage(caps.supportedUsageFlags);
     331          84 :         return ret;
     332           0 : }
     333             : 
     334           0 : VkExtent2D Instance::getSurfaceExtent(VkSurfaceKHR surface, VkPhysicalDevice device) const {
     335             :         VkSurfaceCapabilitiesKHR capabilities;
     336           0 :         vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &capabilities);
     337           0 :         return capabilities.currentExtent;
     338             : }
     339             : 
     340          42 : VkInstance Instance::getInstance() const {
     341          42 :         return _instance;
     342             : }
     343             : 
     344             : #if MODULE_XENOLITH_FONT
     345          42 : Rc<core::Queue> Instance::makeFontQueue(StringView name) const {
     346          84 :         return Rc<FontQueue>::create(name);
     347             : }
     348             : #endif
     349             : 
     350             : #if MODULE_XENOLITH_BACKEND_VKGUI
     351          21 : Rc<xenolith::View> Instance::makeView(Application &loop, const core::Device &dev, ViewInfo &&info) const {
     352          42 :         return vk::platform::createView(loop, dev, move(info));
     353             : }
     354             : #endif
     355             : 
     356          42 : void Instance::printDevicesInfo(std::ostream &out) const {
     357          42 :         out << "\n";
     358             : 
     359         126 :         auto getDeviceTypeString = [&] (VkPhysicalDeviceType type) -> const char * {
     360         126 :                 switch (type) {
     361          42 :                 case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: return "Integrated GPU"; break;
     362          42 :                 case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: return "Discrete GPU"; break;
     363           0 :                 case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: return "Virtual GPU"; break;
     364          42 :                 case VK_PHYSICAL_DEVICE_TYPE_CPU: return "CPU"; break;
     365           0 :                 default: return "Other"; break;
     366             :                 }
     367             :                 return "Other";
     368             :         };
     369             : 
     370         168 :         for (auto &device : _devices) {
     371         126 :                 out << "\tDevice: " << device.device << " " << getDeviceTypeString(device.properties.device10.properties.deviceType)
     372         126 :                                 << ": " << device.properties.device10.properties.deviceName
     373           0 :                                 << " (API: " << getVersionDescription(device.properties.device10.properties.apiVersion)
     374         126 :                                 << ", Driver: " << getVersionDescription(device.properties.device10.properties.driverVersion) << ")\n";
     375             : 
     376         126 :                 uint32_t queueFamilyCount = 0;
     377         126 :                 vkGetPhysicalDeviceQueueFamilyProperties(device.device, &queueFamilyCount, nullptr);
     378             : 
     379         126 :                 Vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
     380         126 :                 vkGetPhysicalDeviceQueueFamilyProperties(device.device, &queueFamilyCount, queueFamilies.data());
     381             : 
     382         126 :                 int i = 0;
     383         462 :                 for (const VkQueueFamilyProperties& queueFamily : queueFamilies) {
     384         336 :                         bool empty = true;
     385         336 :                         out << "\t\t[" << i << "] Queue family; Flags: ";
     386         336 :                         if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
     387         126 :                                 if (!empty) { out << ", "; } else { empty = false; }
     388         126 :                                 out << "Graphics";
     389             :                         }
     390         336 :                         if (queueFamily.queueFlags & VK_QUEUE_COMPUTE_BIT) {
     391         210 :                                 if (!empty) { out << ", "; } else { empty = false; }
     392         210 :                                 out << "Compute";
     393             :                         }
     394         336 :                         if (queueFamily.queueFlags & VK_QUEUE_TRANSFER_BIT) {
     395         336 :                                 if (!empty) { out << ", "; } else { empty = false; }
     396         336 :                                 out << "Transfer";
     397             :                         }
     398         336 :                         if (queueFamily.queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) {
     399         294 :                                 if (!empty) { out << ", "; } else { empty = false; }
     400         294 :                                 out << "SparseBinding";
     401             :                         }
     402         336 :                         if (queueFamily.queueFlags & VK_QUEUE_PROTECTED_BIT) {
     403           0 :                                 if (!empty) { out << ", "; } else { empty = false; }
     404           0 :                                 out << "Protected";
     405             :                         }
     406             : 
     407         336 :                         VkBool32 presentSupport = _checkPresentSupport ? _checkPresentSupport(this, device.device, i) : false;
     408         336 :                         if (presentSupport) {
     409         105 :                                 if (!empty) { out << ", "; } else { empty = false; }
     410         105 :                                 out << "Present";
     411             :                         }
     412             : 
     413         336 :                         out << "; Count: " << queueFamily.queueCount << "\n";
     414         336 :                         i++;
     415             :                 }
     416         126 :                 out << device.description();
     417         126 :         }
     418          42 : }
     419             : 
     420         126 : void Instance::getDeviceFeatures(const VkPhysicalDevice &device, DeviceInfo::Features &features, ExtensionFlags flags, uint32_t api) const {
     421         126 :         void *next = nullptr;
     422             : #ifdef VK_ENABLE_BETA_EXTENSIONS
     423             :         if ((flags & ExtensionFlags::Portability) != ExtensionFlags::None) {
     424             :                 features.devicePortability.pNext = next;
     425             :                 next = &features.devicePortability;
     426             :         }
     427             : #endif
     428         126 :         features.flags = flags;
     429             : #if VK_VERSION_1_3
     430         126 :         if (api >= VK_API_VERSION_1_3) {
     431         126 :                 features.device13.pNext = next;
     432         126 :                 features.device12.pNext = &features.device13;
     433         126 :                 features.device11.pNext = &features.device12;
     434         126 :                 features.device10.pNext = &features.device11;
     435             : 
     436         126 :                 if (vkGetPhysicalDeviceFeatures2) {
     437         126 :                         vkGetPhysicalDeviceFeatures2(device, &features.device10);
     438           0 :                 } else if (vkGetPhysicalDeviceFeatures2KHR) {
     439           0 :                         vkGetPhysicalDeviceFeatures2KHR(device, &features.device10);
     440             :                 } else {
     441           0 :                         vkGetPhysicalDeviceFeatures(device, &features.device10.features);
     442             :                 }
     443             : 
     444         126 :                 features.updateFrom13();
     445             :         } else
     446             : #endif
     447           0 :         if (api >= VK_API_VERSION_1_2) {
     448           0 :                 features.device12.pNext = next;
     449           0 :                 features.device11.pNext = &features.device12;
     450           0 :                 features.device10.pNext = &features.device11;
     451             : 
     452           0 :                 if (vkGetPhysicalDeviceFeatures2) {
     453           0 :                         vkGetPhysicalDeviceFeatures2(device, &features.device10);
     454           0 :                 } else if (vkGetPhysicalDeviceFeatures2KHR) {
     455           0 :                         vkGetPhysicalDeviceFeatures2KHR(device, &features.device10);
     456             :                 } else {
     457           0 :                         vkGetPhysicalDeviceFeatures(device, &features.device10.features);
     458             :                 }
     459             : 
     460           0 :                 features.updateFrom12();
     461             :         } else {
     462           0 :                 if ((flags & ExtensionFlags::Storage16Bit) != ExtensionFlags::None) {
     463           0 :                         features.device16bitStorage.pNext = next;
     464           0 :                         next = &features.device16bitStorage;
     465             :                 }
     466           0 :                 if ((flags & ExtensionFlags::Storage8Bit) != ExtensionFlags::None) {
     467           0 :                         features.device8bitStorage.pNext = next;
     468           0 :                         next = &features.device8bitStorage;
     469             :                 }
     470           0 :                 if ((flags & ExtensionFlags::ShaderFloat16) != ExtensionFlags::None || (flags & ExtensionFlags::ShaderInt8) != ExtensionFlags::None) {
     471           0 :                         features.deviceShaderFloat16Int8.pNext = next;
     472           0 :                         next = &features.deviceShaderFloat16Int8;
     473             :                 }
     474           0 :                 if ((flags & ExtensionFlags::DescriptorIndexing) != ExtensionFlags::None) {
     475           0 :                         features.deviceDescriptorIndexing.pNext = next;
     476           0 :                         next = &features.deviceDescriptorIndexing;
     477             :                 }
     478           0 :                 if ((flags & ExtensionFlags::DeviceAddress) != ExtensionFlags::None) {
     479           0 :                         features.deviceBufferDeviceAddress.pNext = next;
     480           0 :                         next = &features.deviceBufferDeviceAddress;
     481             :                 }
     482           0 :                 features.device10.pNext = next;
     483             : 
     484           0 :                 if (vkGetPhysicalDeviceFeatures2) {
     485           0 :                         vkGetPhysicalDeviceFeatures2(device, &features.device10);
     486           0 :                 } else if (vkGetPhysicalDeviceFeatures2KHR) {
     487           0 :                         vkGetPhysicalDeviceFeatures2KHR(device, &features.device10);
     488             :                 } else {
     489           0 :                         vkGetPhysicalDeviceFeatures(device, &features.device10.features);
     490             :                 }
     491             : 
     492           0 :                 features.updateTo12(true);
     493             :         }
     494         126 : }
     495             : 
     496         126 : void Instance::getDeviceProperties(const VkPhysicalDevice &device, DeviceInfo::Properties &properties, ExtensionFlags flags, uint32_t api) const {
     497         126 :         void *next = nullptr;
     498             : #ifdef VK_ENABLE_BETA_EXTENSIONS
     499             :         if ((flags & ExtensionFlags::Portability) != ExtensionFlags::None) {
     500             :                 properties.devicePortability.pNext = next;
     501             :                 next = &properties.devicePortability;
     502             :         }
     503             : #endif
     504         126 :         if ((flags & ExtensionFlags::Maintenance3) != ExtensionFlags::None) {
     505         126 :                 properties.deviceMaintenance3.pNext = next;
     506         126 :                 next = &properties.deviceMaintenance3;
     507             :         }
     508         126 :         if ((flags & ExtensionFlags::DescriptorIndexing) != ExtensionFlags::None) {
     509         126 :                 properties.deviceDescriptorIndexing.pNext = next;
     510         126 :                 next = &properties.deviceDescriptorIndexing;
     511             :         }
     512             : 
     513         126 :         properties.device10.pNext = next;
     514             : 
     515         126 :         if (vkGetPhysicalDeviceProperties2) {
     516         126 :                 vkGetPhysicalDeviceProperties2(device, &properties.device10);
     517           0 :         } else if (vkGetPhysicalDeviceProperties2KHR) {
     518           0 :                 vkGetPhysicalDeviceProperties2KHR(device, &properties.device10);
     519             :         } else {
     520           0 :                 vkGetPhysicalDeviceProperties(device, &properties.device10.properties);
     521             :         }
     522         126 : }
     523             : 
     524         126 : DeviceInfo Instance::getDeviceInfo(VkPhysicalDevice device) const {
     525         126 :         DeviceInfo ret;
     526         126 :         uint32_t graphicsFamily = maxOf<uint32_t>();
     527         126 :         uint32_t presentFamily = maxOf<uint32_t>();
     528         126 :         uint32_t transferFamily = maxOf<uint32_t>();
     529         126 :         uint32_t computeFamily = maxOf<uint32_t>();
     530             : 
     531         126 :         uint32_t queueFamilyCount = 0;
     532         126 :         vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
     533             : 
     534         126 :         Vector<DeviceInfo::QueueFamilyInfo> queueInfo(queueFamilyCount);
     535         126 :         Vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
     536             : 
     537         126 :         vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
     538             : 
     539         126 :         int i = 0;
     540         462 :         for (const VkQueueFamilyProperties &queueFamily : queueFamilies) {
     541         336 :                 auto presentSupport = _checkPresentSupport ? _checkPresentSupport(this, device, i) : false;
     542             : 
     543         336 :                 queueInfo[i].index = i;
     544         336 :                 queueInfo[i].ops = getQueueOperations(queueFamily.queueFlags, presentSupport);
     545         336 :                 queueInfo[i].count = queueFamily.queueCount;
     546         336 :                 queueInfo[i].used = 0;
     547         336 :                 queueInfo[i].minImageTransferGranularity = queueFamily.minImageTransferGranularity;
     548         336 :                 queueInfo[i].presentSurfaceMask = presentSupport;
     549             : 
     550         336 :                 if ((queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) && graphicsFamily == maxOf<uint32_t>()) {
     551         126 :                         graphicsFamily = i;
     552             :                 }
     553             : 
     554         336 :                 if ((queueFamily.queueFlags & VK_QUEUE_TRANSFER_BIT) && transferFamily == maxOf<uint32_t>()) {
     555         126 :                         transferFamily = i;
     556             :                 }
     557             : 
     558         336 :                 if ((queueFamily.queueFlags & VK_QUEUE_COMPUTE_BIT) && computeFamily == maxOf<uint32_t>()) {
     559         126 :                         computeFamily = i;
     560             :                 }
     561             : 
     562         336 :                 if (presentSupport != 0 && presentFamily == maxOf<uint32_t>()) {
     563          63 :                         presentFamily = i;
     564             :                 }
     565             : 
     566         336 :                 i ++;
     567             :         }
     568             : 
     569             :         // try to select different families for transfer and compute (for more concurrency)
     570         126 :         if (computeFamily == graphicsFamily) {
     571         462 :                 for (auto &it : queueInfo) {
     572         336 :                         if (it.index != graphicsFamily && ((it.ops & QueueOperations::Compute) != QueueOperations::None)) {
     573          84 :                                 computeFamily = it.index;
     574             :                         }
     575             :                 }
     576             :         }
     577             : 
     578         126 :         if (transferFamily == computeFamily || transferFamily == graphicsFamily) {
     579         462 :                 for (auto &it : queueInfo) {
     580         336 :                         if (it.index != graphicsFamily && it.index != computeFamily && ((it.ops & QueueOperations::Transfer) != QueueOperations::None)) {
     581         126 :                                 transferFamily = it.index;
     582             :                         }
     583             :                 }
     584         126 :                 if (transferFamily == computeFamily || transferFamily == graphicsFamily) {
     585          84 :                         if (queueInfo[computeFamily].count >= queueInfo[graphicsFamily].count) {
     586          84 :                                 transferFamily = computeFamily;
     587             :                         } else {
     588           0 :                                 transferFamily = graphicsFamily;
     589             :                         }
     590             :                 }
     591             :         }
     592             : 
     593             :         // try to map present with graphics
     594         126 :         if (presentFamily != graphicsFamily) {
     595          63 :                 if ((queueInfo[graphicsFamily].ops & QueueOperations::Present) != QueueOperations::None) {
     596           0 :                         presentFamily = graphicsFamily;
     597             :                 }
     598             :         }
     599             : 
     600             :         // fallback when Transfer or Compute is not defined
     601         126 :         if (transferFamily == maxOf<uint32_t>()) {
     602           0 :                 transferFamily = graphicsFamily;
     603           0 :                 queueInfo[transferFamily].ops |= QueueOperations::Transfer;
     604             :         }
     605             : 
     606         126 :         if (computeFamily == maxOf<uint32_t>()) {
     607           0 :                 computeFamily = graphicsFamily;
     608             :         }
     609             : 
     610             :         uint32_t extensionCount;
     611         126 :         vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
     612             : 
     613         126 :         Vector<VkExtensionProperties> availableExtensions(extensionCount);
     614         126 :         vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());
     615             : 
     616             :         // we need only API version for now
     617             :         VkPhysicalDeviceProperties deviceProperties;
     618         126 :         vkGetPhysicalDeviceProperties(device, &deviceProperties);
     619             : 
     620             :         // find required device extensions
     621         126 :         bool notFound = false;
     622         252 :         for (auto &extensionName : s_requiredDeviceExtensions) {
     623         252 :                 if (!extensionName) {
     624         126 :                         break;
     625             :                 }
     626             : 
     627         126 :                 if (isPromotedExtension(deviceProperties.apiVersion, extensionName)) {
     628         126 :                         continue;
     629             :                 }
     630             : 
     631           0 :                 bool found = false;
     632           0 :                 for (auto &extension : availableExtensions) {
     633           0 :                         if (strcmp(extensionName, extension.extensionName) == 0) {
     634           0 :                                 found = true;
     635           0 :                                 break;
     636             :                         }
     637             :                 }
     638             : 
     639           0 :                 if (!found) {
     640             :                         if constexpr (s_printVkInfo) {
     641           0 :                                 log::verbose("Vk-Info", "Required device extension not found: %s", extensionName);
     642             :                         }
     643           0 :                         notFound = true;
     644           0 :                         break;
     645             :                 }
     646             :         }
     647             : 
     648         126 :         if (notFound) {
     649           0 :                 ret.requiredExtensionsExists = false;
     650             :         } else {
     651         126 :                 ret.requiredExtensionsExists = true;
     652             :         }
     653             : 
     654             :         // check for optionals
     655         126 :         ExtensionFlags extensionFlags = ExtensionFlags::None;
     656         126 :         Vector<StringView> enabledOptionals;
     657         126 :         Vector<StringView> promotedOptionals;
     658        1386 :         for (auto &extensionName : s_optionalDeviceExtensions) {
     659        1386 :                 if (!extensionName) {
     660         126 :                         break;
     661             :                 }
     662             : 
     663        1260 :                 checkIfExtensionAvailable(deviceProperties.apiVersion,
     664             :                                 extensionName, availableExtensions, enabledOptionals, promotedOptionals, extensionFlags);
     665             :         }
     666             : 
     667         126 :         ret.device = device;
     668         126 :         ret.graphicsFamily = queueInfo[graphicsFamily];
     669         126 :         ret.presentFamily = (presentFamily == maxOf<uint32_t>()) ? DeviceInfo::QueueFamilyInfo() : queueInfo[presentFamily];
     670         126 :         ret.transferFamily = queueInfo[transferFamily];
     671         126 :         ret.computeFamily = queueInfo[computeFamily];
     672         126 :         ret.optionalExtensions = move(enabledOptionals);
     673         126 :         ret.promotedExtensions = move(promotedOptionals);
     674             : 
     675         126 :         ret.availableExtensions.reserve(availableExtensions.size());
     676       20412 :         for (auto &it : availableExtensions) {
     677       20286 :                 ret.availableExtensions.emplace_back(it.extensionName);
     678             :         }
     679             : 
     680         126 :         getDeviceProperties(device, ret.properties, extensionFlags, deviceProperties.apiVersion);
     681         126 :         getDeviceFeatures(device, ret.features, extensionFlags, deviceProperties.apiVersion);
     682             : 
     683         126 :         auto requiredFeatures = DeviceInfo::Features::getRequired();
     684         126 :         ret.requiredFeaturesExists = ret.features.canEnable(requiredFeatures, deviceProperties.apiVersion);
     685             : 
     686         252 :         return ret;
     687         126 : }
     688             : 
     689             : }

Generated by: LCOV version 1.14