Vulkan Tutorial 06 邏輯設備與隊列


操作系統:Windows8.1

顯卡:Nivida GTX965M

開發工具:Visual Studio 2017


Introduction

在選擇要使用的物理設備之后,我們需要設置一個邏輯設備用於交互。邏輯設備創建過程與instance創建過程類似,也需要描述我們需要使用的功能。因為我們已經查詢過哪些隊列簇可用,在這里需要進一步為邏輯設備創建具體類型的命令隊列。如果有不同的需求,也可以基於同一個物理設備創建多個邏輯設備。

 

首先添加一個新的類成員來存儲邏輯設備句柄。

VkDevice device;

接下來創建一個新的函數createLogicalDevice,並在initVulkan函數中調用,以創建邏輯設備。

void initVulkan() {
    createInstance();
    setupDebugCallback();
    pickPhysicalDevice();
    createLogicalDevice();
}

void createLogicalDevice() {

}

Specifying the queues to be created


創建邏輯設備需要在結構體中明確具體的信息,首先第一個結構體VkDeviceQueueCreateInfo。這個結構體描述隊列簇中預要申請使用的隊列數量。現在我們僅關心具備圖形能力的隊列。

QueueFamilyIndices indices = findQueueFamilies(physicalDevice);

VkDeviceQueueCreateInfo queueCreateInfo = {};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.queueFamilyIndex = indices.graphicsFamily;
queueCreateInfo.queueCount = 1;

當前可用的驅動程序所提供的隊列簇只允許創建少量的隊列,並且很多時候沒有必要創建多個隊列。這是因為可以在多個線程上創建所有命令緩沖區,然后在主線程一次性的以較低開銷的調用提交隊列。

 

Vulkan允許使用0.0到1.0之間的浮點數分配隊列優先級來影響命令緩沖區執行的調用。即使只有一個隊列也是必須的:

float queuePriority = 1.0f;
queueCreateInfo.pQueuePriorities = &queuePriority;

Specifying used device features


下一個要明確的信息有關設備要使用的功能特性。這些是我們在上一節中用vkGetPhysicalDeviceFeatures查詢支持的功能,比如geometry shaders。現在我們不需要任何特殊的功能,所以我們可以簡單的定義它並將所有內容保留到VK_FALSE。一旦我們要開始用Vulkan做更多的事情,我們會回到這個結構體,進一步設置。

VkPhysicalDeviceFeatures deviceFeatures = {};

Creating the logical device


使用前面的兩個結構體,我們可以填充VkDeviceCreateInfo結構。

VkDeviceCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;

首先添加指向隊列創建信息的結構體和設備功能結構體:

createInfo.pQueueCreateInfos = &queueCreateInfo;
createInfo.queueCreateInfoCount = 1;

createInfo.pEnabledFeatures = &deviceFeatures;

結構體其余的部分與VkInstanceCreateInfo相似,需要指定擴展和validation layers,總而言之這次不同之處是為具體的設備設置信息。

 

設置具體擴展的一個案例是VK_KHR_swapchain,它允許將來自設備的渲染圖形呈現到Windows。系統中的Vulkan設備可能缺少該功能,例如僅僅支持計算操作。我們將在交換鏈章節中展開這個擴展。

 

就像之前validation layers小節中提到的,允許為instance開啟validation layers,現在我們將為設備開啟validation layers,而不需要為設備指定任何擴展。

createInfo.enabledExtensionCount = 0;

if (enableValidationLayers) {
    createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
    createInfo.ppEnabledLayerNames = validationLayers.data();
} else {
    createInfo.enabledLayerCount = 0;
}

就這樣,我們現在可以通過調用vkCreateDevice函數來創建實例化邏輯設備。

if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) {
    throw std::runtime_error("failed to create logical device!");
}

這些參數分別是包含具體隊列使用信息的物理設備,可選的分配器回調指針以及用於存儲邏輯設備的句柄。與instance創建類似,此調用可能由於啟用不存在的擴展或者指定不支持的功能,導致返回錯誤。

 

cleanup函數中邏輯設備需要調用vkDestroyDevice銷毀:

void cleanup() {
    vkDestroyDevice(device, nullptr);
    ...
}

邏輯設備不與instance交互,所以參數中不包含instance。

Retrieving queue handles


這些隊列與邏輯設備自動的一同創建,但是我們還沒有一個與它們進行交互的句柄。在這里添加一個新的類成員來存儲圖形隊列句柄:

VkQueue graphicsQueue;

設備隊列在設備被銷毀的時候隱式清理,所以我們不需要在cleanup函數中做任何操作。

 

我們可以使用vkGetDeviceQueue函數來檢測每個隊列簇中隊列的句柄。參數是邏輯設備,隊列簇,隊列索引和存儲獲取隊列變量句柄的指針。因為我們只是從這個隊列簇創建一個隊列,所以需要使用索引 0

vkGetDeviceQueue(device, indices.graphicsFamily, 0, &graphicsQueue);

在成功獲取邏輯設備和隊列句柄后,我們可以通過顯卡做一些實際的事情了,在接下來的幾章節中,我們會設置資源並將相應的結果提交到窗體系統。

 

獲取工程代碼 GitHub checkout 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM