Vulkan将设备划分为两种形式:逻辑设备和物理设备:
- 物理设备(Physical device):物理设备表示一个独立的物理硬件,它可能包括一个GPU,以及其他硬件组成部分,在一起构成了任务的分发工作系统。对于一个简单的系统来说,物理设备可以被认为是一个实际的GPU单元。
- 逻辑设备(Logical device):逻辑设备,即实际设备在应用程序中的表现形式。
物理设备
OpenGL并不会暴露物理设备,它将物理设备完全隐藏在幕后使用。而另一方面,Vulkan则直接向应用程序端暴露了系统的实际运算设备(或者就是GPU)。这样应用程序就可以直接枚举当前系统的所有物理设备了。
本文我们需要添加一个新的自定义类,即VulkanDevice。这个类的实现代码参见源文件VulkanDevice.h/.cpp
。它负责管理物理设备(VkPhysicalDevice)以及逻辑设备(VkDevice)。此外,它也负责管理物理设备中的队列族。
以下给出了VulkanDevice类的声明部分。读者可以直接阅读源代码头文件中的声明部分来了解完整的实现过程:
1.枚举物理设备
如果要建立和物理设备的连接,应用程序需要首先枚举所有的设备。物理设备的目录过程中会列出Vulkan所支持的实际设备的数量,它们都是当前系统中可用的。我们通过调用函数vkEnumeratePhysicalDevices()来取得物理设备的列表。
以下给出这个API函数的语法:
这个API函数的相关参数说明见表所示。
这个API被封装在Application类的函数enumeratePhysicalDevices当中。它会返回当前系统中可用的物理设备对象的列表:
如图所示为当前系统中枚举物理设备,并关联到VkInstance对象的过程。
2.查询物理设备的扩展
物理设备的扩展查询和实例的查询是类似的。对于每一个实例层的属性(VkLayer-Properties)来说,都会存在对应的物理设备可以查询到的扩展属性,这里会用到函数vkEnumerateDeviceExtensionProperties()。
以下给出了这个API的语法:
这个API的参数说明见表所示。
查询设备相关的扩展属性的过程,与查询实例相关的属性的过程也是非常类似的。下面给出了这个函数的实现代码:
3.获取物理设备的属性
我们可以使用函数vkGetPhysicalDeviceProperties()获取物理设备的属性;所获取的属性被保存到结构体VkPhysicalDeviceProperties当中。以下给出了这一过程的语法:
vkGetPhysicalDeviceMemoryProperties的参数说明见表所示。
4.查询物理设备的内存属性
单一的物理设备可能有多种不同的内存类型,它们的属性之间可能还存在着更多的差异。因此应用程序非常有必要查询和获取内存的特性,然后根据程序逻辑以及资源类型的不同,执行更好的资源分配策略。下面的函数就是用来获取物理设备内存属性的,它的语法如下:
vkGetPhysicalDeviceMemoryProperties函数的参数说明见表所示。
逻辑设备
逻辑设备是物理设备的一种表示方式,它主要用在应用程序端,属于物理设备在用户层的代理视图。举例来说,物理设备可能包含了三种队列:图形、计算和传输。但是逻辑设备创建的时候,可以只关联一个单独的队列(比如图形),这样我们就可以很方便地向队列提交指令缓存了。
1.创建逻辑设备
逻辑设备是通过VkDevice来表现的,它的创建需要通过函数vkCreateDevice来完成。以下给出了函数的语法:
这个函数的参数说明见表所示。
这个函数中用到了VkDeviceCreateInfo结构体对象(deviceInfo),它包含了有关逻辑设备对象创建所需的一些必要参数信息。例如,它包含了层的名称(注意这个参数已经被废弃,仅为了保持向前兼容性而保留),以及扩展的名称,可以在设备上启用。此外,它还设置了需要创建和关联的队列。在本章的例子中,我们只对图形绘制操作感兴趣,因此我们需要得到对应的队列句柄(graphicsQueueIndex),这个队列只负责实现各种绘制功能。换句话说,我们只需要得到图形队列的句柄即可。
队列的信息包含在VkDeviceQueueCreateInfo结构体对象queueInfo当中。当我们创建了逻辑设备之时,同时也会根据结构体的设置自动创建与它关联的队列。如果读者希望了解更多有关队列的内容,包括如何获取图形队列的索引,队列的创建过程等,参考酷客教程中队列和队列族。
VulkanDevice::createDevice
是一个用户自定义的方法,可以创建新的逻辑设备对象。以下给出了它的实现过程:
2.宿主机端的等待
如果一个设备的队列中一直有工作在执行,那么我们说这个设备是激活状态。如果队列中没有需要执行的指令缓存,那么设备将处于空闲状态。我们在宿主机端通过函数vkDeviceWaitIdle来等待逻辑设备的所有队列进入空闲状态。这个函数的参数就是逻辑设备对象的句柄,我们将检查这个设备的空闲状况。函数的语法如下:
VkResult vkDeviceWaitIdle(VkDevice device);
3. 设备丢失
当逻辑设备(VKDevice)和物理设备(VKPhysicalDevice)处于工作状态时,因为某个特殊的原因——例如硬件故障、设备错误、执行超时、电源管理事件,或者一些特殊的系统事件,可能导致设备丢失。此时指令缓存的延迟执行可能会失败。
如果物理设备丢失,那么创建逻辑设备对象(VKDevice)的过程也会失败,同时返回VK_ERROR_DEVICE_LOST。如果逻辑设备丢失,那么某些指令使用时会返回VK_ERROR_DEVICE_LOST。但是对应的物理设备并没有受到影响,因此也就不会自动重置该逻辑设备的丢失状态,不过这种丢失状态只是针对当前逻辑设备对象(VKDevice)的,并不会影响到其他激活的逻辑设备对象。
酷客网相关文章:
评论前必须登录!
注册