CJ_Notned
CJ_Notned

Reputation: 308

How to properly load Vulkan extensions?

I dont understand the behaviour of the Vulkan extension system and the loading/not loading some of them, can please somebody explain me why, when I have these required extensions:

    settings.requiredInstanceExtensions.insert(
    settings.requiredInstanceExtensions.end(),
    {
      VK_KHR_SURFACE_EXTENSION_NAME,
      VK_KHR_DISPLAY_EXTENSION_NAME,
      VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
      VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME,
      VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME
    }
  );   
       
  settings.requiredDeviceExtensions.insert(
    settings.requiredDeviceExtensions.end(),
    {
      VK_KHR_SWAPCHAIN_EXTENSION_NAME,
      VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
      VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME,
      VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME,
      VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME
    }
  );

I just check the presence of extensions during the instance creation:

  VkInstanceCreateInfo createInfo = {};
  createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
  createInfo.pApplicationInfo = &appInfo;
  createInfo.enabledLayerCount = static_cast<uint32_t>(_validation.getValidationLayersCount());
  createInfo.ppEnabledLayerNames = _validation.getValidationLayersNames();
  _settings.requiredInstanceExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);

  /// Check for available extensions.
  uint32_t extensionCount = 0;
  vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
  std::vector<VkExtensionProperties> availableExtensions(extensionCount);
  vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, availableExtensions.data());

  cerrlog.debug() << "Available extensions: " << std::endl;
  for(const auto& extension : availableExtensions) {
      cerrlog.debug() << extension.extensionName << std::endl;
  }

  createInfo.enabledExtensionCount = static_cast<uint32_t>(_settings.requiredInstanceExtensions.size());
  createInfo.ppEnabledExtensionNames = _settings.requiredInstanceExtensions.data();

  VkResult result = vkCreateInstance(&createInfo, nullptr, &_instance);
  VulkanException::throwIfNotOK("Failed to create vk instance!", result);

In similar way I check the extension suppoort for device extensions and then create it:

  VkDeviceCreateInfo createInfo = {};
  createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
  createInfo.queueCreateInfoCount = static_cast<int>(queueCreateInfos.size());
  createInfo.pQueueCreateInfos = queueCreateInfos.data();
  createInfo.pEnabledFeatures = &deviceFeatures;
  createInfo.enabledExtensionCount = static_cast<uint32_t>(_deviceExtensions.size());
  createInfo.ppEnabledExtensionNames = _deviceExtensions.data();

  if (validationEnabled) {
    createInfo.enabledLayerCount = static_cast<uint32_t>(
      validationLayers.getValidationLayersCount());
    createInfo.ppEnabledLayerNames = validationLayers.getValidationLayersNames();
  } else {
    createInfo.enabledLayerCount = 0;
  }

  VkResult result = vkCreateDevice(_physicalDevice, &createInfo, nullptr, &_device);

This will lead to the creation of the instance and also maps the vulkan core calls through this instance (even for device as it is mapped from instance). But I still need to load debug utils:

VkResult VulkanDebugLogger::CreateDebugUtilsMessengerEXT(
  VkInstance instance,
  const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
  const VkAllocationCallbacks* pAllocator,
  VkDebugUtilsMessengerEXT* pCallback
)
{
  auto func = reinterpret_cast<PFN_vkCreateDebugUtilsMessengerEXT>(
    vkGetInstanceProcAddr(instance,"vkCreateDebugUtilsMessengerEXT")
  );

  if (func != nullptr) {
    return func(instance, pCreateInfo, pAllocator, pCallback);
  }
  else {
    return VK_ERROR_EXTENSION_NOT_PRESENT;
  }
}

And also I need to load these extension:

void VulkanRenderer::loadExtensions()
{
  vkGetMemoryWin32HandleKHR = PFN_vkGetMemoryWin32HandleKHR(vkGetInstanceProcAddr(
    _instance,
    "vkGetMemoryWin32HandleKHR"
  ));

  vkGetSemaphoreWin32HandleKHR = PFN_vkGetSemaphoreWin32HandleKHR(vkGetInstanceProcAddr(
    _instance,
    "vkGetSemaphoreWin32HandleKHR"
  ));
}

As content of these extensions is not vulkan core it must be loaded manually - as I understand loading process. But why I do not need to do the same with the rest of required extensions? Namely:



I understand that these last two are probably the same but OS specific so I do not need to load other two because I am manually loading the win32 versions of them

Long story short:

1. I do not understand why e.g. vkDisplay and vkSwapChain related method calls works perfectly for me without manully mapping them through vkGetProcAdress...

OR

2. Why I need to manually load:

PFN_vkGetSomeExtensionKHR = vkGetInstanceProcAddr(instance,"vkCreateDebugUtilsMessengerEXT") vkGetInstanceProcAddr(_instance,"vkGetMemoryWin32HandleKHR") vkGetInstanceProcAddr(_instance,"vkGetSemaphoreWin32HandleKHR")

and these are not loaded automatically too... can somebody please explain me this inconsistency of necessary steps when loading extensions in Vulkan?

Upvotes: 1

Views: 3439

Answers (1)

krOoze
krOoze

Reputation: 13246

The guarantee comes from the LoaderAndLayerInterface.md document:

The loader library on Windows, Linux, Android, and macOS will export all core Vulkan and all appropriate Window System Interface (WSI) extensions. This is done to make it simpler to get started with Vulkan development.

Otherwisely, the Loader might or might not export other extension commands.

Given that new versions of Vulkan take extensions and basically accept them into the vanilla Vulkan, then those original extension commands might as well be exported. (E.g. VK_KHR_get_physical_device_properties2 is now part of Vulkan 1.1.) But I think those command exports are not guaranteed, and you should load them manually anyway.

Upvotes: 1

Related Questions