我正在关注Joshua Shucker的Vulkan Youtube video tutorial。我目前正在观看他的第14个视频,他正在为顶点缓冲区创建辅助队列族。这集中于顶点缓冲区的暂存过程。除了我添加用于测试的cout statement
的代码外,我的代码与他的视频中的代码相同。这是队列家族的功能和结构:
struct QueueFamilyIndices {
int graphicsFamily = -1;
int transferFamily = -1;
bool isComplete() {
return (graphicsFamily >= 0 && transferFamily >= 0);
}
};
QueueFamilyIndices FindQueueFamilies( const VkPhysicalDevice* device, const VkSurfaceKHR* surface ) {
QueueFamilyIndices indices;
uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties( *device, &queueFamilyCount, nullptr );
std::vector<VkQueueFamilyProperties> queueFamilies( queueFamilyCount );
vkGetPhysicalDeviceQueueFamilyProperties( *device, &queueFamilyCount, queueFamilies.data() );
int i = 0;
for( const auto &queueFamily : queueFamilies ) {
VkBool32 presentSupport = false;
vkGetPhysicalDeviceSurfaceSupportKHR( *device, i, *surface, &presentSupport );
if( queueFamily.queueCount > 0 && (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) && presentSupport ) {
indices.graphicsFamily = i;
}
if( queueFamily.queueCount > 0 && (queueFamily.queueFlags & VK_QUEUE_TRANSFER_BIT) &&
!(queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) && presentSupport ) {
indices.transferFamily = i;
}
if( indices.isComplete() ) {
break;
}
i++;
}
if( indices.graphicsFamily >= 0 && indices.transferFamily == -1 ) {
std::cout << "Graphics family found, transfer family missing: using graphics family" << std::endl;
indices.transferFamily = indices.graphicsFamily;
}
return indices;
}
在此功能内vkGetPhysicalDeviceSurfaceSupportKHR(...)
被调用两次,因为在调用vkGetPhysicalDeviceQueueFamilyProperties(...)
来填充VkQueueFamilyProperties
结构的向量之后发现了2个队列族。
这是我的NVidia GeForce gtx 750 Ti
卡的规格,基于其队列系列的Vulkan's
规范:Vulkan:Report,如果链接随时间而变化,这里直接提供信息:
Queue family 0 queueCount 16 flags GRAPHICS_BIT COMPUTE_BIT TRANSFER_BIT SPARSE_BINDING_BIT timestampValidBits 64 minImageTransferGranularity.width 1 minImageTransferGranularity.height 1 minImageTransferGranularity.depth 1 supportsPresent 1 Queue family 1 queueCount 1 flags TRANSFER_BIT timestampValidBits 64 minImageTransferGranularity.width 1 minImageTransferGranularity.height 1 minImageTransferGranularity.depth 1 supportsPresent 0
现在,根据这些规范,它们与我的结构向量中的值一致,而我正在逐步通过调试器,将结构填充为 的值:
queueFamilies[0].queueFlags = 15;
queueFamilies[0].queueCount = 16;
queueFamilies[0].timestampValidBits = 64;
queueFamilies[0].minImageTransferGranularity = { width = 1, height = 1, depth = 1 };
queueFamilies[1].queueFlags = 4;
queueFamilies[1].queueCount = 1;
queueFamilies[1].timestampValidBits = 64;
queueFamilies[1].minImageTransferGranularity = { width = 1, height = 1, depth = 1 };
在我看来,我的卡确实支持单独的queueFamily
,特别是transferFamily
。
基于我对该支持的假设并逐步完成该功能,他有两个if语句来检查for循环中每个索引queueFamily
对象的有效条件。 if语句将返回应有的状态。我的代码可以编译并生成,没有任何错误或警告,当我没有通过调试器运行它时,它仍会渲染然后呈现三角形,并且它的退出代码为(0)。因此,代码似乎很好。但是我没有得到我至少会期望的结果。
我不确定他的代码中是否有他遗漏的错误,是否误解了我的视频卡对此Vulkan功能的支持,或者这可能是Vulkan API错误或NVidia驱动程序错误。
但是,当我逐步执行此功能时,要找出为什么未将indices.transferFamily
变量设置为i
的原因;我注意到在循环的第二次迭代中,它与transferFamilyQueue
的存在,其参数值或标志无关。导致此if语句返回false的原因是presentSupport
变量,因为它在第二次调用中被设置为0
,与上面的数据表匹配。所以输出是预期的。
然后我的问题变成:第二个if语句中的条件检查是否存在实际的实现问题?
这是我感到困惑的地方,因为我有点困惑,因为我们正在检查是否有transferQueueFamily
可用,如果有,请使用它来创建并使用stagingBuffer
复制vertex buffer(s)
从CPU到GPU的内容。从我看来,我的卡上确实有这个transferFamily
,但没有这个家庭的supportPresent
。但是,考虑时;如果您使用的是transferFamily
-transferQueue
,则不想直接present
,因为您只是将数据从CPU上的临时vertexBuffer
复制到将在GPU上使用的vertexBuffer
。所以我想知道if语句中的最终检查是否正确。如果我对Vulkan在这里的工作方式的假设不正确,请立即纠正我,因为这是我第一次尝试使Vulkan
渲染应用程序正常工作。
答案 0 :(得分:2)
没有Vulkan API或NVidia驱动程序错误。就在您的报告表中
supportsPresent 0
例如AMD似乎确实支持VK_QUEUE_TRANSFER_BIT
队列家族中的礼物,但是它纯粹是可选的(31.4。查询WSI支持):
并非所有物理设备都将包括WSI支持。在物理设备中,并非所有队列系列都支持演示。
答案 1 :(得分:1)
在搜索特定于传输的队列时,没有充分的理由检查presentSupport
。这很可能是复制粘贴错误某处。通常,您不关心图形队列以外的任何内容是否支持演示。
您这样做要使用没有 设置了图形位的传输队列,因为该队列可能对应于专用传输硬件,不会影响在图形队列上完成的工作的性能。
答案 2 :(得分:0)
在阅读了一些好的答案并完成了一些测试之后,我认为我已经找到了适合应用程序代码设计的解决方案。在整个应用程序中,此函数被其他函数调用大约4或5次。在初始化Vulkan
时调用它,在对设备选择合适的最佳设备进行评估时再次调用它,在创建逻辑设备时也调用它,依此类推。
所有这些初始调用通常仅需要queueFamily's
个计数和/或索引值,以确保具有queueFamily
的合适图形设备可用于图形处理和渲染。
但是,当调用此函数以创建任意缓冲区时,这次将其用作现有专用传输队列的临时缓冲区,我们实际上需要族队列及其所有属性。因此,要解决此问题;在检查graphicsQueue
时,我离开了最后一个条件检查以查看presentSupport
是否可用,至于当for循环迭代到下一个索引以检查专用transferQueue
时,我省略了在这种情况下,请一起检查presentSupport
。
QueueFamilyIndices FindQueueFamilies( const VkPhysicalDevice* device, const VkSurfaceKHR* surface ) {
QueueFamilyIndices indices;
uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties( *device, &queueFamilyCount, nullptr );
std::vector<VkQueueFamilyProperties> queueFamilies( queueFamilyCount );
vkGetPhysicalDeviceQueueFamilyProperties( *device, &queueFamilyCount, queueFamilies.data() );
int i = 0;
for( const auto &queueFamily : queueFamilies ) {
VkBool32 presentSupport = false;
vkGetPhysicalDeviceSurfaceSupportKHR( *device, i, *surface, &presentSupport );
if( queueFamily.queueCount > 0 && (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) && presentSupport ) {
indices.graphicsFamily = i;
}
if( queueFamily.queueCount > 0 && (queueFamily.queueFlags & VK_QUEUE_TRANSFER_BIT) &&
!(queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) /*&& presentSupport*/ ) {
indices.transferFamily = i;
}
if( indices.isComplete() ) {
break;
}
i++;
}
if( indices.graphicsFamily >= 0 && indices.transferFamily == -1 ) {
std::cout << "Graphics family found, transfer family missing: using graphics family" << std::endl;
indices.transferFamily = indices.graphicsFamily;
}
return indices;
}
现在,不仅在第二次 迭代中将indices.transferFamily
设置为i
; indices.isComplete()
的检查也返回true,而用于回滚的最后一个if语句现在返回false。一切似乎都正确呈现,没有问题。看来staging buffers
现在正在复制到GPU
上,而不是对CPU
对象使用vertex buffer
。