samedi 29 septembre 2018

Vulkan's queue family for transfer capabilities for video card support. Are the condition checks accurate?

I am following this Vulkan Youtube video tutorial by Joshua Shucker. I'm currently on his 14th video where he is working on creating a secondary queue family for the vertex buffer. My code matches that of his in his video except that of a cout statement in which I added for testing. Here is the function:

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;
}

Within this function vkGetPhysicalDeviceSurfaceSupportKHR(...) is being called twice as there have been 2 queue families found after vkGetPhysicalDeviceQueueFamilyProperties(...) has been called to populate the vector of VkQueueFamilyProperties structures. Here is the specs for my NVidia GeForce gtx 750 Ti card based on Vulkan's specifications for its queue families: Vulkan:Report and in case the link changes over time here is the information directly:

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 

Now according to these specs which coincide with the values in my vector of structs while I'm stepping through the debugger my structures are populated with the values of:

 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 };

So this appears to me that my card does support a separate queueFamily specifically the transferFamily.

Based on my assumption of this support and stepping through this function he has two if statements to check for valid conditions within the for loop for each of the indexed queueFamily objects. The if statements are returning exactly as they should be. My code compiles and builds without any errors or warnings, and it still does render then triangle when I'm not running it through the debugger and it does exit with a code of (0). So the code appears to be fine. However I'm not getting the results that I would at least be expecting.

I'm not sure if there is a bug in his code that he happened to missed, if I'm misinterpreting my video card's support of this Vulkan functionality, or if this could be either a Vulkan API bug or NVidia Driver bug.

However as I was stepping through this function to find out why the indices.transferFamily variable was not being set to i on the second iteration of the loop has nothing to do with the presence of the transferFamilyQueue, its parameter values or flags. What is causing this if statement to return false is the presentSupport variable as it is being set to 0 on the second call which does match the data sheet above. So the output is as expected.

My question them becomes: is there an actual implementation problem with the condition checking in the second if statement?

This is where I'm stuck as I am a bit confused because we are checking to see if there is a transferQueueFamily available and if so use that to create and use a stagingBuffer to copy the contents from the CPU to the GPU for the vertex buffer(s). From what I can see it appears my card does have this transferFamily but does not have supportPresent for this family. However, when thinking about it; if you are using a transferFamily - transferQueue you wouldn't want to present it directly as you'll just be copying the data from a temporary vertexBuffer on the CPU to the vertexBuffer that will be used on the GPU. So I'm wondering if the final check in this if statement is correct or not. If my assumptions about how Vulkan is working here is incorrect please don't hesitate to correct me as this is my first attempt and getting a rendering application of Vulkan working.

Aucun commentaire:

Enregistrer un commentaire