如何正确加载 Vulkan 扩展?

How to properly load Vulkan extensions?

我不明白 Vulkan 扩展系统的行为以及 loading/not 加载其中的一些,当我有这些必需的扩展时,请有人解释为什么:

    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
    }
  );

我只是在实例创建期间检查扩展是否存在:

  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);

我以类似的方式检查设备扩展的扩展支持,然后创建它:

  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);

这将导致实例的创建,并通过该实例映射 vulkan 核心调用(即使是设备,因为它是从实例映射的)。但我仍然需要加载调试工具:

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;
  }
}

我还需要加载这些扩展:

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

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

由于这些扩展的内容不是 vulkan 核心,因此必须手动加载 - 据我了解加载过程。但是为什么我不需要对其余的必需扩展做同样的事情呢? 即:



我知道最后两个可能相同但 OS 具体所以我不需要加载其他两个因为我手动加载它们的 win32 版本

长话短说:

1. 我不明白为什么vkDisplay 和 vkSwapChain 相关的方法调用非常适合我,无需通过 vkGetProcAdress 手动映射它们...

2. 为什么我需要手动加载:

PFN_vkGetSomeExtensionKHR = vkGetInstanceProcAddr(实例,“vkCreateDebugUtilsMessengerEXT”) vkGetInstanceProcAddr(_instance,"vkGetMemoryWin32HandleKHR") vkGetInstanceProcAddr(_instance,"vkGetSemaphoreWin32HandleKHR")

而且这些也不会自动加载...有人可以解释一下在 Vulkan 中加载扩展时必要步骤的不一致吗?

保证来自LoaderAndLayerInterface.md文档:

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.

否则,加载程序可能会或可能不会导出其他扩展命令。

鉴于 Vulkan 的新版本采用扩展并基本上将它们接受到 vanilla Vulkan 中,那么这些原始扩展命令也可以导出。 (例如 VK_KHR_get_physical_device_properties2 现在是 Vulkan 1.1 的一部分。)但我认为这些命令导出不能保证,无论如何您都应该手动加载它们。