Vulkan學習--4.創建 VkDevice(邏輯設備) 和 VkQueue(隊列)

• 爲繪製和顯示操作創建 VkDevice(邏輯設備) 和 VkQueue(隊列)
選擇物理設備後,我們還需要一個邏輯設備來作爲和物理設備交互的接口。
我們還需要指定使用的隊列所屬的隊列族。
對於同一個物理設備,我們可以根據需求的不同,創建多個邏輯設備。

部分示例:
    VkDevice device;//邏輯設備--3
    VkQueue graphicsQueue;//邏輯設備的隊列句柄,自動被清除--3
    //創建一個邏輯設備--3
    void createLogicalDevice(){
        //獲取帶有圖形能力的隊列族
        QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
        std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
        /**
        目前而言,對於每個隊列族,驅動程序只允許創建很少數量的隊列,但實際上,
        對於每一個隊列族,我們很少需要一個以上的隊列。
        我們可以在多個線程創建指令緩衝,然後在主線程一次將它們全部提交,降低調用開銷。
        Vulkan需要我們賦予隊列一個0.0到1.0之間的浮點數作爲優先級來控制指令緩衝的執行順序。
        即使只有一個隊列,我們也要顯式地賦予隊列優先級
         */
        float queuePriority = 1.0f;
            //描述了針對一個隊列族我們所需的隊列數量。
            VkDeviceQueueCreateInfo queueCreateInfo = {};
            queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
            queueCreateInfo.queueFamilyIndex=indices.graphicsFamily;
            queueCreateInfo.queueCount = 1;
            queueCreateInfo.pQueuePriorities = &queuePriority;

        //指定應用程序使用的設備特性
        VkPhysicalDeviceFeatures deviceFeatures = {};
        //創建邏輯設備相關信息
        VkDeviceCreateInfo createInfo = {};
        createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
        createInfo.queueCreateInfoCount = 1;
        createInfo.pQueueCreateInfos = &queueCreateInfo;
        createInfo.pEnabledFeatures = &deviceFeatures;

        if(enableValidationLayers){
            //以對設備和 Vulkan 實例使用相同地校驗層
            createInfo.enabledLayerCount =
                    static_cast<uint32_t>(validataionLayers.size());
            createInfo.ppEnabledLayerNames = validataionLayers.data();
        }else{
            createInfo.enabledLayerCount = 0;
        }
        /**
        vkCreateDevice 函數的參數:
        1.創建的邏輯設備進行交互的物理設備對象
        2.指定的需要使用的隊列信息
        3.可選的分配器回調
        4.用來存儲返回的邏輯設備對象的內存地址
        邏輯設備並不直接與Vulkan實例交互,所以創建邏輯設備時不需要使用Vulkan實例作爲參數
          */
        //創建邏輯設備
        if(vkCreateDevice(physicalDevice,&createInfo,nullptr,
                          &device) != VK_SUCCESS){
            throw std::runtime_error("failed to create logical device!");
        }
        //獲取指定隊列族的隊列句柄
        //它的參數依次是邏輯設備對象,隊列族索引,隊列索引,用來存儲返回的隊列句柄的內存地址
        //我們只創建了一個隊列,所以,可以直接使用索引 0
        vkGetDeviceQueue(device,indices.graphicsFamily,0,&graphicsQueue);
    }

設備隊列和隊列系列

與其他圖形API不同,Vulkan將設備隊列暴露給程序員,以便程序員可以決定使用多少隊列以及使用哪種類型的隊列。

隊列是用於向硬件提交命令的抽象機制。稍後您將看到Vulkan應用程序如何構建一個充滿命令的命令緩衝區,然後將它們提交到隊列以供GPU硬件進行異步處理。

Vulkan根據隊列類型將隊列排列到隊列系列中。爲了找到您感興趣的隊列的類型和特徵,您可以從物理設備查詢QueueFamilyProperties:
在這裏插入圖片描述

typedef struct VkQueueFamilyProperties {
    VkQueueFlags    queueFlags;
    uint32_t        queueCount;
    uint32_t        timestampValidBits;
    VkExtent3D      minImageTransferGranularity;
} VkQueueFamilyProperties;

typedef enum VkQueueFlagBits {
    VK_QUEUE_GRAPHICS_BIT = 0x00000001,
    VK_QUEUE_COMPUTE_BIT = 0x00000002,
    VK_QUEUE_TRANSFER_BIT = 0x00000004,
    VK_QUEUE_SPARSE_BINDING_BIT = 0x00000008,
} VkQueueFlagBits;

該VkQueueFamilyProperties結構稱爲“系列”,因爲可能有許多(queueCount)隊列可用於特定的一組queueFlags。例如,一個系列中可能有8個具有該VK_QUEUE_GRAPHICS_BIT組的隊列。

設備上的隊列和隊列系列可能如下所示:
在這裏插入圖片描述

該VkQueueFlagBits指示每個硬件隊列可以處理什麼類型的工作負載。例如,設備可以定義VK_QUEUE_GRAPHICS_BIT爲正常3D圖形工作設置的隊列族 。但是,如果同一設備具有用於執行像素塊複製(blits)的專用硬件,則它可以僅使用該VK_QUEUE_TRANSFER_BIT 集定義另一個隊列系列。這使得硬件可以與blit工作負載並行處理圖形工作負載。

一些更簡單的GPU硬件可能只通告一個具有多個隊列類型標誌集的隊列系列:
在這裏插入圖片描述

創建設備

    ///4.創建設備
    VkDeviceQueueCreateInfo queue_info = {};
    uint32_t queue_family_count=0;
    vkGetPhysicalDeviceQueueFamilyProperties(gpus[0], &queue_family_count, NULL);
    assert(queue_family_count >= 1);
    std::vector<VkQueueFamilyProperties> queue_props(queue_family_count);
    //獲取隊列信息
    vkGetPhysicalDeviceQueueFamilyProperties(gpus[0], &queue_family_count,
                                             queue_props.data());
    std::cout <<queue_family_count<<" "<<queue_props.size() <<std::endl;

    bool found = false;
    for (unsigned int i = 0; i < queue_family_count; i++) {
        //現在只對繪製簡單圖形感興趣,所以只需要查找圖形位
        if (queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
            //note:隊列系列不是用句柄表示,而是用索引表示
            queue_info.queueFamilyIndex = i;
            found = true;
            break;
        }
    }
    std::cout <<"found:"<< found << std::endl;
    //如果有多個隊列可用,則更復雜的程序可能希望在多個隊列上提交圖形命令
    //這裏只有一個隊列,所以放入的值queue_priorities[] 並不重要
    float queue_priorities[1] = {0.0};
    queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
    queue_info.pNext = NULL;
    queue_info.queueCount = 1;
    queue_info.pQueuePriorities = queue_priorities;
    //構建設備信息
    VkDeviceCreateInfo device_info = {};
    device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
    device_info.pNext = NULL;
    device_info.queueCreateInfoCount = 1;
    device_info.pQueueCreateInfos = &queue_info;
    device_info.enabledExtensionCount = 0;
    device_info.ppEnabledExtensionNames = NULL;
    //最近在Vulkan中不推薦使用設備圖層,因此在創建設備時不必指定任何圖層
    device_info.enabledLayerCount = 0;
    device_info.ppEnabledLayerNames = NULL;
    device_info.pEnabledFeatures = NULL;
    VkDevice device;//創建設備
    res = vkCreateDevice(gpus[0], &device_info, NULL, &device);
    assert(res == VK_SUCCESS);
    ///
    vkDestroyDevice(device, NULL);

原文url:https://vulkan.lunarg.com/doc/sdk/1.1.101.0/windows/tutorial/html/02-enumerate_devices.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章