Skip to content

Vulkan Review

在此,我们将使用 Vulkan-Hpp & C++17

Overview

  1. Init
    1. Create Instance
    2. Create Surface
    3. Select PhysicalDevice
    4. Create (Logical)Device and QueueFamily
    5. Create CommandPool, DescriptorPool
    6. Create CommandBuffers, SyncObjects(Fence, Semaphore), ImageSampler,
    7. Create Main RenderPass
    8. Create Swapchain
  2. Render
  3. Destroy

Init

1. Create Instance

cpp
static vk::Instance CreateInstance(
    bool enableValidationLayer, 
    const std::vector<const char*>& in_extensions
) {
    vk::ApplicationInfo appInfo{
        .pApplicationName = "N/A",
        .applicationVersion = VK_MAKE_VERSION(0, 0, 1),
        .pEngineName = "No Engine",
        .engineVersion = VK_MAKE_VERSION(0, 0, 1),
        .apiVersion = VK_API_VERSION_1_3
    };

    vk::InstanceCreateInfo instInfo{};
    instInfo.pApplicationInfo = &appInfo;


    // Instance Extensions

    std::vector<const char*> extensions = in_extensions;

#ifdef __APPLE__
    // for prevents VK_ERROR_INCOMPATIBLE_DRIVER err on MacOS MoltenVK sdk.
    extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
    instInfo.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;

    // for supports VK_KHR_portability_subset logical-device-extension on MacOS.
    extensions.push_back("VK_KHR_get_physical_device_properties2");
#endif

    if (enableValidationLayer) {
        extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
    }

    instInfo.enabledExtensionCount = extensions.size();
    instInfo.ppEnabledExtensionNames = extensions.data();


    vk::DebugUtilsMessengerCreateInfoEXT debugMessengerInfo{};
    if (enableValidationLayer)
    {
        _CheckValidationLayersSupport(g_ValidationLayers);

        instInfo.enabledLayerCount = g_ValidationLayers.size();
        instInfo.ppEnabledLayerNames = g_ValidationLayers.data();

        debugMessengerInfo.messageSeverity =
            vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose |
            vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo | 
            vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
            vk::DebugUtilsMessageSeverityFlagBitsEXT::eError;
        debugMessengerInfo.messageType =
            vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
            vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation |
            vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance;

        debugMessengerInfo.pfnUserCallback = _DebugMessengerCallback;
        debugMessengerInfo.pUserData = nullptr; // Optional
        instInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*)&debugMessengerInfo;
    }

    vk::Instance instance = vk::createInstance(instInfo, vkx::ctx().Allocator);

    if (enableValidationLayer)
    {
        // Setup EXT DebugMessenger
        auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
        assert(func != nullptr);
        vkx::check(func(instance, (VkDebugUtilsMessengerCreateInfoEXT*)&debugMessengerInfo, nullptr, &g_DebugUtilsMessengerEXT));
    }


    return instance;
}

VkBootstrap version

cpp
auto vkb_inst = vkb::InstanceBuilder().set_app_name("N/A")
    .request_validation_layers(bUseValidationLayers)
    .use_default_debug_messenger()
    .require_api_version(1, 3, 0)
    .build();

vkb::Instance vkb_inst = inst_ret.value();

//grab the instance 
vk::Instance instance = vkb_inst.instance;
VkDebugUtilsMessengerEXT debugMessager = vkb_inst.debug_messenger;

2. Create Surface

cpp
VkSurfaceKHR surfaceKHR;
// GLFW
glfwCreateWindowSurface(inst, (GLFWwindow*)wnd, (VkAllocationCallbacks*)vkx::ctx().Allocator, &surfaceKHR);
// SDL
SDL_Vulkan_CreateSurface(wnd, inst, &surfaceKHR);

3. Select PhysicalDevice

cpp
static VkPhysicalDevice SelectPhysicalDevice(
    vk::Instance inst,
    vk::PhysicalDeviceProperties* out_pProps, 
    vk::PhysicalDeviceFeatures* out_pFeats,
    vk::PhysicalDeviceMemoryProperties* out_pMemProps
) {
    std::vector<vk::PhysicalDevice> gpus = inst.enumeratePhysicalDevices();
    vk::PhysicalDevice gpu = gpus.front();

    *out_pProps = gpu.getProperties();
    *out_pFeats = gpu.getFeatures();
    *out_pMemProps = gpu.getMemoryProperties();
    return gpu;
}

VkBootstrap

cpp
//vulkan 1.3 features
VkPhysicalDeviceVulkan13Features features{ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES };
features.dynamicRendering = true;
features.synchronization2 = true;

//vulkan 1.2 features
VkPhysicalDeviceVulkan12Features features12{ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES };
features12.bufferDeviceAddress = true;
features12.descriptorIndexing = true;


//use vkbootstrap to select a gpu. 
//We want a gpu that can write to the SDL surface and supports vulkan 1.3 with the correct features
vkb::PhysicalDeviceSelector selector{ vkb_inst };
vkb::PhysicalDevice physicalDevice = selector
    .set_minimum_version(1, 3)
    .set_required_features_13(features)
    .set_required_features_12(features12)
    .set_surface(_surface)
    .select()
    .value();


//create the final vulkan device
vkb::DeviceBuilder deviceBuilder{ physicalDevice };

vkb::Device vkbDevice = deviceBuilder.build().value();

// Get the VkDevice handle used in the rest of a vulkan application
_device = vkbDevice.device;
_chosenGPU = physicalDevice.physical_device;

Resources