src/core/VulkanDevice.cpp
VkResult
VulkanDevice::createLogicalDevice(VkPhysicalDeviceFeatures enabledFeatures, std::vector<const char *> enabledExtensions,
                                  void *pNextChain, bool useSwapChain, VkQueueFlags requestedQueueTypes) {
    // Desired queues need to be requested upon logical device creation
    // Due to differing queue family configurations of Vulkan implementations this can be a bit tricky, especially if the application
    // requests different queue types

    std::vector<VkDeviceQueueCreateInfo> queueCreateInfos{};

    // Get queue family indices for the requested queue family types
    // Note that the indices may overlap depending on the implementation

    const float defaultQueuePriority(0.0f);

    // Graphics queue
    if (requestedQueueTypes & VK_QUEUE_GRAPHICS_BIT) {
        queueFamilyIndices.graphics = getQueueFamilyIndex(VK_QUEUE_GRAPHICS_BIT);
        VkDeviceQueueCreateInfo queueInfo{};
        queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
        queueInfo.queueFamilyIndex = queueFamilyIndices.graphics;
        queueInfo.queueCount = 1;
        queueInfo.pQueuePriorities = &defaultQueuePriority;
        queueCreateInfos.push_back(queueInfo);
    } else {
        queueFamilyIndices.graphics = 0;
    }

    // Dedicated compute queue
    if (requestedQueueTypes & VK_QUEUE_COMPUTE_BIT) {
        queueFamilyIndices.compute = getQueueFamilyIndex(VK_QUEUE_COMPUTE_BIT);
        if (queueFamilyIndices.compute != queueFamilyIndices.graphics) {
            // If compute family index differs, we need an additional queue create info for the compute queue
            VkDeviceQueueCreateInfo queueInfo{};
            queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
            queueInfo.queueFamilyIndex = queueFamilyIndices.compute;
            queueInfo.queueCount = 1;
            queueInfo.pQueuePriorities = &defaultQueuePriority;
            queueCreateInfos.push_back(queueInfo);
        }
    } else {
        // Else we use the same queue
        queueFamilyIndices.compute = queueFamilyIndices.graphics;
    }

    // Dedicated transfer queue
    if (requestedQueueTypes & VK_QUEUE_TRANSFER_BIT) {
        queueFamilyIndices.transfer = getQueueFamilyIndex(VK_QUEUE_TRANSFER_BIT);
        if ((queueFamilyIndices.transfer != queueFamilyIndices.graphics) &&
            (queueFamilyIndices.transfer != queueFamilyIndices.compute)) {
            // If compute family index differs, we need an additional queue create info for the compute queue
            VkDeviceQueueCreateInfo queueInfo{};
            queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
            queueInfo.queueFamilyIndex = queueFamilyIndices.transfer;
            queueInfo.queueCount = 1;
            queueInfo.pQueuePriorities = &defaultQueuePriority;
            queueCreateInfos.push_back(queueInfo);
        }
    } else {
        // Else we use the same queue
        queueFamilyIndices.transfer = queueFamilyIndices.graphics;
    }

    // Create the logical device representation
    std::vector<const char *> deviceExtensions(std::move(enabledExtensions));
    if (useSwapChain) {
        // If the device will be used for presenting to a display via a swapchain we need to request the swapchain extension
        deviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
    }

    VkDeviceCreateInfo deviceCreateInfo = {};
    deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
    deviceCreateInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());;
    deviceCreateInfo.pQueueCreateInfos = queueCreateInfos.data();
    deviceCreateInfo.pEnabledFeatures = &enabledFeatures;

    // If a pNext(Chain) has been passed, we need to add it to the device creation info
    VkPhysicalDeviceFeatures2 physicalDeviceFeatures2{};
    if (pNextChain) {
        physicalDeviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
        physicalDeviceFeatures2.features = enabledFeatures;
        physicalDeviceFeatures2.pNext = pNextChain;
        deviceCreateInfo.pEnabledFeatures = nullptr;
        deviceCreateInfo.pNext = &physicalDeviceFeatures2;
    }



    // Enable the debug marker extension if it is present (likely meaning a debugging tool is present)
    if (extensionSupported(VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) {
        deviceExtensions.push_back(VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
    }


    if (deviceExtensions.size() > 0) {
        for (const char *enabledExtension: deviceExtensions) {
            if (!extensionSupported(enabledExtension)) {
                std::cerr << "Enabled device extension \"" << enabledExtension << "\" is not present at device level\n";
            }
        }

        deviceCreateInfo.enabledExtensionCount = (uint32_t) deviceExtensions.size();
        deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions.data();
    }

    this->enabledFeatures = enabledFeatures;

    VkResult result = vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &logicalDevice);
    if (result != VK_SUCCESS) {
        return result;
    }

    // Create a default command pool for graphics command buffers
    commandPool = createCommandPool(queueFamilyIndices.graphics);

    // Initialize a transfer queue
    vkGetDeviceQueue(logicalDevice, queueFamilyIndices.transfer, 0, &transferQueue);

    return result;


}
/**
	* Create the logical device based on the assigned physical device, also gets default queue family indices
	*
	* @param enabledFeatures Can be used to enable certain features upon device creation
	* @param pNextChain Optional chain of pointer to extension structures
	* @param useSwapChain Set to false for headless rendering to omit the swapchain device extensions
	* @param requestedQueueTypes Bit flags specifying the queue types to be requested from the device
	*
	* @return VkResult of the device creation call
	*/
Create the logical device based on the assigned physical device, also gets default queue family indices
@param enabledFeatures Can be used to enable certain features upon device creation
@param pNextChain Optional chain of pointer to extension structures
@param useSwapChain Set to false for headless rendering to omit the swapchain device extensions
@param requestedQueueTypes Bit flags specifying the queue types to be requested from the device

@return VkResult of the device creation call
Create the logical device based on the assigned physical device also gets default queue family indices @param enabledFeatures Can be used to enable certain features upon device creation @param pNextChain Optional chain of pointer to extension structures @param useSwapChain Set to false for headless rendering to omit the swapchain device extensions @param requestedQueueTypes Bit flags specifying the queue types to be requested from the device @return VkResult of the device creation call
VkResult
VulkanDevice::createLogicalDevice(VkPhysicalDeviceFeatures enabledFeatures, std::vector<const char *> enabledExtensions,
                                  void *pNextChain, bool useSwapChain, VkQueueFlags requestedQueueTypes) {
    std::vector<VkDeviceQueueCreateInfo> queueCreateInfos{};
    const float defaultQueuePriority(0.0f);
    if (requestedQueueTypes & VK_QUEUE_GRAPHICS_BIT) {
        queueFamilyIndices.graphics = getQueueFamilyIndex(VK_QUEUE_GRAPHICS_BIT);
        VkDeviceQueueCreateInfo queueInfo{};
        queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
        queueInfo.queueFamilyIndex = queueFamilyIndices.graphics;
        queueInfo.queueCount = 1;
        queueInfo.pQueuePriorities = &defaultQueuePriority;
        queueCreateInfos.push_back(queueInfo);
    } else {
        queueFamilyIndices.graphics = 0;
    }
    if (requestedQueueTypes & VK_QUEUE_COMPUTE_BIT) {
        queueFamilyIndices.compute = getQueueFamilyIndex(VK_QUEUE_COMPUTE_BIT);
        if (queueFamilyIndices.compute != queueFamilyIndices.graphics) {
            VkDeviceQueueCreateInfo queueInfo{};
            queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
            queueInfo.queueFamilyIndex = queueFamilyIndices.compute;
            queueInfo.queueCount = 1;
            queueInfo.pQueuePriorities = &defaultQueuePriority;
            queueCreateInfos.push_back(queueInfo);
        }
    } else {
        queueFamilyIndices.compute = queueFamilyIndices.graphics;
    }
    if (requestedQueueTypes & VK_QUEUE_TRANSFER_BIT) {
        queueFamilyIndices.transfer = getQueueFamilyIndex(VK_QUEUE_TRANSFER_BIT);
        if ((queueFamilyIndices.transfer != queueFamilyIndices.graphics) &&
            (queueFamilyIndices.transfer != queueFamilyIndices.compute)) {
            VkDeviceQueueCreateInfo queueInfo{};
            queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
            queueInfo.queueFamilyIndex = queueFamilyIndices.transfer;
            queueInfo.queueCount = 1;
            queueInfo.pQueuePriorities = &defaultQueuePriority;
            queueCreateInfos.push_back(queueInfo);
        }
    } else {
        queueFamilyIndices.transfer = queueFamilyIndices.graphics;
    }
    std::vector<const char *> deviceExtensions(std::move(enabledExtensions));
    if (useSwapChain) {
        deviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
    }
    VkDeviceCreateInfo deviceCreateInfo = {};
    deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
    deviceCreateInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());;
    deviceCreateInfo.pQueueCreateInfos = queueCreateInfos.data();
    deviceCreateInfo.pEnabledFeatures = &enabledFeatures;
    VkPhysicalDeviceFeatures2 physicalDeviceFeatures2{};
    if (pNextChain) {
        physicalDeviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
        physicalDeviceFeatures2.features = enabledFeatures;
        physicalDeviceFeatures2.pNext = pNextChain;
        deviceCreateInfo.pEnabledFeatures = nullptr;
        deviceCreateInfo.pNext = &physicalDeviceFeatures2;
    }
    if (extensionSupported(VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) {
        deviceExtensions.push_back(VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
    }
    if (deviceExtensions.size() > 0) {
        for (const char *enabledExtension: deviceExtensions) {
            if (!extensionSupported(enabledExtension)) {
                std::cerr << "Enabled device extension \"" << enabledExtension << "\" is not present at device level\n";
            }
        }
        deviceCreateInfo.enabledExtensionCount = (uint32_t) deviceExtensions.size();
        deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions.data();
    }
    this->enabledFeatures = enabledFeatures;
    VkResult result = vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &logicalDevice);
    if (result != VK_SUCCESS) {
        return result;
    }
    commandPool = createCommandPool(queueFamilyIndices.graphics);
    vkGetDeviceQueue(logicalDevice, queueFamilyIndices.transfer, 0, &transferQueue);
    return result;
}
VkResult VulkanDevice :: createLogicalDevice ( VkPhysicalDeviceFeatures enabledFeatures , std :: vector < const char * > enabledExtensions , void * pNextChain , bool useSwapChain , VkQueueFlags requestedQueueTypes ) { std :: vector < VkDeviceQueueCreateInfo > queueCreateInfos { } ; const float defaultQueuePriority ( 0.0f ) ; if ( requestedQueueTypes & VK_QUEUE_GRAPHICS_BIT ) { queueFamilyIndices . graphics = getQueueFamilyIndex ( VK_QUEUE_GRAPHICS_BIT ) ; VkDeviceQueueCreateInfo queueInfo { } ; queueInfo . sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO ; queueInfo . queueFamilyIndex = queueFamilyIndices . graphics ; queueInfo . queueCount = 1 ; queueInfo . pQueuePriorities = & defaultQueuePriority ; queueCreateInfos . push_back ( queueInfo ) ; } else { queueFamilyIndices . graphics = 0 ; } if ( requestedQueueTypes & VK_QUEUE_COMPUTE_BIT ) { queueFamilyIndices . compute = getQueueFamilyIndex ( VK_QUEUE_COMPUTE_BIT ) ; if ( queueFamilyIndices . compute != queueFamilyIndices . graphics ) { VkDeviceQueueCreateInfo queueInfo { } ; queueInfo . sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO ; queueInfo . queueFamilyIndex = queueFamilyIndices . compute ; queueInfo . queueCount = 1 ; queueInfo . pQueuePriorities = & defaultQueuePriority ; queueCreateInfos . push_back ( queueInfo ) ; } } else { queueFamilyIndices . compute = queueFamilyIndices . graphics ; } if ( requestedQueueTypes & VK_QUEUE_TRANSFER_BIT ) { queueFamilyIndices . transfer = getQueueFamilyIndex ( VK_QUEUE_TRANSFER_BIT ) ; if ( ( queueFamilyIndices . transfer != queueFamilyIndices . graphics ) && ( queueFamilyIndices . transfer != queueFamilyIndices . compute ) ) { VkDeviceQueueCreateInfo queueInfo { } ; queueInfo . sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO ; queueInfo . queueFamilyIndex = queueFamilyIndices . transfer ; queueInfo . queueCount = 1 ; queueInfo . pQueuePriorities = & defaultQueuePriority ; queueCreateInfos . push_back ( queueInfo ) ; } } else { queueFamilyIndices . transfer = queueFamilyIndices . graphics ; } std :: vector < const char * > deviceExtensions ( std :: move ( enabledExtensions ) ) ; if ( useSwapChain ) { deviceExtensions . push_back ( VK_KHR_SWAPCHAIN_EXTENSION_NAME ) ; } VkDeviceCreateInfo deviceCreateInfo = { } ; deviceCreateInfo . sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO ; deviceCreateInfo . queueCreateInfoCount = static_cast < uint32_t > ( queueCreateInfos . size ( ) ) ; ; deviceCreateInfo . pQueueCreateInfos = queueCreateInfos . data ( ) ; deviceCreateInfo . pEnabledFeatures = & enabledFeatures ; VkPhysicalDeviceFeatures2 physicalDeviceFeatures2 { } ; if ( pNextChain ) { physicalDeviceFeatures2 . sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 ; physicalDeviceFeatures2 . features = enabledFeatures ; physicalDeviceFeatures2 . pNext = pNextChain ; deviceCreateInfo . pEnabledFeatures = nullptr ; deviceCreateInfo . pNext = & physicalDeviceFeatures2 ; } if ( extensionSupported ( VK_EXT_DEBUG_MARKER_EXTENSION_NAME ) ) { deviceExtensions . push_back ( VK_EXT_DEBUG_MARKER_EXTENSION_NAME ) ; } if ( deviceExtensions . size ( ) > 0 ) { for ( const char * enabledExtension : deviceExtensions ) { if ( ! extensionSupported ( enabledExtension ) ) { std :: cerr << " \" " << enabledExtension << " \" \n " ; } } deviceCreateInfo . enabledExtensionCount = ( uint32_t ) deviceExtensions . size ( ) ; deviceCreateInfo . ppEnabledExtensionNames = deviceExtensions . data ( ) ; } this -> enabledFeatures = enabledFeatures ; VkResult result = vkCreateDevice ( physicalDevice , & deviceCreateInfo , nullptr , & logicalDevice ) ; if ( result != VK_SUCCESS ) { return result ; } commandPool = createCommandPool ( queueFamilyIndices . graphics ) ; vkGetDeviceQueue ( logicalDevice , queueFamilyIndices . transfer , 0 , & transferQueue ) ; return result ; }
Create the logical device based on the assigned physical device, also gets default queue family indices
 @param enabledFeatures Can be used to enable certain features upon device creation
 @param pNextChain Optional chain of pointer to extension structures
 @param useSwapChain Set to false for headless rendering to omit the swapchain device extensions
 @param requestedQueueTypes Bit flags specifying the queue types to be requested from the device
Create the logical device based on the assigned physical device also gets default queue family indices @param enabledFeatures Can be used to enable certain features upon device creation @param pNextChain Optional chain of pointer to extension structures @param useSwapChain Set to false for headless rendering to omit the swapchain device extensions @param requestedQueueTypes Bit flags specifying the queue types to be requested from the device
// Desired queues need to be requested upon logical device creation // Due to differing queue family configurations of Vulkan implementations this can be a bit tricky, especially if the application // requests different queue types // Get queue family indices for the requested queue family types // Note that the indices may overlap depending on the implementation // Graphics queue // Dedicated compute queue // If compute family index differs, we need an additional queue create info for the compute queue // Else we use the same queue // Dedicated transfer queue // If compute family index differs, we need an additional queue create info for the compute queue // Else we use the same queue // Create the logical device representation // If the device will be used for presenting to a display via a swapchain we need to request the swapchain extension // If a pNext(Chain) has been passed, we need to add it to the device creation info // Enable the debug marker extension if it is present (likely meaning a debugging tool is present) // Create a default command pool for graphics command buffers // Initialize a transfer queue