Elytra
Graphics

Vulkan Review

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

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

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

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

3. Select PhysicalDevice

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

//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

On this page