Vulkan【4】创建一个逻辑设备

创建一个逻辑设备

本节的代码是 03-init_device.cpp

下一步是创建一个VkDevice逻辑设备对象,它对应于系统上的一个物理设备。逻辑设备是稍后用于将图形命令定向到硬件的关键对象。

到目前为止,我们的示例已经确定了你有多少物理设备。列举这些设备的示例工具函数确保了至少有一个设备,否则它会以不正确的断言停止。

选择一个设备

为了使事情变得简单,示例只从设备枚举返回的列表中取出第一个设备。你可以在“初始化设备”示例中看到它使用info.gpus[0]。一个更复杂的程序可能需要额外的工作来决定如果有不止一个设备时要使用哪个。在这里,我们假设列表上的第一个设备足以满足本示例。

现在您已经选择了一个物理设备,您需要创建VkDevice或逻辑设备对象。但是要做到这一点,您需要提供关于队列的一些信息。

设备队列和队列家族

与其他图形api不同,Vulkan将设备队列暴露给程序员,这样程序员就可以决定要使用多少队列以及要使用什么样的队列。

队列是用来向硬件提交命令的抽象机制。稍后您将看到一个Vulkan应用程序如何构建一个充满命令的命令缓冲区,然后将它们提交到一个队列中,以便由GPU硬件进行异步处理。

Vulkan将队列按照它们的类型排列成队列家族。为了找到您感兴趣的队列的类型和特征,您可以从物理设备查询QueueFamilyProperties:

这里写图片描述

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。
您可以检查样例代码,以查看样例遵循枚举设备中描述的模式,解释如何使用Vulkan API获取对象列表。它调用vkGetPhysicalDeviceQueueFamilyProperties来获得计数,并再次调用它来获取数据。

VkQueueFamilyProperties结构被称为“家族”,因为可能有许多(queueCount)数量的队列,每个队列有一组特定的queueFlags。例如,在一个拥有VK_QUEUE_GRAPHICS_BIT集的家族中可能有8个队列。

在这样的设备上的队列和队列家族可能看起来像:

这里写图片描述

VkQueueFlagBits指示每个硬件队列可以处理的工作负载类型。例如,一个设备可能会有个定义为VK_QUEUE_GRAPHICS_BIT的队列家族,来处理3D图形工作。但是,如果同一设备有专门的硬件来做像素块拷贝(blits),它可能会定义另一个VK_QUEUE_TRANSFER_BIT队列家族。这使得硬件可以让blit的工作负载和图形处理工作负载并行处理。

请注意,还有一个用于计算操作的队列类型,本教程中没有介绍这一类型。

一些简单的GPU硬件可能只有一个队列家族,但队列类的flag却被设置了多种:

这里写图片描述

现在,假设示例程序只针对绘制简单的图形,所以他们只需要查找图形位:

bool found = false;
for (unsigned int i = 0; i < info.queue_family_count; i++) {
    if (info.queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
        queue_info.queueFamilyIndex = i;
        found = true;
        break;
    }
}

重要的是要注意,队列家族没有用句柄表示,而是用索引代替。

一旦您选择了一个队列家族索引,您就可以填充其余的结构:

float queue_priorities[1] = {0.0};
queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue_info.pNext = NULL;
queue_info.queueCount = 1;
queue_info.pQueuePriorities = queue_priorities;

如果有超过一个队列,更复杂的程序可能希望在多个队列上提交图形命令。但是由于样本很简单,你只需要在这里要求一个。因为只有一个队列,所以在queue_priorities[]中放置的值并不重要。

创建逻辑设备

随着队列问题的解决,创建逻辑设备非常简单:

VkDeviceCreateInfo device_info = {};
device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
device_info.pNext = NULL;
device_info.queueCreateInfoCount = 1;
device_info.pQueueCreateInfos = &queue_info;
device_info.enabledExtensionCount = 0;
device_info.ppEnabledExtensionNames = NULL;
device_info.enabledLayerCount = 0;
device_info.ppEnabledLayerNames = NULL;
device_info.pEnabledFeatures = NULL;

VkDevice device;
VkResult res = vkCreateDevice(info.gpus[0], &device_info, NULL, &device);
assert(res == VK_SUCCESS);

在本教程的这一点上,您不需要过多地担心扩展。您将很快获得使用扩展的机会。

至于层,设备层最近在Vulkan中被弃用,所以在创建设备时,不应该指定任何层。

现在您已经有了一个设备,您已经准备好了通过创建一个命令缓冲区来准备它接受图形命令。

© Copyright 2016 LunarG, Inc

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值