Vulkan的传输队列系列功能和视频卡支持:条件检查是否准确?

时间:2018-09-29 22:31:03

标签: c++ specifications vulkan

我正在关注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渲染应用程序正常工作。

3 个答案:

答案 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设置为iindices.isComplete()的检查也返回true,而用于回滚的最后一个if语句现在返回false。一切似乎都正确呈现,没有问题。看来staging buffers现在正在复制到GPU上,而不是对CPU对象使用vertex buffer