VK_LUNARG_direct_driver_loading

添加一个扩展,允许应用程序在实例创建期间向加载器提供驱动程序。

1. 问题陈述

有几种用例导致应用程序希望自带驱动程序。在许多 Web 浏览器中,添加备用 CPU 驱动程序对于支持不支持 Vulkan 的硬件是必要的,并且对于可能没有硬件可用的测试基础设施也是必要的。虽然目前有几种桌面 Vulkan 加载器机制允许应用程序提供驱动程序,但它们都存在各种缺点。下面详细介绍了一个不全面的列表。

  • 有些需要运行安装程序。这需要卸载程序,并使驱动程序对系统或用户“全局化”。

  • 它们可能需要提升的权限才能使用,例如使用安装程序,或者在以提升的权限运行时会导致解决方案失败,例如使用环境变量。

2. 当前解决方案空间

  • 安装到操作系统特定位置

    1. 需要运行显式安装程序和卸载程序

    2. 对所有应用程序全局

    3. 在大多数情况下需要提升的权限

  • 环境变量

    1. 由于安全问题,在以提升的权限运行时禁用

    2. 设置繁琐,因为它们需要驱动程序清单的完整路径

  • MacOS 包 - 允许将 .dylib 放置在可重定位的包中,加载器知道如何在其中查找

    1. 不适用于任何其他平台

  • 在当前工作目录中查找

    1. 当以提升的权限运行时禁用,因为这是一种攻击媒介

3. 提议

VK_LUNARG_direct_driver_loading 扩展了 VkInstanceCreateInfo 的 pNext 链,以提供一个结构列表,其中包含加载器加载驱动程序所需的信息。这是通过提供驱动程序的 vkGetInstanceProcAddr 实现的,绕过了加载器使用系统动态链接器加载驱动程序函数的需求。

该扩展还允许应用程序专门使用提供的驱动程序,因此不会加载系统上找到的任何驱动程序。

这满足了要求

  • 与所有其他正在运行的进程隔离。

  • 无需安装。

  • 当应用程序以提升的权限运行时有效。

该扩展的目的是在桌面 Vulkan 加载器中实现。

typedef struct VkDirectDriverLoadingInfoLUNARG {
    VkStructureType                         sType;
    const void*                             pNext;
    VkDirectDriverLoadingFlagsLUNARG        flags;
    PFN_vkGetInstanceProcAddr               pfnGetInstanceProcAddr;
} VkDirectDriverLoadingInfoLUNARG;

typedef struct VkDirectDriverLoadingListLUNARG {
    VkStructureType                         sType;
    const void*                             pNext;
    VkDirectDriverLoadingModeLUNARG         mode;
    uint32_t                                driverCount;
    const VkDirectDriverLoadingInfoLUNARG*  pDrivers;
} VkDirectDriverLoadingListLUNARG;

typedef enum VkDirectDriverLoadingModeLUNARG {
    VK_DIRECT_DRIVER_LOADING_MODE_EXCLUSIVE_LUNARG = 0,
    VK_DIRECT_DRIVER_LOADING_MODE_INCLUSIVE_LUNARG = 1,
    VK_DIRECT_DRIVER_LOADING_MODE_MAX_ENUM_LUNARG = 0x7FFFFFFF
} VkDirectDriverLoadingModeLUNARG;

VkDirectDriverLoadingModeLUNARG 允许应用程序选择仅加载它们提供的驱动程序,还是将它们提供的驱动程序与 Vulkan 加载器在系统上找到的所有驱动程序一起加载。

此扩展存在已知缺陷。当应用程序查询实例扩展列表时,无法向 Vulkan 加载器提供应用程序提供的驱动程序列表,以将驱动程序的扩展与系统上驱动程序和隐式层支持的扩展相结合。作为一种解决方法,应用程序可以从提供的驱动程序加载 vkEnumerateInstanceExtensionProperties 入口点,以获取它们的扩展列表。

当所有以下条件都为真时,此解决方法存在已知缺陷

  1. 应用程序使用 VK_LUNARG_direct_driver_loading 来添加驱动程序。

  2. 一个层(将被启用)在调用 vkEnumerateInstanceExtensionProperties 入口点期间过滤掉不支持的扩展。

  3. 应用程序在 VkInstanceCreateInfo 中启用了应用程序提供的驱动程序支持但层不支持的实例扩展。

由于应用程序直接调用驱动程序的 vkEnumerateInstanceExtensionProperties,而不是加载程序的,这会阻止层修改扩展列表。由于层将无法过滤掉不支持的实例扩展,该层可能无法工作、在其他地方导致错误或崩溃。

4. 示例用法

此示例展示了典型的用法,其中提供的驱动程序应该是唯一找到的驱动程序。它使用 VK_DIRECT_DRIVER_LOADING_MODE_EXCLUSIVE_LUNARG 来防止加载程序加载系统上的任何驱动程序,这对于在测试条件下运行时很有用。

VkDirectDriverLoadingInfoLUNARG app_provided_driver{};
app_provided_driver.sType = VK_STRUCTURE_TYPE_DIRECT_DRIVER_LOADING_INFO_LUNARG;
app_provided_driver.pfnGetInstanceProcAddr = /* address of drivers function pointer*/

VkDirectDriverLoadingListLUNARG direct_driver_loading{};
direct_driver_loading.sType = VK_STRUCTURE_TYPE_DIRECT_DRIVER_LOADING_LIST_LUNARG;
direct_driver_loading.mode = VK_DIRECT_DRIVER_LOADING_MODE_EXCLUSIVE_LUNARG; // Do not load any other drivers
direct_driver_loading.driverCount = 1;
direct_driver_loading.pDrivers = &app_provided_driver;

VkInstanceCreateInfo instance_info{};
instance_info.pNext = &direct_driver_loading;

vkCreateInstance(&instance_info, NULL, inst);

5. 问题

5.1. 已解决:全局函数不可扩展

由于此提案允许添加驱动程序,并且 vkEnumerateInstanceExtensionProperties 返回系统上驱动程序支持的扩展列表,因此应用程序必须“知道”所提供的驱动程序支持哪些扩展,或者直接查询它们,然后在 VkInstanceCreateInfo 中手动启用这些扩展。虽然对于大多数用例来说,这是一个足够的解决方案,但当存在修改实例扩展列表的层时,它会产生一个边缘情况。从根本上说,这是扩展枚举和实例创建设计的问题。虽然可以向此扩展添加解决此问题的功能,但最好使用其自身的扩展来解决,因为实例创建存在比此扩展所能解决的更多问题。

5.2. 已解决:此扩展是否也应处理层加载?

否,层需要更多信息才能让加载程序正确处理,并且具有全局函数不可扩展的相同缺陷。

5.3. 已解决:驱动程序是否实现此扩展?

否,这将由 Vulkan 加载器实现。

5.4. 已解决:驱动程序需要进行哪些更改才能允许在此扩展中使用?

部分需要,驱动程序今天不需要修改即可工作。但是,为了支持 Loader-ICD 接口的所有功能,它们需要支持“Loader-ICD 接口版本 7”。此版本要求可以通过 vkGetInstanceProcAddr 查询 Loader-ICD 接口中所有当前导出的入口点,这是一个简单的添加。

5.5. 已解决:期望此扩展使用哪种类型的驱动程序?

此扩展旨在与非硬件驱动程序一起使用,例如 lavapipe 和 swiftshader 等软件实现,以及 MoltenVK 等 API 转换层。明确不希望并且强烈不鼓励将此扩展与硬件驱动程序一起使用,因为硬件驱动程序需要操作系统和其他必须安装的系统组件的支持。此外,硬件驱动程序的内核组件可能会在版本之间发生变化,导致更新后任何用户模式组件都无法使用。