队列族

之前提到,Vulkan的几乎所有操作,从绘制到加载纹理都需要将操作指令提交给一个队列,然后才能执行。Vulkan有多种不同类型的队列,它们属于不同的队列族,每个队列族的队列只允许执行特定的一部分指令。比如,可能存在只允许执行计算相关指令的队列族和只允许执行内存传输相关指令的队列族。

我们需要检测设备支持的队列族,以及它们中哪些支持我们需要使用的指令。为了完成这一目的,我们添加了一个叫做findQueueFamilies的函数,这一函数会查找出满足我们需求的队列族。目前而言,我们需要的队列族只需要支持图形指令即可,但在之后的章节,我们可能会有更多的需求。

这一函数会返回满足需求得队列族的索引。这里,我们使用了一个结构体来作为函数返回结果的类型,索引-1表示没有找到满足需求的队列族:

struct QueueFamilyIndices {
    int graphicsFamily = -1;

    bool isComplete() {
        return graphicsFamily >= 0;
    }
};

接下来,我们实现findQueueFamilies函数:

QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) {
    QueueFamilyIndices indices;

        ...

    return indices;
}

我们首先获取设备的队列族个数,然后分配数组存储队列族的VkQueueFamilyProperties对象:

uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);

std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());

VkQueueFamilyProperties结构体包含了队列族的很多信息,比如支持的操作类型,该队列族可以创建的队列个数。在这里,我们需要找到一个支持VK_QUEUE_GRAPHICS_BIT的队列族。

int i = 0;
for (const auto& queueFamily : queueFamilies) {
    if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
        indices.graphicsFamily = i;
    }

    if (indices.isComplete()) {
        break;
    }

    i++;
}

现在,我们可以在isDeviceSuitable函数中调用它来确保我们选择的设备可以执行我们需要的指令:

bool isDeviceSuitable(VkPhysicalDevice device) {
    QueueFamilyIndices indices = findQueueFamilies(device);

    return indices.isComplete();
}

太棒了!我们已经完成了查找我们需要的物理设备这一工作!接下来,让我们创建逻辑设备来使用它!

本章节代码:

C++:

https://vulkan-tutorial.com/code/03_physical_device_selection.cpp