//
// Created by lhyqy5 on 2025/12/9.
//
// vulkan_loader.h
#pragma once

#include <vulkan/vulkan.h>
#include <vector>

class VulkanLoader {
public:
    VulkanLoader();
    ~VulkanLoader();

    // open libvulkan.so, load vkGetInstanceProcAddr
    bool openLib(const char* path = "libvulkan.so");

    // load global functions such as vkCreateInstance
    bool loadGlobalFuncs();

    // create instance
    bool createInstance(const VkInstanceCreateInfo* createInfo,
                        const VkAllocationCallbacks *pAllocator);

    // load instance-level function
    template<typename T>
    T getInstanceProc(const char* name) {
        return reinterpret_cast<T>(_getInstanceProc(name));
    }

    // load device-level function
    template<typename T>
    T getDeviceProc(VkDevice device, const char* name) {
        return reinterpret_cast<T>(_getDeviceProc(device, name));
    }

    VkInstance instance = VK_NULL_HANDLE;

private:
    void* lib = nullptr;

    PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = nullptr;

    // global-level functions
    PFN_vkCreateInstance vkCreateInstance = nullptr;
    PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties = nullptr;

    // internal helpers
    void* _getInstanceProc(const char* name);
    void* _getDeviceProc(VkDevice device, const char* name);

    // disable copy
    VulkanLoader(const VulkanLoader&) = delete;
    VulkanLoader& operator=(const VulkanLoader&) = delete;
};
