队列验证层错误:队列族索引在 pCreateInfo->pQueueCreateInfos 数组中不是唯一的
Validation Layer Error with Queues: QueueFamilyIndex is not unique within pCreateInfo->pQueueCreateInfos array
我正在创建一个 Vulkan 渲染器并设置一个 Vulkan 设备及其相应的队列。以前,由于我只创建了一个队列,因此创建队列没有任何问题,但是现在我正在创建其中的几个(一个用于图形,一个用于计算,一个用于传输),验证层在设备创建之后/期间抛出此错误:
VUID-VkDeviceCreateInfo-queueFamilyIndex-00372(ERROR / SPEC): msgNum: 0 - vkCreateDevice: pCreateInfo->pQueueCreateInfos[1].queueFamilyIndex (=0) is not unique within pCreateInfo->pQueueCreateInfos array. The Vulkan spec states: (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDeviceCreateInfo-queueFamilyIndex-00372)
Objects: 1
[0] 0x16933778a10, type: 2, name: NULL
VUID-VkDeviceCreateInfo-queueFamilyIndex-00372(ERROR / SPEC): msgNum: 0 - vkCreateDevice: pCreateInfo->pQueueCreateInfos[2].queueFamilyIndex (=0) is not unique within pCreateInfo->pQueueCreateInfos array. The Vulkan spec states: (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDeviceCreateInfo-queueFamilyIndex-00372)
Objects: 1
[0] 0x16933778a10, type: 2, name: NULL
VUID-VkDeviceCreateInfo-queueFamilyIndex-00372(ERROR / SPEC): msgNum: 0 - CreateDevice(): pCreateInfo->pQueueCreateInfos[1].queueFamilyIndex (=0) is not unique within pQueueCreateInfos. The Vulkan spec states: (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDeviceCreateInfo-queueFamilyIndex-00372)
Objects: 1
[0] 0x16933778a10, type: 3, name: NULL
VUID-VkDeviceCreateInfo-queueFamilyIndex-00372(ERROR / SPEC): msgNum: 0 - CreateDevice(): pCreateInfo->pQueueCreateInfos[2].queueFamilyIndex (=0) is not unique within pQueueCreateInfos. The Vulkan spec states: (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDeviceCreateInfo-queueFamilyIndex-00372)
Objects: 1
[0] 0x16933778a10, type: 3, name: NULL
来自vkCreateDevice的VkResult是VK_ERROR_INITIALIZATION_FAILED。
我的三个队列是这样创建的(这是非标准代码,它包装在我自己的结构中):
GraphicsQueueInfo.QueueFlag = VK_QUEUE_GRAPHICS_BIT;
GraphicsQueueInfo.QueuePriority = 1.0f;
ComputeQueueInfo.QueueFlag = VK_QUEUE_COMPUTE_BIT;
ComputeQueueInfo.QueuePriority = 1.0f;
TransferQueueInfo.QueueFlag = VK_QUEUE_TRANSFER_BIT;
TransferQueueInfo.QueuePriority = 1.0f;
QueueFlag 成员用于确定我们要从中建立的队列类型。这稍后在队列选择函数中使用(这是一个片段)
uint8 i = 0;
while (true)
{
if ((queueFamilies[i].queueCount > 0) && (queueFamilies[i].queueFlags & _QI.QueueFlag))
{
break;
}
i++;
}
QueueCreateInfo.queueFamilyIndex = i;
似乎所有队列最终都具有相同的 queueFamilyIndex(从 i 设置)并导致错误,但我不知道我是否做错了什么。
vulkan-1.dll也会在设备创建失败后调用vkGetDeviceQueue时崩溃。
在第二个块中,您将根据您找到的第一个队列_QI.QueueFlag
,使用 i 填充QueueCreateInfo.queueFamilyIndex
(我假设类型为 VkDeviceQueueCreateInfo)。
我还假设您在某种循环中调用此块,以便获取图形、计算和传输的队列。 因此,让我们假设您的块位于一个名为findQueueFamilyIndex(...)
的函数中,并且您将其称为类似的东西......
std::vector<VkDeviceQueueCreateInfo> deviceQueueInfos;
deviceQueueInfos.push_back({});
findQueueFamilyIndex(VK_QUEUE_GRAPHICS_BIT, deviceQueueInfos.back());
deviceQueueInfos.push_back({});
findQueueFamilyIndex(VK_QUEUE_COMPUTE_BIT, deviceQueueInfos.back());
deviceQueueInfos.push_back({});
findQueueFamilyIndex(VK_QUEUE_TRANSFER_BIT, deviceQueueInfos.back());
这里的问题是,您几乎肯定会在这里获得所有三个队列的相同队列系列索引,这是非法的。 每个图形队列都必须支持计算和传输操作,因此您的循环
if ((queueFamilies[i].queueCount > 0) && (queueFamilies[i].queueFlags & _QI.QueueFlag))
{
break;
}
是选取队列系列索引的不良方法。您想要的是具有给定标志的队列的队列系列索引,以及尽可能少的其他标志。 像这样:
uint32_t targetIndex = UINT32_MAX;
uint32_t targetFlags = 0xFFFFFFFF;
for (uint32_t i = 0; i < queueFamilyCount; ++i) {
// doesn't have the flag? ignore this
if (0 == (queueFamilies[i].queueFlags & _QI.QueueFlag)) {
continue;
}
// first matching queue? use it and continue
if (targetIndex == UINT32_MAX) {
targetIndex = i;
targetFlags = queueFamilies[i].queueFlags;
continue;
}
// Matching queue, but with fewer flags than the current best? Use it.
if (countBits(queueFamilies[i].queueFlags) < countBits(targetFlags)) {
targetIndex = i;
targetFlags = queueFamilies[i].queueFlags;
continue;
}
}
如果要从给定队列系列中生成 N 个队列,则必须指定该系列一次,并说需要 N 个队列。 因此,如果您希望为不同类型的工作使用多个队列,最好的方法是首先找到给定工作类型的最佳队列系列索引。 这将是除您请求的VkQueueFlagBits
数最少的那个。 例如,nVidia RTX 2080有3个队列系列。 一个专用于计算,一个专用于传输,一个支持所有 3 个。
因此,让我们假设您编写一个函数,该函数获取队列系列列表并返回给定队列的最佳系列索引:
uint32_t findBestQeueue(
VkQueueFlags desiredFlags,
const std::vector<VkQueueFamilyProperties>& queueFamilies)
{ ... }
然后你可以做的是这样的:
std::vector<VkQueueFamilyProperties> qfps;
... populate qfps using vkGetPhysicalDeviceQueueFamilyProperties ...
std::map<uint32_t, uint32_t> queueFamilyToQueueCount;
auto qfi = findBestQeueue(VK_QUEUE_TRANSFER_BIT, qfps);
queueFamilyToQueueCount[qfi] += 1;
qfi = findBestQeueue(VK_QUEUE_COMPUTE_BIT, qfps);
queueFamilyToQueueCount[qfi] += 1;
qfi = findBestQeueue(VK_QUEUE_TRANSFER_BIT, qfps);
queueFamilyToQueueCount[qfi] += 1;
现在,您有一个队列系列索引的映射,该映射显示了它们所需的队列计数。 然后,您可以将其转换为一个std::vector<VkDeviceQueueCreateInfo>
然后可用于填充VkDeviceCreateInfo
的相应成员。
请注意,这不是抓取队列的完美方法。 例如,可能只有一个队列系列和一个队列... 在这种情况下,此代码将失败,因为它从只有一个可用队列的家庭请求 3 个队列,但对于大多数硬件来说,这应该可以让您克服此特定故障。
- 为什么我需要C++中不同的排序格式来对这个USACO代码上的数组和优先级队列进行排序
- 堆栈和队列是否像C++中的数组一样传递?
- C++数组队列实现方法错误
- C++数组队列
- 如何通过 malloc 为队列数组分配内存?
- 队列数组指针 (C++)
- 链表数组(5 个队列)
- 队列验证层错误:队列族索引在 pCreateInfo->pQueueCreateInfos 数组中不是唯一的
- 如何删除在没有STL的队列中存储在数组中的第一个字符串元素
- 在队列中存储字符数组
- 无法修改数组中对象的队列
- 如何在队列中存储数组
- 为什么我会在数组队列程序中获得不希望的输出
- C++ 中的队列容器数组
- 使用链表C++数组的优先级队列
- 具有可变大小的C++全局队列数组
- 队列模拟的数组与双链表
- 从庸医(队列/堆栈)中包含的圆形数组顶部弹出一个项目
- 队列的数组实现:奇怪的输出
- 如何在C++中有效地将整个队列复制到向量/数组