vulakn教程--Drawing a Triangle--Set up--Logical Device

来源:互联网 发布:淘宝一淘怎么报名 编辑:程序博客网 时间:2024/05/25 19:57

原文链接 : Vulakn-tutorial


Logical Device

只有Physical Device 还不行,我们还需要创建Logical Device 来与它相联。Logical Device的创建和VkInstance的创建过程差不多,需要明确我们所需的特性(features)、extensions、Validation layers 、queue等。

声明 :

VDeleter<VkDevice> device{vkDestroyDevice};

我们不打算使例子太复杂,特性(fetures)采用默认值Vk_FALSE,当我们想做一些更有趣的事情的时候,可以再回过头来修改。

VkPhysicalDeviceFeatures deviceFeatures = {};

首先,我们来看一个和队列有关的,一个很重要的结构体VkDeviceQueueCreateInfo:

typedef struct VkDeviceQueueCreateInfo {    VkStructureType             sType;    const void*                 pNext;    VkDeviceQueueCreateFlags    flags;    uint32_t                    queueFamilyIndex;    uint32_t                    queueCount;    const float*                pQueuePriorities;} VkDeviceQueueCreateInfo;

说明 : flags 保留未来使用(reserved for future use),后面3个参数表示,创建queueCount个queueFamilyIndex类型的队列,每个队列的优先级用pQueuePriorities数组表示。优先级的值为0.0~1.0 , 值越大优先级越高。

填充 :

QueueFamilyIndices indices = findQueueFamilies(physicalDevice);VkDeviceQueueCreateInfo queueCreateInfo = {};queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;queueCreateInfo.queueFamilyIndex = indices.graphicsFamily;queueCreateInfo.queueCount = 1; //创建一个队列float queuePriority = 1.0f;queueCreateInfo.pQueuePriorities = &queuePriority;  

像创建其他Vulkan对象一样,必不可少的是Vk_XXX_CreateInfo结构体,这次我们需要 VkDeviceCreateInfo:

typedef struct VkDeviceCreateInfo {    VkStructureType                    sType;    const void*                        pNext;    VkDeviceCreateFlags                flags;//(future use)    uint32_t                           queueCreateInfoCount;    const VkDeviceQueueCreateInfo*     pQueueCreateInfos;    uint32_t                           enabledLayerCount;    const char* const*                 ppEnabledLayerNames;    uint32_t                           enabledExtensionCount;    const char* const*                 ppEnabledExtensionNames;    const VkPhysicalDeviceFeatures*    pEnabledFeatures;} VkDeviceCreateInfo;

说明: 该结构除了对队列(queue)和特性(features)支持的限定外,还有对Validation layers 和 Extensions的限定,例如一个很重要的extension : VK_KHR_swapchain 支持,同样,我们不想把问题复杂化,正如在创建VkInstance时定义的那样,我们直接将那时定义的layers 和 extensions应用到这里,所不同的是现在是创建VkDevice阶段。

VkDeviceCreateInfo createInfo = {};createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;createInfo.pQueueCreateInfos = &queueCreateInfo;createInfo.queueCreateInfoCount = 1;createInfo.pEnabledFeatures = &deviceFeatures;createInfo.enabledExtensionCount = 0;  //暂时不使用扩展if (enableValidationLayers) {    createInfo.enabledLayerCount = validationLayers.size();    createInfo.ppEnabledLayerNames = validationLayers.data();} else {    createInfo.enabledLayerCount = 0;}//创建logical deviceif (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) {    throw std::runtime_error("failed to create logical device!");}

这里enableValidationLayers和validationLayers直接取自创建VkInstances时已有的定义。
我们在VkDeviceCreateInfo 里定义的队列(queue 类型为VkQueue)将会随着logical device 一同被创建。那么我们怎么获得这个队列的句柄(handle)呢 ?

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

参数说明 :
device : logical device.
indices.graphicsFamily : 队列种类。
queueIndex : 这里是 0 ,因为我们只创建了一个队列,所以这里索引为0.
VkQueue * : &graphicsQueue


源码:

#define GLFW_INCLUDE_VULKAN#include <GLFW/glfw3.h>#include <iostream>#include <stdexcept>#include <functional>#include <vector>#include <cstring>const int WIDTH = 800;const int HEIGHT = 600;const std::vector<const char*> validationLayers = {    "VK_LAYER_LUNARG_standard_validation"};#ifdef NDEBUGconst bool enableValidationLayers = false;#elseconst bool enableValidationLayers = true;#endifVkResult CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback) {    auto func = (PFN_vkCreateDebugReportCallbackEXT) vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT");    if (func != nullptr) {        return func(instance, pCreateInfo, pAllocator, pCallback);    } else {        return VK_ERROR_EXTENSION_NOT_PRESENT;    }}void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator) {    auto func = (PFN_vkDestroyDebugReportCallbackEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT");    if (func != nullptr) {        func(instance, callback, pAllocator);    }}template <typename T>class VDeleter {public:    VDeleter() : VDeleter([](T, VkAllocationCallbacks*) {}) {}    VDeleter(std::function<void(T, VkAllocationCallbacks*)> deletef) {        this->deleter = [=](T obj) { deletef(obj, nullptr); };    }    VDeleter(const VDeleter<VkInstance>& instance, std::function<void(VkInstance, T, VkAllocationCallbacks*)> deletef) {        this->deleter = [&instance, deletef](T obj) { deletef(instance, obj, nullptr); };    }    VDeleter(const VDeleter<VkDevice>& device, std::function<void(VkDevice, T, VkAllocationCallbacks*)> deletef) {        this->deleter = [&device, deletef](T obj) { deletef(device, obj, nullptr); };    }    ~VDeleter() {        cleanup();    }    T* operator &() {        cleanup();        return &object;    }    operator T() const {        return object;    }private:    T object{VK_NULL_HANDLE};    std::function<void(T)> deleter;    void cleanup() {        if (object != VK_NULL_HANDLE) {            deleter(object);        }        object = VK_NULL_HANDLE;    }};struct QueueFamilyIndices {    int graphicsFamily = -1;    bool isComplete() {        return graphicsFamily >= 0;    }};class HelloTriangleApplication {public:    void run() {        initWindow();        initVulkan();        mainLoop();    }private:    GLFWwindow* window;    VDeleter<VkInstance> instance{vkDestroyInstance};    VDeleter<VkDebugReportCallbackEXT> callback{instance, DestroyDebugReportCallbackEXT};    VDeleter<VkSurfaceKHR> surface{instance, vkDestroySurfaceKHR};    VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;    VDeleter<VkDevice> device{vkDestroyDevice};    VkQueue graphicsQueue;    void initWindow() {        glfwInit();        glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);        glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);        window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);    }    void initVulkan() {        createInstance();        setupDebugCallback();        pickPhysicalDevice();        createLogicalDevice();    }    void mainLoop() {        while (!glfwWindowShouldClose(window)) {            glfwPollEvents();        }    }    void createInstance() {        if (enableValidationLayers && !checkValidationLayerSupport()) {            throw std::runtime_error("validation layers requested, but not available!");        }        VkApplicationInfo appInfo = {};        appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;        appInfo.pApplicationName = "Hello Triangle";        appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);        appInfo.pEngineName = "No Engine";        appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);        appInfo.apiVersion = VK_API_VERSION_1_0;        VkInstanceCreateInfo createInfo = {};        createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;        createInfo.pApplicationInfo = &appInfo;        auto extensions = getRequiredExtensions();        createInfo.enabledExtensionCount = extensions.size();        createInfo.ppEnabledExtensionNames = extensions.data();        if (enableValidationLayers) {            createInfo.enabledLayerCount = validationLayers.size();            createInfo.ppEnabledLayerNames = validationLayers.data();        } else {            createInfo.enabledLayerCount = 0;        }        if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {            throw std::runtime_error("failed to create instance!");        }    }    void setupDebugCallback() {        if (!enableValidationLayers) return;        VkDebugReportCallbackCreateInfoEXT createInfo = {};        createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;        createInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;        createInfo.pfnCallback = debugCallback;        if (CreateDebugReportCallbackEXT(instance, &createInfo, nullptr, &callback) != VK_SUCCESS) {            throw std::runtime_error("failed to set up debug callback!");        }    }    void pickPhysicalDevice() {        uint32_t deviceCount = 0;        vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);        if (deviceCount == 0) {            throw std::runtime_error("failed to find GPUs with Vulkan support!");        }        std::vector<VkPhysicalDevice> devices(deviceCount);        vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());        for (const auto& device : devices) {            if (isDeviceSuitable(device)) {                physicalDevice = device;                break;            }        }        if (physicalDevice == VK_NULL_HANDLE) {            throw std::runtime_error("failed to find a suitable GPU!");        }    }    void createLogicalDevice() {        QueueFamilyIndices indices = findQueueFamilies(physicalDevice);        VkDeviceQueueCreateInfo queueCreateInfo = {};        queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;        queueCreateInfo.queueFamilyIndex = indices.graphicsFamily;        queueCreateInfo.queueCount = 1;        float queuePriority = 1.0f;        queueCreateInfo.pQueuePriorities = &queuePriority;        VkPhysicalDeviceFeatures deviceFeatures = {};        VkDeviceCreateInfo createInfo = {};        createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;        createInfo.pQueueCreateInfos = &queueCreateInfo;        createInfo.queueCreateInfoCount = 1;        createInfo.pEnabledFeatures = &deviceFeatures;        createInfo.enabledExtensionCount = 0;        if (enableValidationLayers) {            createInfo.enabledLayerCount = validationLayers.size();            createInfo.ppEnabledLayerNames = validationLayers.data();        } else {            createInfo.enabledLayerCount = 0;        }        if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) {            throw std::runtime_error("failed to create logical device!");        }        vkGetDeviceQueue(device, indices.graphicsFamily, 0, &graphicsQueue);    }    bool isDeviceSuitable(VkPhysicalDevice device) {        QueueFamilyIndices indices = findQueueFamilies(device);        return indices.isComplete();    }    QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) {        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) {            if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {                indices.graphicsFamily = i;            }            if (indices.isComplete()) {                break;            }            i++;        }        return indices;    }    std::vector<const char*> getRequiredExtensions() {        std::vector<const char*> extensions;        unsigned int glfwExtensionCount = 0;        const char** glfwExtensions;        glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);        for (unsigned int i = 0; i < glfwExtensionCount; i++) {            extensions.push_back(glfwExtensions[i]);        }        if (enableValidationLayers) {            extensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);        }        return extensions;    }    bool checkValidationLayerSupport() {        uint32_t layerCount;        vkEnumerateInstanceLayerProperties(&layerCount, nullptr);        std::vector<VkLayerProperties> availableLayers(layerCount);        vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());        for (const char* layerName : validationLayers) {            bool layerFound = false;            for (const auto& layerProperties : availableLayers) {                if (strcmp(layerName, layerProperties.layerName) == 0) {                    layerFound = true;                    break;                }            }            if (!layerFound) {                return false;            }        }        return true;    }    static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t obj, size_t location, int32_t code, const char* layerPrefix, const char* msg, void* userData) {        std::cerr << "validation layer: " << msg << std::endl;        return VK_FALSE;    }};int main() {    HelloTriangleApplication app;    try {        app.run();    } catch (const std::runtime_error& e) {        std::cerr << e.what() << std::endl;        return EXIT_FAILURE;    }    return EXIT_SUCCESS;}
0 0