Vulkan创建逻辑设备

创建逻辑设备
在我们编写的应用程序中,逻辑设备是最重要的对象之一。逻辑设备代表真实的硬件,还代表为逻辑设备启用的所有扩展和功能,以及通过逻辑设备执行的所有操作队列。

Vulkan创建逻辑设备
使用逻辑设备可以执行典型的渲染程序工作,如创建图像和缓冲区、设置管线状态和加载着色器。逻辑设备的最重要功能是记录命令(如提交绘制调用和分配计算工作)和将命令提交给队列,命令会按照它在队列中的次序由具体硬件处理。完成上述处理过程后,我们就得到了通过提交操作计算的结果。这些结果可以是由计算着色器算出的一组值,也可以是通过绘制调用命令生成的其他数据(不一定是图像)。所有这些工作都是在逻辑设备上执行的,下面让我们来了解创建逻辑设备的方式。

准备工作
本节将使用一个自定义结构类型的变量,该自定义结构类型名为QueueInfo,下面是它的定义。

Vulkan创建逻辑设备

在这种类型的变量中,我们将会存储通过指定逻辑设备执行的队列的信息。这些数据(信息)中含有我们想要使用的队列所属家族的索引、我们想要使用的队列所属家族中含有队列的总数和与每个队列对应的家族属性。因为家族属性的数量必须与该家族中队列的数量相等,所以指定家族中含有的队列总数,就会与std::vector容器Priorities变量中元素的个数相等。
具体处理过程
(1)根据功能、限定条件、可用扩展和得到支持的操作类型,通过调用vkEnumeratePhysical Devices()函数获取可用物理设备名单,并从该名单中选择一个物理设备(请参阅“确认哪些物理设备可用”小节)。将获得的物理设备句柄,存储到一个VkPhysical Device类型的变量中,将该变量命名为physical_device。
(2)归纳想要启用的设备扩展。将想要使用的扩展的名称,存储到一个std::vector<char const*>类型的变量中,将该变量命名为desired_extensions。
(3)创建一个std::vector<VkExtensionProperties>类型的变量,将该变量命名为available_extensions。获取所有可用扩展的名单,并将该名单存储到available_extensions变量中(请参阅“检查可用的设备扩展”小节)。
(4)确保desired_extensions变量中存储的扩展名称也出现在available_extensions变量中。
(5)创建一个VkPhysicalDeviceFeatures类型的变量,将其命名为desired_features。
(6)获取得到物理设备支持的一系列功能,这些功能由physical_device变量中存储的句柄代表。
(7)确保由physical_device变量代表的物理设备支持想要使用的功能。通过检查desired_features变量存储的结构中相应成员是否被设置为1,可以查明指定物理设备是否支持想要使用的功能。清除desired_features变量存储的结构中的其他成员(将这些成员设置为0)。
(8)根据队列家族的属性(支持的操作类型),归纳想要使用的队列家族名单,这些家族用于提供队列。为每个选中的队列家族设置提供队列的数量。在队列家族中为每个队列设置优先权:由浮点型值0.0~1.0为代表(多个队列可能会拥有相同的优先权值)。创建一个std::vector容器的变量,将vector容器中元素类型设置为QueueInfo自定义类型,将该变量命名为queue_infos。
(9)创建一个std::vector<VkDeviceQueueCreateInfo>类型的变量,将其命名为queue_create_infos。为存储在queue_infos变量中的每个队列家族std::vector容器queue_create_infos,添加一个新元素。将下列值赋予这个新元素中的成员。
① 将sType成员的值设置为VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO。
② 将pNext成员的值设置为nullptr。
③ 将flags成员的值设置为0。
④ 将queueFamilyIndex成员的值设置为该队列家族的索引。
⑤ 将queueCount成员的值设置为该队列家族能够提供队列的数量。
⑥ 将pQueuePriorities成员的值设置为指向该队列家族中队列属性列表中第一个元素的指针。
(10)创建一个VkDeviceCreateInfo类型的变量,将其命名为device_create_info。将下列值赋予device_create_info变量中的各个成员。
① 将sType成员的值设置为VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO。
② 将pNext成员的值设置为nullptr。
③ 将flags成员的值设置为0。
④ 将queueCreateInfoCount成员的值设置为vector容器queue_create_infos含有元素的数量。
⑤ 将pQueueCreateInfos成员的值设置为指向vector容器queue_create_infos中第一个元素的指针。
⑥ 将enabledLayerCount成员的值设置为0。
⑦ 将ppEnabledLayerNames成员的值设置为nullptr。
⑧ 将enabledExtensionCount成员的值设置为vector容器desired_extensions含有元素的数量。
⑨ 将ppEnabledExtensionNames成员的值设置为指向vector容器desired_extensions中第一个元素的指针。
⑩ 将pEnabledFeatures成员的值设置为指向desired_features变量的指针。
(11)创建一个VkDevice类型的变量,将其命名为logical_device。
(12)调用vkCreateDevice(physical_device,&device_create_info,nullptr,&logical_device)函数。将第一个参数设置为物理设备的句柄,将第二个参数设置为指向device_create_info变量的指针,将第三个参数设置为nullptr,将第四个参数设置为指向logical_device变量的指针。
(13)通过查明调用vkCreateDevice()函数返回的值等于VK_SUCCESS,确认该函数调用操作已成功完成。

具体运行情况
要创建逻辑设备,需要先准备大量的数据。首先,应获取物理设备支持扩展的名单,并查明我们想要使用的扩展是否包含在物理设备支持扩展的名单中。与创建实例类似,我们无法使用物理设备不支持的扩展创建逻辑设备,这类操作会失败。

Vulkan创建逻辑设备
Vulkan创建逻辑设备


其次,应创建一个vector容器类型的变量,可将其命名为queue_create_infos,使用该变量存储我们想要添加到逻辑设备中的队列和队列家族的信息。该vector容器中的每个元素都应设置为VkDeviceQueueCreateInfo类型;该vector容器含有的最重要的信息,是队列家族的索引和该家族含有队列的数量;该vector容器中的每个元素都代表一个队列家族,且每个元素都应具有唯一性。
vector容器变量queue_create_infos还应含有队列的属性信息。一个家族中的每个队列都拥有不同的优先权:由浮点型值0.0~1.0为代表,较大的数值代表较高的优先权。这意味着硬件会根据队列的优先权,安排处理多个队列的次序,而且会为拥有较高优先权的队列分配更多处理时间。然而,这仅是一种意向,而不是万无一失的保证。这也不会影响其他设备中的队列。

Vulkan创建逻辑设备
vector容器变量queue_create_infos,用于为VkDeviceCreateInfo类型的变量提供信息。VkDeviceCreateInfo类型的变量用于存储为逻辑设备提供队列的家族含有队列的数量、已启用逻辑层的数量和名称、我们想要为设备启用的扩展和我们想要使用的功能。
逻辑层和扩展不是用于使设备正常运行的必要信息,但是有些扩展非常有用,如果我们想要显示通过Vulkan生成的图像,就必须启用这些扩展。

功能也不是必要信息,因为Vulkan的核心已经提供了大量的功能,使用这些功能可以生成图像和执行复杂的计算。如果我们不想启用任何功能,则可以将pEnabledFeatures成员的值设置为nullptr,或者使用被设置为0的变量为该成员赋值。然而,如果我们想要使用更高级的功能(如几何和曲面细分着色器),就需要先获取设备支持的功能名单并确认我们想要使用的功能可用,然后通过变量提供合适的指针。应禁用不必要的功能,因为某些功能会影响性能。在使用Vulkan时,我们应该只做必要的事情和使用必须使用的功能。

Vulkan创建逻辑设备
device_create_info变量用于为vkCreateDevice()函数提供数据,vkCreateDevice()函数用于创建逻辑设备。要确认调用vkCreateDevice()函数的操作成功执行,需要查明vkCreateDevice()函数的返回值是否等于VK_SUCCESS。如果该值等于VK_SUCCESS,那么创建好的逻辑设备的句柄会存储在调用vkCreateDevice()函数时,所用的最后一个参数指向的变量中。
Vulkan创建逻辑设备
Vulkan创建逻辑设备

酷客网相关文章:

赞(0)

评论 抢沙发

评论前必须登录!

 

Vulkan实战