LCOV - code coverage report
Current view: top level - xenolith/backend/vk - XLVkPlatform.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 122 159 76.7 %
Date: 2024-05-12 00:16:13 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /**
       2             :  Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
       3             : 
       4             :  Permission is hereby granted, free of charge, to any person obtaining a copy
       5             :  of this software and associated documentation files (the "Software"), to deal
       6             :  in the Software without restriction, including without limitation the rights
       7             :  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       8             :  copies of the Software, and to permit persons to whom the Software is
       9             :  furnished to do so, subject to the following conditions:
      10             : 
      11             :  The above copyright notice and this permission notice shall be included in
      12             :  all copies or substantial portions of the Software.
      13             : 
      14             :  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      17             :  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      18             :  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      19             :  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      20             :  THE SOFTWARE.
      21             :  **/
      22             : 
      23             : #include "XLVkPlatform.h"
      24             : 
      25             : namespace STAPPLER_VERSIONIZED stappler::xenolith::vk {
      26             : 
      27             : SPUNUSED static VKAPI_ATTR VkBool32 VKAPI_CALL s_debugMessageCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
      28             :                 VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData);
      29             : 
      30             : }
      31             : 
      32             : namespace STAPPLER_VERSIONIZED stappler::xenolith::vk::platform {
      33             : 
      34             : static uint32_t s_InstanceVersion = 0;
      35             : static Vector<VkLayerProperties> s_InstanceAvailableLayers;
      36             : static Vector<VkExtensionProperties> s_InstanceAvailableExtensions;
      37             : 
      38          42 : Rc<Instance> FunctionTable::createInstance(const Callback<bool(VulkanInstanceData &, const VulkanInstanceInfo &)> &setupCb, Dso &&vulkanModule, Instance::TerminateCallback &&termCb) const {
      39          42 :         VulkanInstanceInfo info = loadInfo();
      40          42 :         VulkanInstanceData data;
      41             : 
      42          42 :         if (!prepareData(data, info)) {
      43           0 :                 return nullptr;
      44             :         }
      45             : 
      46          42 :         if (!setupCb(data, info)) {
      47           0 :                 log::warn("Vk", "VkInstance creation was aborted by client");
      48           0 :                 return nullptr;
      49             :         }
      50             : 
      51          42 :         if (!validateData(data, info)) {
      52           0 :                 return nullptr;
      53             :         }
      54             : 
      55          42 :         return doCreateInstance(data, move(vulkanModule), move(termCb));
      56          42 : }
      57             : 
      58          42 : VulkanInstanceInfo FunctionTable::loadInfo() const {
      59          42 :         VulkanInstanceInfo ret;
      60             : 
      61          42 :         if (s_InstanceVersion == 0) {
      62          21 :                 if (vkEnumerateInstanceVersion) {
      63          21 :                         vkEnumerateInstanceVersion(&s_InstanceVersion);
      64             :                 } else {
      65           0 :                         s_InstanceVersion = VK_API_VERSION_1_0;
      66             :                 }
      67             :         }
      68             : 
      69          42 :         if (s_InstanceAvailableLayers.empty()) {
      70          21 :                 uint32_t layerCount = 0;
      71          21 :                 vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
      72             : 
      73          21 :                 s_InstanceAvailableLayers.resize(layerCount);
      74          21 :                 vkEnumerateInstanceLayerProperties(&layerCount, s_InstanceAvailableLayers.data());
      75             :         }
      76             : 
      77          42 :         if (s_InstanceAvailableExtensions.empty()) {
      78          21 :                 uint32_t extensionCount = 0;
      79          21 :                 vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
      80             : 
      81          21 :                 s_InstanceAvailableExtensions.resize(extensionCount);
      82          21 :                 vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, s_InstanceAvailableExtensions.data());
      83             :         }
      84             : 
      85          42 :         ret.targetVersion = s_InstanceVersion;
      86          42 :         ret.availableLayers = s_InstanceAvailableLayers;
      87          42 :         ret.availableExtensions = s_InstanceAvailableExtensions;
      88             : 
      89          42 :         return ret;
      90             : }
      91             : 
      92          42 : bool FunctionTable::prepareData(VulkanInstanceData &data, const VulkanInstanceInfo &info) const {
      93          42 :         data.targetVulkanVersion = info.targetVersion;
      94             : 
      95          42 :         bool layerFound = false;
      96             :         if constexpr (vk::s_enableValidationLayers) {
      97          84 :                 for (const char *layerName : vk::s_validationLayers) {
      98             : 
      99         420 :                         for (const auto &layerProperties : s_InstanceAvailableLayers) {
     100         420 :                                 if (strcmp(layerName, layerProperties.layerName) == 0) {
     101          42 :                                         data.layersToEnable.emplace_back(layerName);
     102          42 :                                         layerFound = true;
     103          42 :                                         break;
     104             :                                 }
     105             :                         }
     106             : 
     107          42 :                         if (!layerFound) {
     108           0 :                                 log::error("Vk", "Validation layer not found: ", layerName);
     109             :                         }
     110             :                 }
     111             :         }
     112             : 
     113          42 :         const char *debugExt = nullptr;
     114             : 
     115         882 :         for (auto &extension : s_InstanceAvailableExtensions) {
     116             :                 if constexpr (vk::s_enableValidationLayers) {
     117         840 :                         if (strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, extension.extensionName) == 0) {
     118          42 :                                 data.extensionsToEnable.emplace_back(extension.extensionName);
     119          42 :                                 debugExt = extension.extensionName;
     120          42 :                                 continue;
     121             :                         }
     122             :                 }
     123             :         }
     124             : 
     125             :         if constexpr (vk::s_enableValidationLayers) {
     126          42 :                 if (!debugExt && layerFound) {
     127           0 :                         for (const auto &layerName : vk::s_validationLayers) {
     128             :                                 uint32_t layer_ext_count;
     129           0 :                                 vkEnumerateInstanceExtensionProperties(layerName, &layer_ext_count, nullptr);
     130           0 :                                 if (layer_ext_count == 0) {
     131           0 :                                         continue;
     132             :                                 }
     133             : 
     134           0 :                                 VkExtensionProperties layer_exts[layer_ext_count];
     135           0 :                                 vkEnumerateInstanceExtensionProperties(layerName, &layer_ext_count, layer_exts);
     136             : 
     137           0 :                                 for (auto &extension : layer_exts) {
     138           0 :                                         if (strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, extension.extensionName) == 0) {
     139           0 :                                                 data.extensionsToEnable.emplace_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
     140           0 :                                                 debugExt = extension.extensionName;
     141           0 :                                                 break;
     142             :                                         }
     143             :                                 }
     144             : 
     145           0 :                                 if (debugExt) {
     146           0 :                                         break;
     147             :                                 }
     148           0 :                         }
     149             :                 }
     150             : 
     151          42 :                 if (!debugExt) {
     152           0 :                         log::error("Vk", "Required extension not found: ", VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
     153             :                 }
     154             :         }
     155             : 
     156          42 :         return true;
     157             : }
     158             : 
     159          42 : bool FunctionTable::validateData(VulkanInstanceData &data, const VulkanInstanceInfo &info) const {
     160          42 :         bool completeExt = true;
     161          84 :         for (auto &it : vk::s_requiredExtension) {
     162          84 :                 if (!it) {
     163          42 :                         break;
     164             :                 }
     165             : 
     166         126 :                 for (auto &extension : data.extensionsToEnable) {
     167          84 :                         if (strcmp(it, extension) == 0) {
     168           0 :                                 continue;
     169             :                         }
     170             :                 }
     171             : 
     172          42 :                 bool found = false;
     173         882 :                 for (auto &extension : info.availableExtensions) {
     174         840 :                         if (strcmp(it, extension.extensionName) == 0) {
     175          42 :                                 found = true;
     176          42 :                                 data.extensionsToEnable.emplace_back(it);
     177             :                         }
     178             :                 }
     179          42 :                 if (!found) {
     180           0 :                         log::error("Vk", "Required extension not found: ", it);
     181           0 :                         completeExt = false;
     182             :                 }
     183             :         }
     184             : 
     185          42 :         if (!completeExt) {
     186           0 :                 log::error("Vk", "Not all required extensions found, fail to create VkInstance");
     187           0 :                 return false;
     188             :         }
     189             : 
     190          42 :         return true;
     191             : }
     192             : 
     193          42 : Rc<Instance> FunctionTable::doCreateInstance(VulkanInstanceData &data, Dso &&vulkanModule, Instance::TerminateCallback &&cb) const {
     194          42 :         Vector<StringView> enabledOptionals;
     195          42 :         for (auto &opt : s_optionalExtension) {
     196          42 :                 if (!opt) {
     197          42 :                         break;
     198             :                 }
     199           0 :                 bool found = false;
     200           0 :                 for (auto &it : data.extensionsToEnable) {
     201           0 :                         if (strcmp(it, opt) == 0) {
     202           0 :                                 enabledOptionals.emplace_back(StringView(opt));
     203           0 :                                 found = true;
     204           0 :                                 break;
     205             :                         }
     206             :                 }
     207           0 :                 if (!found) {
     208           0 :                         data.extensionsToEnable.emplace_back(opt);
     209             :                 }
     210             :         }
     211             : 
     212          42 :         const char *debugExt = nullptr;
     213          42 :         for (auto &it : data.extensionsToEnable) {
     214          42 :                 if (strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, it) == 0) {
     215          42 :                         debugExt = it;
     216          42 :                         break;
     217             :                 }
     218             :         }
     219             : 
     220          42 :         bool validationEnabled = false;
     221          84 :         for (auto &v : s_validationLayers) {
     222          42 :                 for (auto &it : data.layersToEnable) {
     223          42 :                         if (strcmp(it, v) == 0) {
     224          42 :                                 validationEnabled = true;
     225          42 :                                 break;
     226             :                         }
     227             :                 }
     228             :         }
     229             : 
     230          42 :         VkInstance instance = VK_NULL_HANDLE;
     231             : 
     232          42 :         VkApplicationInfo appInfo{}; vk::sanitizeVkStruct(appInfo);
     233          42 :         appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
     234          42 :         appInfo.pNext = nullptr;
     235          42 :         appInfo.pApplicationName = data.applicationName.data();
     236          42 :         appInfo.applicationVersion = XL_MAKE_API_VERSION(data.applicationVersion);
     237          42 :         appInfo.pEngineName = xenolith::platform::name();
     238          42 :         appInfo.engineVersion = xenolith::platform::version();
     239          42 :         appInfo.apiVersion = data.targetVulkanVersion;
     240             : 
     241          42 :         VkInstanceCreateInfo createInfo{}; vk::sanitizeVkStruct(createInfo);
     242          42 :         createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
     243          42 :         createInfo.pNext = nullptr;
     244          42 :         createInfo.flags = 0;
     245          42 :         createInfo.pApplicationInfo = &appInfo;
     246             : 
     247          42 :         createInfo.enabledExtensionCount = data.extensionsToEnable.size();
     248          42 :         createInfo.ppEnabledExtensionNames = data.extensionsToEnable.data();
     249             : 
     250          42 :         enum VkResult ret = VK_SUCCESS;
     251          42 :         if (validationEnabled) {
     252          42 :                 VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo = {};
     253          42 :                 debugCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
     254          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;
     255          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;
     256          42 :                 debugCreateInfo.pfnUserCallback = s_debugMessageCallback;
     257          42 :                 createInfo.pNext = &debugCreateInfo;
     258             :         } else{
     259           0 :                 createInfo.pNext = nullptr;
     260             :         }
     261             : 
     262          42 :         createInfo.enabledLayerCount = data.layersToEnable.size();
     263          42 :         createInfo.ppEnabledLayerNames = data.layersToEnable.data();
     264          42 :         ret = vkCreateInstance(&createInfo, nullptr, &instance);
     265             : 
     266          42 :         if (ret != VK_SUCCESS) {
     267           0 :                 log::error("Vk", "Fail to create Vulkan instance");
     268           0 :                 return nullptr;
     269             :         }
     270             : 
     271          42 :         auto vkInstance = Rc<vk::Instance>::alloc(instance, vkGetInstanceProcAddr, data.targetVulkanVersion, move(enabledOptionals),
     272          84 :                         move(vulkanModule), move(cb), move(data.checkPresentationSupport), validationEnabled && (debugExt != nullptr), move(data.userdata));
     273             : 
     274             :         if constexpr (vk::s_printVkInfo) {
     275          42 :                 StringStream out;
     276          42 :                 out << "\n\tVulkan: " << getVersionDescription(s_InstanceVersion) << "\n\tLayers:\n";
     277         462 :                 for (const auto &layerProperties : s_InstanceAvailableLayers) {
     278         420 :                         out << "\t\t" << layerProperties.layerName << " ("
     279         420 :                                         << getVersionDescription(layerProperties.specVersion) << "/"
     280         420 :                                         << getVersionDescription(layerProperties.implementationVersion)
     281         420 :                                         << ")\t - " << layerProperties.description << "\n";
     282             :                 }
     283             : 
     284          42 :                 out << "\tExtensions:\n";
     285         882 :                 for (const auto &extension : s_InstanceAvailableExtensions) {
     286         840 :                         out << "\t\t" << extension.extensionName << ": " << getVersionDescription(extension.specVersion) << "\n";
     287             :                 }
     288             : 
     289          42 :                 vkInstance->printDevicesInfo(out);
     290             : 
     291          42 :                 log::verbose("Vk-Info", out.str());
     292          42 :         }
     293             : 
     294          42 :         return vkInstance;
     295          42 : }
     296             : 
     297             : }

Generated by: LCOV version 1.14