Vulkan Tutorial(2)

Create a (Logical) Device

这一节对应的代码文件为 03-init_device.cpp。

下一步是创建一个 VkDevice 类型的逻辑设备对象,对应于系统中的其中一个物理设备。该逻辑设备是后面用于把图形命令指示给硬件的一个关键对象。

到目前为止,我们的示例已经确定了你有多少个物理设备。示例中用于枚举设备的通用函数已确保系统中至少包含一个物理设备,否则该示例会出现判断为否的断言而终止运行。

Picking a Device

为了使程序更简单,示例中直接使用从设备枚举返回的列表中的第一个设备。你可以看到在 device 示例程序代码中,默认使用 info.gpus[0] 设备。如果系统中含有一个以上的设备,一个更复杂的程序可能需要额外的工作来决定要使用如果哪一个设备。在本教程中,示例程序都简单地假设列表中的第一个设备就能够满足示例的目的。

现在,你已经选择了一个物理设备,接下来需要创建 VkDevice 或逻辑设备对象。但要做到这一点,你还需要了解一些关于队列的知识。

Device Queues and Queue Families

不同于其他的图形 API,Vulkan 向编程人员公开了设备队列,因此编程人员可以决定使用多少个队列以及哪种类型的队列。

队列是一种抽象的机制,用于把命令提交到硬件中。后面你将会看到 Vulkan 应用程序如何建立一个存满命令的命令缓冲区,然后把这些命令提交到队列中通过GPU硬件进行异步处理。

Vulkan 根据队列在队列家族中所属的类型分配队列。为了找到一个让你感兴趣的队列的类型和特性,可以从物理设备中查询 QueueFamilyProperties:
Vulkan Tutorial(2)_第1张图片

typedef struct VkQueueFamilyProperties {
    VkQueueFlags    queueFlags;
    uint32_t        queueCount;
    uint32_t        timestampValidBits;
    VkExtent3D      minImageTransferGranularity;
} VkQueueFamilyProperties;

typedef enum VkQueueFlagBits {
    VK_QUEUE_GRAPHICS_BIT = 0x00000001,
    VK_QUEUE_COMPUTE_BIT = 0x00000002,
    VK_QUEUE_TRANSFER_BIT = 0x00000004,
    VK_QUEUE_SPARSE_BINDING_BIT = 0x00000008,
} VkQueueFlagBits;

示例程序继续执行正面的函数调用来获取队列信息︰

vkGetPhysicalDeviceQueueFamilyProperties(
    info.gpus[0], &info.queue_family_count, info.queue_props.data());

其中 info.queue_props 是一个 VkQueueFamilyProperties 类型的 vector(c++ STL) 变量。通过查看示例代码你会发现该示例遵循了在 Enumerate Devices 一节所描述的方式,其中讲解了如何获得包含 Vulkan API 的对象列表。示例中首先调用一次 vkGetPhysicalDeviceQueueFamilyProperties 函数获取计数,然后再一次调用以获取数据。

VkQueueFamilyProperties 结构体被称为”family”,是因为对于一组特定的 queueFlags,可能有很多 (queueCount) 可以用的队列。例如,在一个设置了 VK_QUEUE_GRAPHICS_BIT flag 的家族中可能有 8 个队列。

在这样一个设备上的队列和队列家族可能看起来如下图所示︰
Vulkan Tutorial(2)_第2张图片

VkQueueFlagBits 指定了每个硬件队列可以处理的工作负载的类型。例如,一个设备可以定义一个设置了 VK_QUEUE_GRAPHICS_BIT 的队列家族用于 3D 图形工作。 但是,如果同一个设备又指定了硬件执行像素块拷贝 (blits) 工作,那么可以定义另一个队列家庭,并且只需要设置 VK_QUEUE_TRANSFER_BIT。这种方式使得硬件可以并行处理图形工作以及 blit 工作任务。

你可能感兴趣的:(Vulkan)