Vulkan加载器接口架构(1)

Vulkan加载器接口架构

此文翻译于 https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/blob/master/loader/LoaderAndLayerInterface.md

Table of Contents

Overview

Vulkan is a layered architecture, made up of the following elements:

High Level View of Loader

The general concepts in this document are applicable to the loaders available for Windows, Linux and Android based systems.

Who Should Read This Document

这份文档主要的目标读者是Vulkan应用开发者,驱动和layer开发者,然而本文的信息对于想要深入了解Vulkan运行时 lib的人都是有帮助的。

The Loader

应用程序处于加载器的一端,是加载器直接的上层。 应用程序中加载器的另外一侧是ICD,它控制了vulkan兼容的硬件。需要谨记的一点是Vulkan兼容的硬件可以基于图形的、基于计算的,或者二者兼有。 在应用程序和ICD之间,加载器可以插入多个可选的 layers,这些layer各自提供了某些功能。

加载器负责和各种layers打交道,并负责支持多GPU及驱动程序。任何Vulkan函数最终都会访问到各个模块:加载器、layers和ICDs。加载器肩负把Vulkan函数转发到合适layers和ICDs的重责。Vulkan对象模型允许加载器想调用链中插入layers,以便layers可以在ICD被调用之前处理Vulkan函数。

此文档旨在提供在这些概念之间必需的接口的概览。

Goals of the Loader

加载器设计之初衷如下:

  1. 在用户的计算机系统上支持多个Vulkan兼容的ICD,且互相之间不影响。
  2. 支持Vulkan 层,它是可选的模块,可以被应用程序、用户或者系统设定所启用。
  3. Impact the overall performance of a Vulkan application in the lowest possible fashion.

Layers

Layers是增强Vulkan系统可选的组件。它们可以在已有的Vulkan函数从应用程序到硬件之间进行拦截、求值,甚至修改。 Layers通过libraries来实现,可以通过多种不同的方式被启用(包括应用程序的请求),在CreateInstance的时候被载入。 每一个layer可以选择hook(拦截)任何Vulkan函数,终造成vulkan函数被忽略或者增强。一个layer可以不拦截任何Vulkan函数。它可以选择拦截任何已知的的函数,或者可以选择只拦截一个函数。

layers能带来的特性案例可以包括如下几个:

  • 验证API的使用
  • 增强Vulkan API的跟踪和调试能力
  • 给应用程序的surfaces覆盖追加的内容

因为layers是可选的,你可以选择启用layers来调试你的应用程序,但是在发布产品的时候关闭任何layer。

Installable Client Drivers

Vulkan允许多个 Installable Client Drivers (ICDs) 的一个系统中共存,每一个支持一个或者多个物理设备(通过  VkPhysicalDevice 对象表示)。 加载器负责查找系统上可用的Vulkan ICDs。当给出一组可用的ICDs,加载器可以遍历所有可用的物理设备,并把这些信息返回给应用程序。

Instance Versus Device

在此文档中你可能一直看到一个非常重要的概念。很多函数,拓展和Vulkan中其他的东西都被分为两类:

  • Instance-related Objects
  • Device-related Objects
Instance-related Objects

一个Vulkan实例是一个高层次的构造,用来提供Vulkan系统层次的信息或者功能。和instance直接相关的Vulkan对象有:

  • VkInstance
  • VkPhysicalDevice

一个instance函数的定义是任何把Instance列表的其中一个作为第一个参数,或者没有参数的函数。一些Vulkan Instance函数有:

  • vkEnumerateInstanceExtensionProperties
  • vkEnumeratePhysicalDevices
  • vkCreateInstance
  • vkDestroyInstance

你可以使用vkGetInstanceProcAddr查询Vulkan实例函数。vkGetInstanceProcAddr 可以被用来查询设备或者实例的入口函数(包括核心入口函数)。 返回的函数指针对实例以及在该实例下创建的对象(包括所有的l VkDevice 对象)来说是有效的。

同样,一个实例拓展是拓展了Vulkan语言的一系列实例函数。这些将在后续小节中讨论。

Device-related Objects

一个Vulkan设备,从另外一方面讲,是一个用来关联函数和用户系统上特定物理设备的逻辑标识符。 与设备直接关联的Vulkan数据结构有:

  • VkDevice
  • VkQueue
  • VkCommandBuffer
  • Any dispatchable object that is a child of a one of the above.

一个设备函数是任何把设备对象作为第一个参数的函数。一些设备函数有:

  • vkQueueSubmit
  • vkBeginCommandBuffer
  • vkCreateEvent

你可以使用 vkGetInstanceProcAddr 或vkGetDeviceProcAddr 来查询Vulkan设备函数。 如果你选择使用vkGetInstanceProcAddr,它将在调用链上有附加的层,这将些许降低程序性能。 然而,返回的函数指针可以用在以后创建的任何设备上,只要它关联到同一个Vulkan实例上。 如果你使用 vkGetDeviceProcAddr,调用链将针对特定设备被优化,但是它将  能在查询到该函数的设备上使用。 还有,不像 vkGetInstanceProcAddrvkGetDeviceProcAddr 只能用于核心的Vulkan设备函数,或者设备拓展函数。

最佳解决方案是使用vkGetInstanceProcAddr来查询实例拓展函数,使用vkGetDeviceProcAddr来查询设备拓展函数。 参考Best Application Performance Setup 以获取更多信息。

和Instance拓展一样,一个设备拓展是一系列的拓展了Vulkan语言的Vulkan设备函数。 你可以在本文档后面有更多的了解。

Dispatch Tables and Call Chains

Vulkan使用对象模型来控制特定动作/操作的生命周期。被操作的对象一般都作为Vulkan调用的第一个参数,而且是一个可分发对象(参看Vulkan规范 2.3节 对象模型)。在底层,可分发对象的handle是一个指向数据结构的指针,数据结构反过来包含了一个由加载器维护的分发表。这个转发表包含了能够获取到这个对象的Vulkan函数的指针。

加载器维护了两种类型的分发表:

  • Instance转发表
  • vkCreateInstance调用中加载器创建的
  • 设备转发表
  • vkCreateDevice调用中加载器创建的

在此时,应用程序或者系统可以指定可选的将被包括的layers。加载器将初始化指定的layers,来为每一个Vulkan函数创建一个调用链,转发表的每一条将指向该调用链的第一个元素。故,加载器为每一个被创建的 VkInstance 建立了instance调用链,为每一个被创建的VkDevice 建立了设备调用链。

当应用程序调用一个Vulkan函数,通常这将先访问加载器的trampoline 函数。这些trampoline 函数很小、简短,能跳转到给定对象的分发表的某一条。另外,对于在instance调用链的函数,加载器有额外的函数,称为 terminator,它在所有即将启用的layers把合适的信息存放到可选的ICDs之后被调用。

Instance Call Chain Example

例如,如下的图展示了vkCreateInstance的调用链发生了什么。在初始化链之后,加载器将调用第一层的vkCreateInstance,它将再次调用加载器,这个函数将调用每一个ICD的vkCreateInstance 并保存运行结果。这允许调用链中每一个被启用的层都能基于VkInstanceCreateInfo数据结构建立自己所需的信息。

Instance Call Chain

这也强调出来加载器在使用instance调用链时必须管理好各种复杂性。如下所示,加载器的 terminator 必须在可见的多个ICD中收集或发送分类信息。这表示加载器必须获知实例层的各个拓展,以便更好的分类。

Device Call Chain Example

设备调用链是在vkCreateDevice 调用中创建的,通常较为简单,因为他们只和一个物理设备打交道,ICD也总是调用链的 terminator

Loader Device Call Chain



猜你喜欢

转载自blog.csdn.net/cloudqiu/article/details/78877884