【问题标题】:How to properly load Vulkan extensions?如何正确加载 Vulkan 扩展?
【发布时间】:2020-11-04 16:34:24
【问题描述】:

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

    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 核心,因此必须手动加载 - 据我了解加载过程。但是为什么我不需要对其余所需的扩展做同样的事情呢? 即:

  • 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
  • VK_KHR_SWAPCHAIN_EXTENSION_NAME

  • VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME
  • VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME

我知道最后两个可能相同,但特定于操作系统,所以我不需要加载其他两个,因为我手动加载它们的 win32 版本

  • VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME
  • VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME

长话短说:

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

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

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

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

【问题讨论】:

    标签: vulkan


    【解决方案1】:

    保证来自LoaderAndLayerInterface.md文档:

    Windows、Linux、Android 和 macOS 上的加载程序库将导出所有核心 Vulkan 和所有适当的窗口系统接口 (WSI) 扩展。这样做是为了更轻松地开始 Vulkan 开发。

    否则,加载器可能会也可能不会导出其他扩展命令。

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

    【讨论】:

    • 因此,如果我理解您并以正确的方式链接,我必须依靠我需要的扩展在我的平台上导出的事实,或者以首选方式我应该调用 vkGetInstanceProcAddr(_instance,"vkGetSomeExtension")对于我将在我的应用程序中使用的所有扩展。 - 但它也适用于 VK_KHR_SWAPCHAIN_EXTENSION_NAME 和 VK_KHR_SURFACE_EXTENSION_NAME 扩展,我从未在任何 vulkan 示例中看到要专门导出?
    • @CJ_Notned 我们的想法是,对于初学者,您可以获得所有核心 Vulkan 命令(直到支持的版本)和基本 WSI(VK_KHR_surfaceVK_KHR_*_surfaceVK_KHR_swapchain)。您可以通过 env 使用调试工具(因此无需直接使用扩展)。这就是“hello cube”应用程序和此类实验所需的一切。然后就是你想钻多深的兔子洞了。如果您觉得您受到调用开销的限制,那么最好对所有设备命令使用vkGetDeviceProcAddr。或者甚至可以使用 Volk 手动加载所有内容。
    猜你喜欢
    • 2014-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多