#define VMA_IMPLEMENTATION
#include "buffer.h"
#include "../backend.h"
#include "zlog.h"
namespace vulkanapi {
    VmaAllocator Buffer::vmaAllocator;
	void Buffer::MakeVmaAllocator(Backend& backend)
	{
        // 因为用volk库手动加载所有Vulkan函数了，所以这里要给VMA传递获取函数地址的方法，让VMA可以正确获取Vulkan函数
        VmaVulkanFunctions vmaVkFunctions = {};
        vmaVkFunctions.vkGetInstanceProcAddr = vkGetInstanceProcAddr;
        vmaVkFunctions.vkGetDeviceProcAddr = vkGetDeviceProcAddr;

        VmaAllocatorCreateInfo vmaInfo = {};
        vmaInfo.vulkanApiVersion = VK_HEADER_VERSION_COMPLETE;
        vmaInfo.instance = backend.GetInstance().Ptr();
        vmaInfo.physicalDevice = backend.GetDevice().GetPhysical();
        vmaInfo.device = backend.GetDevice().Ptr();
        vmaInfo.flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT;
        // 如果不手动加载Vulkan函数，这里可以填NULL
        vmaInfo.pVulkanFunctions = &vmaVkFunctions;

        vmaCreateAllocator(&vmaInfo, &vmaAllocator);
	}
    VkBufferCreateInfo Buffer::MakeStageInfo(VmaAllocationCreateInfo& allocationCreateInfo, VkDeviceSize vertexBufferSize)
    {
        VkBufferCreateInfo bufferCreateInfo = {};
        bufferCreateInfo.size = vertexBufferSize;
        bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
        bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
        bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;

        allocationCreateInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_HOST;
        allocationCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
        return bufferCreateInfo;
    }
    VkBufferCreateInfo Buffer::MakeDeviceInfo(VmaAllocationCreateInfo& allocationCreateInfo, VkDeviceSize vertexBufferSize, VkBufferUsageFlags flags)
    {
        VkBufferCreateInfo bufferCreateInfo = {};
        bufferCreateInfo.size = vertexBufferSize;
        bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
        bufferCreateInfo.usage = flags | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
        bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;

        allocationCreateInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
        return bufferCreateInfo;
    }
    VkBuffer Buffer::CreateBuffer(VkBufferCreateInfo& bufferCreateInfo, VmaAllocationCreateInfo& allocationCreateInfo, VmaAllocation& allocation)
    {
        VkBuffer buffer;
        vmaCreateBuffer(vmaAllocator, &bufferCreateInfo, &allocationCreateInfo, &buffer, &allocation, nullptr);
        return buffer;
    }
    VkBuffer Buffer::CreateStageBuffer(VmaAllocationCreateInfo& allocationCreateInfo, VmaAllocation& allocation, VkDeviceSize bufferSize)
    {
        VkBufferCreateInfo bufferCreateInfo = MakeStageInfo(allocationCreateInfo, bufferSize);
        return CreateBuffer(bufferCreateInfo, allocationCreateInfo, allocation);
    }
    void Buffer::CopyData(VmaAllocation& allocation, void* data, VkDeviceSize size)
    {
        // 拷贝数据到StagingBuffer
        void* vertexData;
        vmaMapMemory(vmaAllocator, allocation, &vertexData);
        memcpy(vertexData, data, size);
        vmaUnmapMemory(vmaAllocator, allocation);
    }
    void Buffer::DestroyBuffer(VkBuffer buffer, VmaAllocation bufferAlloc)
    {
        // 销毁StagingBuffer
        vmaDestroyBuffer(vmaAllocator, buffer, bufferAlloc);
    }
    void Buffer::CreateImage(VkImageCreateInfo& imageInfo, VkImage& ptr, VmaAllocation& allocation, VmaMemoryUsage usage)
    {
        VmaAllocationCreateInfo allocationInfo = {};
        allocationInfo.usage = usage;
        vmaCreateImage(vmaAllocator, &imageInfo, &allocationInfo, &ptr, &allocation, nullptr);
    }
}
