Untitled

 avatar
unknown
c_cpp
a year ago
47 kB
18
Indexable
#include "SceneMeshManager.hpp"

#include "Mesh.hpp"
#include "ModelInstance.hpp"
#include "../Renderer/RendererContext.hpp"
#include "MaterialManager.hpp"
#include "Scene.hpp"

#include "../Common/Log.hpp"
#include "../Common/CommonDefinitions.hpp"

enum BufferCopySlots {
    VERTEX_COPY = 0,
    INDEX_COPY = 1,
    INDIRECT_COPY = 2,
    DRAWMETA_COPY = 3
};

SCENE::MeshManager::MeshManager(RENDERER::RendererContext &RendererContext)
{
    Create(RendererContext);
}

void SCENE::MeshManager::Create(RENDERER::RendererContext& RendererContext)
{
    this->RendererContext = &RendererContext;
    SceneMeshIndexBuffers.resize(MAX_FRAMES_IN_FLIGHT);
    PerformanceModeBuffers.Create();

    for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
    {
        ModelEntries[i].MaterialIndexAllocator.Create();
    }
}

void SCENE::MeshManager::Destroy(VkDevice& LogicalDevice)
{
    PerformanceModeBuffers.Destroy(RendererContext->DeviceContext.logicalDevice);
    //BalancedModeBuffers.Destroy(RendererContext->DeviceContext.logicalDevice);
    //MemorySavingModeBuffers.Destroy(RendererContext->DeviceContext.logicalDevice);
    for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
    {
        SceneMeshIndexBuffers[i].Destroy(RendererContext->DeviceContext.logicalDevice);
    }
}

void SCENE::MeshManager::UpdateMeshTransformations(std::vector<ModelInstance*>& UpdateList, uint32_t CurrentFrame)
{
    if (UpdateList.empty()) return;
    uint8_t* Destination = reinterpret_cast<uint8_t*>(PerformanceModeBuffers.ModelMatricesBuffers[CurrentFrame].Buffer.MappedMemory);
    auto& CurrentFrameModelEntries = ModelEntries[CurrentFrame].ModelEntries;

    for (auto& ModelInstance : UpdateList)
    {
        auto& AllocatedMemoryRegion = CurrentFrameModelEntries[ModelInstance->Source].Instances[ModelInstance];
        glm::mat4 ModelMatrix = ModelInstance->Transformations.GetModelMatrix();
        memcpy(Destination + AllocatedMemoryRegion[0].Offset,
            &ModelMatrix,
            AllocatedMemoryRegion[0].Size
        );
    }

   /*
    for (auto &[ModelPtr,ModelEntry] : CurrentFrameModelEntries)
    {
        for (auto& [InstancePtr, AllocatedMemoryRegion] : ModelEntry.Instances)
        {
            glm::mat4 ModelMatrix = InstancePtr->Transformations.GetModelMatrix();
            memcpy(Destination + AllocatedMemoryRegion[0].Offset,
                &ModelMatrix,
                AllocatedMemoryRegion[0].Size
            );
        }
    }
    */
}

//Fetch correct materials 
std::vector<SCENE::MaterialMetaData> CreateMaterialMetaData(
    SCENE::ModelInstance* ModelInstance,
    RENDERER_CORE::VirtualArenaAllocator& TexturesIndexBufferAllocator,
    size_t MaterialTextureTypeCount
)
{
    std::vector<SCENE::MaterialMetaData> MaterialMetaDataList;
    MaterialMetaDataList.reserve(ModelInstance->Source->Meshes.size());
    /*
    for (size_t i = 0; i < ModelInstance->Materials.size(); i++)
    {
        SCENE::MaterialMetaData NewMaterialMetaData{};
        NewMaterialMetaData.MaterialPtr = &ModelInstance->Materials[i];
        NewMaterialMetaData.TextureIndexMemoryRegion =
            TexturesIndexBufferAllocator.Allocate(MaterialTextureTypeCount * sizeof(int));

        MaterialMetaDataList.push_back(std::move(NewMaterialMetaData));
    }
    */
    for (size_t i = 0; i < ModelInstance->Source->Meshes.size(); i++)
    {
        SCENE::MaterialMetaData NewMaterialMetaData{};
        NewMaterialMetaData.MaterialPtr = &ModelInstance->Source->Meshes[i].MeshMaterial;
        NewMaterialMetaData.TextureIndexMemoryRegion =
            TexturesIndexBufferAllocator.Allocate(MaterialTextureTypeCount * sizeof(int));

        MaterialMetaDataList.push_back(std::move(NewMaterialMetaData));
    }

    return MaterialMetaDataList;
}


void SCENE::MeshManager::AppendModels(MeshAppendInfo Info)
{
    auto& CurrentFrame = Info.FrameIndex;
    auto& EnabledMeshCount = PerformanceModeBuffers.EnabledMeshCount[CurrentFrame];

    auto& VertexBuffer = PerformanceModeBuffers.VertexBuffers[CurrentFrame];
    auto& IndexBuffer = PerformanceModeBuffers.IndexBuffers[CurrentFrame];
    auto& IndirectBuffer = PerformanceModeBuffers.IndirectBuffers[CurrentFrame];
    auto& TexturesIndexBuffer = PerformanceModeBuffers.TexturesIndexBuffers[CurrentFrame];

    auto& CullBuffers = PerformanceModeBuffers.CullBuffers;
    auto& CulledMetaDataBuffer = CullBuffers.CulledDrawMetaDataBuffer[CurrentFrame];
    auto& CulledIndirectBuffer = CullBuffers.CulledIndirectBuffers[CurrentFrame];
    auto& MeshVisibilityCountBuffer = CullBuffers.MeshVisibilityCountBuffers[CurrentFrame];

    auto& DrawMetaDataBuffer = PerformanceModeBuffers.DrawMetaDataBuffer[CurrentFrame];
    auto& ModelMatricesBuffer = PerformanceModeBuffers.ModelMatricesBuffers[CurrentFrame];

    auto& VertexBufferAllocator = VertexBuffer.Allocator;
    auto& IndexBufferAllocator = IndexBuffer.Allocator;
    auto& IndirectBufferAllocator = IndirectBuffer.Allocator;
    auto& ModelMatricesBufferAllocator = ModelMatricesBuffer.Allocator;
    auto& DrawMetaDataBufferAllocator = DrawMetaDataBuffer.Allocator;
    auto& MeshVisibilityCountBufferAllocator = MeshVisibilityCountBuffer.Allocator;
    auto& TexturesIndexBufferAllocator = TexturesIndexBuffer.Allocator;

    auto& TexturesIndexBufferReallocated = PerformanceModeBuffers.TexturesIndexBuffersReallocated[CurrentFrame];

    size_t VertexSize, IndexSize,IndirectSize, VertexBufferSize = 0,IndexBufferSize = 0,IndirectBufferSize = 0;
    size_t SizeOfVertex = sizeof(Vertex3D), 
        SizeOfUint32 = sizeof(uint32_t),
        SizeOfMat4 = sizeof(glm::mat4), 
        SizeOfDrawMetaData = sizeof(DrawMetadata), 
        SizeOfIndirectCommand = sizeof(ExtendedIndirectCommand);

    size_t VertexBufferCapacity = VertexBufferAllocator.GetCapacity(),
            IndexBufferCapacity = IndexBufferAllocator.GetCapacity(),
            IndirectBufferCapacity = IndirectBufferAllocator.GetCapacity(),
            ModelMatricesBufferCapacity = ModelMatricesBufferAllocator.GetCapacity(),
            MeshVisibilityCountBufferCapacity = MeshVisibilityCountBufferAllocator.GetCapacity(),
            TexturesIndexBufferCapacity = TexturesIndexBufferAllocator.GetCapacity(),
            DrawMetaDataBufferCapacity = DrawMetaDataBufferAllocator.GetCapacity();

    size_t InsertedInstanceCount = 0 , InsertedMeshInstanceCount = 0;

    uint32_t MaterialTextureTypeCount = static_cast<uint32_t>(MATERIAL_TEXTURE_TYPE_META_DATA_SIZE);
    //auto& CurrentFrameMeshEntries = MeshEntries[CurrentFrame];
    auto& CurrentFrameModelEntries = ModelEntries[CurrentFrame];
    //Process newly inserted meshes.
    std::set<Mesh*> InsertedMetaDatas;
    for (auto& ModelInstance : Info.ModelInstances)
    {
        if (!ModelInstance || !ModelInstance->Source) continue;

        //Handle multiple references to the model
        auto& ModelIterator = CurrentFrameModelEntries.ModelEntries.find(ModelInstance->Source);
        bool DoesModelAlreadyExist = ModelIterator != CurrentFrameModelEntries.ModelEntries.end();

        std::array<RENDERER_CORE::MemoryRegion, 2> NewMemoryRegions;
        if (ModelInstance->Materials.size() > ModelInstance->Source->Meshes.size())
        {
            throw std::runtime_error("Instance material count exceeds target mesh count!");
        }
        
        CurrentFrameModelEntries.MaterialUpdateList.push_back(ModelInstance);
        InsertedInstanceCount++;
        if (DoesModelAlreadyExist)
        {
            //Handle already existing instance case
            auto InstanceIterator = ModelIterator->second.Instances.find(ModelInstance);
            if (InstanceIterator != ModelIterator->second.Instances.end())
            {
                auto& InstanceMaterialMetaDataIterator = CurrentFrameModelEntries.InstanceMaterialMetaDatas.find(ModelInstance);
                if (InstanceMaterialMetaDataIterator != CurrentFrameModelEntries.InstanceMaterialMetaDatas.end())
                {
                    for (size_t i = 0; i < ModelInstance->Materials.size(); i++)
                    {
                        InstanceMaterialMetaDataIterator->second[i].MaterialPtr = &ModelInstance->Materials[i];
                    }
                    for (size_t i = ModelInstance->Materials.size(); i < ModelInstance->Source->Meshes.size(); i++)
                    {
                        InstanceMaterialMetaDataIterator->second[i].MaterialPtr = &ModelInstance->Source->Meshes[i].MeshMaterial;
                    }
                }
                continue;
            }

            auto MaterialMetaDataList = CreateMaterialMetaData(ModelInstance, TexturesIndexBufferAllocator, MaterialTextureTypeCount);
            CurrentFrameModelEntries.InstanceMaterialMetaDatas.insert({ ModelInstance,MaterialMetaDataList });
           
            InsertedMeshInstanceCount += ModelIterator->second.MeshEntries.size();
            ModelIterator->second.MetaData.ReferenceCount++;
            ModelIterator->second.MetaData.IsChanged = true;
            NewMemoryRegions[0] = ModelMatricesBufferAllocator.Allocate(SizeOfMat4);
            ModelIterator->second.Instances[ModelInstance] = NewMemoryRegions;
            continue;
        }
        NewMemoryRegions[0] = ModelMatricesBufferAllocator.Allocate(SizeOfMat4);

        auto MaterialMetaDataList = CreateMaterialMetaData(ModelInstance, TexturesIndexBufferAllocator, MaterialTextureTypeCount);
        CurrentFrameModelEntries.InstanceMaterialMetaDatas.insert({ ModelInstance,MaterialMetaDataList });

        //Register the instance and its model
        ModelMetaData NewModelData;
        NewModelData.ReferenceCount++;

        auto &NewModelEntry = CurrentFrameModelEntries.ModelEntries[ModelInstance->Source];
        NewModelEntry.MetaData = NewModelData;
        NewModelEntry.Instances.emplace(ModelInstance, NewMemoryRegions);

        //Process and allocate the individual meshes 
        for (auto& Mesh : ModelInstance->Source->Meshes)
        {
            VertexSize = Mesh.Vertices.size() * SizeOfVertex;
            IndexSize = Mesh.Indices.size() * SizeOfUint32;

            MeshMetaData MetaData{};
            MetaData.MemoryRegions[0] = VertexBufferAllocator.Allocate(VertexSize);
            MetaData.MemoryRegions[1] = IndexBufferAllocator.Allocate(IndexSize);
            MetaData.MemoryRegions[2] = IndirectBufferAllocator.Allocate(SizeOfIndirectCommand);

            MetaData.DrawInfo.VertexOffset = MetaData.MemoryRegions[0].Offset / SizeOfVertex;
            MetaData.DrawInfo.FirstIndex = MetaData.MemoryRegions[1].Offset / SizeOfUint32;
            MetaData.DrawInfo.IndexCount = Mesh.Indices.size();
            MetaData.ModelInstance = ModelInstance;

            NewModelEntry.MeshEntries.push_back({ &Mesh , MetaData });
            InsertedMetaDatas.insert(&Mesh);

            VertexBufferSize += VertexSize;
            IndexBufferSize += IndexSize;
            IndirectBufferSize += SizeOfIndirectCommand;

            EnabledMeshCount++;   
        }
        InsertedMeshInstanceCount += NewModelEntry.MeshEntries.size();
    }
    //ModelMatricesBufferAllocator.Allocate(SizeOfMat4 * InsertedInstanceCount);
    DrawMetaDataBufferAllocator.Allocate(InsertedMeshInstanceCount * SizeOfDrawMetaData);
    MeshVisibilityCountBufferAllocator.Allocate(InsertedMetaDatas.size() * SizeOfUint32);

    //Check whether the allocator allocated extra virtual memory
    bool IsVertexBufferReallocated = VertexBufferCapacity < VertexBufferAllocator.GetCapacity(),
        IsIndexBufferReallocated = IndexBufferCapacity < IndexBufferAllocator.GetCapacity(),
        IsIndirectBufferReallocated = IndirectBufferCapacity < IndirectBufferAllocator.GetCapacity(),
        IsModelMatrixesBufferReallocated = ModelMatricesBufferCapacity < ModelMatricesBufferAllocator.GetCapacity(),
        IsMeshVisibilityCountBufferReallocated = MeshVisibilityCountBufferCapacity < MeshVisibilityCountBufferAllocator.GetCapacity(),
        IsDrawMetaDataBufferReallocated = DrawMetaDataBufferCapacity < DrawMetaDataBufferAllocator.GetCapacity();

    TexturesIndexBufferReallocated = TexturesIndexBufferCapacity < TexturesIndexBufferAllocator.GetCapacity();

    std::vector<RENDERER_CORE::BufferCopyInfo> CopyInfos(4);
    std::vector<RENDERER_CORE::DescriptorSetWriteBuffer> WriteInfos(3);
    //In case the buffer needs be enlarged , create a new buffer and copy existing data into it.
    if (IsVertexBufferReallocated)
    {
        VertexBuffer.Buffer.Destroy(RendererContext->DeviceContext.logicalDevice);
        RENDERER_CORE::CreateBuffer(
            RendererContext->DeviceContext.physicalDevice,
            RendererContext->DeviceContext.logicalDevice,
            VertexBufferAllocator.GetCapacity(),
            VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
            VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
            VertexBuffer.Buffer
        );
    }
    if (IsIndexBufferReallocated)
    {
        IndexBuffer.Buffer.Destroy(RendererContext->DeviceContext.logicalDevice);
        RENDERER_CORE::CreateBuffer(
            RendererContext->DeviceContext.physicalDevice,
            RendererContext->DeviceContext.logicalDevice,
            IndexBufferAllocator.GetCapacity(),
            VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
            VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
            IndexBuffer.Buffer
        );
    }
    if (IsIndirectBufferReallocated)
    {
        IndirectBuffer.Buffer.Destroy(RendererContext->DeviceContext.logicalDevice);
        RENDERER_CORE::CreateBuffer(
            RendererContext->DeviceContext.physicalDevice,
            RendererContext->DeviceContext.logicalDevice,
            IndirectBufferAllocator.GetCapacity(),
            VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
            VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
            IndirectBuffer.Buffer
        );

        CulledIndirectBuffer.Destroy(RendererContext->DeviceContext.logicalDevice);
        RENDERER_CORE::CreateBuffer(
            RendererContext->DeviceContext.physicalDevice,
            RendererContext->DeviceContext.logicalDevice,
            IndirectBufferAllocator.GetCapacity(),
            VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
            VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
            CulledIndirectBuffer
        );

        RENDERER_CORE::DescriptorSetWriteBuffer IndirectBufferWrite(
            IndirectBuffer.Buffer,
            IndirectBufferAllocator.GetCapacity(),
            1,
            Info.TargetDescriptorSets[CurrentFrame],
            VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
        );
        RENDERER_CORE::WriteDescriptorSets(RendererContext->DeviceContext.logicalDevice, { IndirectBufferWrite }, {});
    }
    if (IsModelMatrixesBufferReallocated)
    {
        ModelMatricesBuffer.Buffer.Buffer.Destroy(RendererContext->DeviceContext.logicalDevice);
        RENDERER_CORE::CreateBuffer(
            RendererContext->DeviceContext.physicalDevice,
            RendererContext->DeviceContext.logicalDevice,
            ModelMatricesBufferAllocator.GetCapacity(),
            VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
            VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
            ModelMatricesBuffer.Buffer.Buffer
        );
        ModelMatricesBuffer.Buffer.Map(RendererContext->DeviceContext.logicalDevice, 0, ModelMatricesBufferAllocator.GetCapacity(), 0);

        RENDERER_CORE::DescriptorSetWriteBuffer ModelMatrixBufferWrite(
            ModelMatricesBuffer.Buffer.Buffer,
            ModelMatricesBufferAllocator.GetCapacity(), 
            0, 
            Info.TargetDescriptorSets[CurrentFrame], 
            VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
        );
        RENDERER_CORE::WriteDescriptorSets(RendererContext->DeviceContext.logicalDevice, { ModelMatrixBufferWrite }, {});
    }
    if (IsDrawMetaDataBufferReallocated)
    {
        DrawMetaDataBuffer.Buffer.Destroy(RendererContext->DeviceContext.logicalDevice);
        RENDERER_CORE::CreateBuffer(
            RendererContext->DeviceContext.physicalDevice,
            RendererContext->DeviceContext.logicalDevice,
            DrawMetaDataBufferAllocator.GetCapacity(),
            VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
            VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
            DrawMetaDataBuffer.Buffer
        );

        CulledMetaDataBuffer.Destroy(RendererContext->DeviceContext.logicalDevice);
        RENDERER_CORE::CreateBuffer(
            RendererContext->DeviceContext.physicalDevice,
            RendererContext->DeviceContext.logicalDevice,
            DrawMetaDataBufferAllocator.GetCapacity(),
            VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
            VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
            CulledMetaDataBuffer
        );

        RENDERER_CORE::DescriptorSetWriteBuffer DrawMetaDataBufferWrite(
            DrawMetaDataBuffer.Buffer,
            DrawMetaDataBufferAllocator.GetCapacity(),
            2,
            Info.TargetDescriptorSets[CurrentFrame],
            VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
        );
        RENDERER_CORE::WriteDescriptorSets(RendererContext->DeviceContext.logicalDevice, { DrawMetaDataBufferWrite }, {});
    }
    if (IsMeshVisibilityCountBufferReallocated)
    {
        MeshVisibilityCountBuffer.Buffer.Destroy(RendererContext->DeviceContext.logicalDevice);
        RENDERER_CORE::CreateBuffer(
            RendererContext->DeviceContext.physicalDevice,
            RendererContext->DeviceContext.logicalDevice,
            MeshVisibilityCountBufferAllocator.GetCapacity(),
            VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
            VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
            MeshVisibilityCountBuffer.Buffer
        );
    }
        
    size_t VertexStagingBufferSize = IsVertexBufferReallocated ? VertexBufferAllocator.GetCapacity() : VertexBufferSize,
        IndexStagingBufferSize = IsIndexBufferReallocated ? IndexBufferAllocator.GetCapacity() : IndexBufferSize,
        IndirectStagingBufferSize = IsIndirectBufferReallocated ? IndirectBufferAllocator.GetCapacity() : IndirectBufferSize,
        DrawMetaDataBufferSize = DrawMetaDataBufferAllocator.GetCapacity();
        
    size_t TotalStagingBufferSize = VertexStagingBufferSize + IndexStagingBufferSize + IndirectStagingBufferSize + DrawMetaDataBufferSize;
    if (!TotalStagingBufferSize)
    {
        LOG_FILE(GLOBAL_LOG_FILE_PATH, COMMON::LOG_SEVERITY_VERBOSE, "Unable to proceed model appending operation, faulty staging buffer!");
        throw std::runtime_error("Faulty staging buffer!");
    }

    RENDERER_CORE::PersistentBuffer StagingBuffer{};
    RENDERER_CORE::VirtualArenaAllocator StagingBufferAllocator(TotalStagingBufferSize);
    RENDERER_CORE::CreateStagingBuffer(
        RendererContext->DeviceContext.physicalDevice,
        RendererContext->DeviceContext.logicalDevice,
        TotalStagingBufferSize,
        StagingBuffer.Buffer
    );
    StagingBuffer.Map(RendererContext->DeviceContext.logicalDevice, 0, TotalStagingBufferSize, 0);
    uint8_t* StagingBufferPtr = reinterpret_cast<uint8_t*>(StagingBuffer.MappedMemory);

    if (!StagingBufferPtr) throw std::runtime_error("Unable to map the staging buffer! exitting...");

    //Global draw index iterator
    size_t DrawIndexIterator = 0;
    //Global mesh index iterator
    uint32_t CurrentMesh = 0;
   // ModelMatricesBufferAllocator.Reset();
    DrawMetaDataBufferAllocator.Reset();

    //Local model index iterator
    size_t ModelIterator = 0;
    for (auto& [ModelPtr, ModelEntryMetaData] : CurrentFrameModelEntries.ModelEntries)
    {
        //Produce necessary copy informations
        for (size_t i = 0; i < ModelEntryMetaData.MeshEntries.size(); i++)
        {
            auto& MeshEntry = ModelEntryMetaData.MeshEntries[i];
            auto& MeshEntryPtr = MeshEntry.MeshPtr;
            auto& MeshEntryMetaData = MeshEntry.MetaData;
            bool IsMeshJustInserted = InsertedMetaDatas.find(MeshEntryPtr) != InsertedMetaDatas.end();
            
            //Local instance index iterator
            size_t InstanceIterator = 0;
            for (auto& [InstancePtr, AllocatedMemoryRegions] : ModelEntryMetaData.Instances)
            {
                auto MaterialDataIterator = CurrentFrameModelEntries.InstanceMaterialMetaDatas.find(InstancePtr);

                DrawMetadata NewDrawMetaData{};
                //NewDrawMetaData.MeshID = CurrentMesh;
                NewDrawMetaData.MeshID = MaterialDataIterator->second[i].TextureIndexMemoryRegion.Offset / (MaterialTextureTypeCount * sizeof(int));
                std::cout << "NewDrawMetaData.MeshID: " << NewDrawMetaData.MeshID << " CurrentMesh: " << CurrentMesh << std::endl;
                NewDrawMetaData.ModelMatrixIndex = AllocatedMemoryRegions[0].Offset / SizeOfMat4;
                
                RENDERER_CORE::MemoryRegion DrawMetaDataAllocatedRegion = DrawMetaDataBufferAllocator.Allocate(SizeOfDrawMetaData);
                RENDERER_CORE::MemoryRegion DrawMetaDataStagingAllocatedRegion = StagingBufferAllocator.Allocate(SizeOfDrawMetaData);
                AllocatedMemoryRegions[1] = DrawMetaDataAllocatedRegion;

                memcpy(StagingBufferPtr + DrawMetaDataStagingAllocatedRegion.Offset, &NewDrawMetaData, DrawMetaDataAllocatedRegion.Size);

                VkBufferCopy CopyRegion{};
                CopyRegion.dstOffset = DrawMetaDataAllocatedRegion.Offset;
                CopyRegion.size = DrawMetaDataAllocatedRegion.Size;
                CopyRegion.srcOffset = DrawMetaDataStagingAllocatedRegion.Offset;
                CopyInfos[DRAWMETA_COPY].CopyRegions.push_back(CopyRegion);

                InstanceIterator++;
            }

            if (IsVertexBufferReallocated || IsMeshJustInserted)
            {
                VertexSize = MeshEntryPtr->Vertices.size() * SizeOfVertex;
                RENDERER_CORE::MemoryRegion AllocatedRegion = StagingBufferAllocator.Allocate(VertexSize);

                memcpy(StagingBufferPtr + AllocatedRegion.Offset, MeshEntryPtr->Vertices.data(), AllocatedRegion.Size);

                VkBufferCopy CopyRegion{};
                CopyRegion.dstOffset = MeshEntryMetaData.MemoryRegions[0].Offset;
                CopyRegion.size = AllocatedRegion.Size;
                CopyRegion.srcOffset = AllocatedRegion.Offset;
                CopyInfos[VERTEX_COPY].CopyRegions.push_back(CopyRegion);
            }
            if (IsIndexBufferReallocated || IsMeshJustInserted)
            {
                IndexSize = MeshEntryPtr->Indices.size() * SizeOfUint32;
                RENDERER_CORE::MemoryRegion AllocatedRegion = StagingBufferAllocator.Allocate(IndexSize);
                memcpy(StagingBufferPtr + AllocatedRegion.Offset, MeshEntryPtr->Indices.data(), AllocatedRegion.Size);

                VkBufferCopy CopyRegion{};
                CopyRegion.dstOffset = MeshEntryMetaData.MemoryRegions[1].Offset;
                CopyRegion.size = IndexSize;
                CopyRegion.srcOffset = AllocatedRegion.Offset;
                CopyInfos[INDEX_COPY].CopyRegions.push_back(CopyRegion);
            }
            if (ModelEntryMetaData.MetaData.IsChanged || IsIndirectBufferReallocated || IsMeshJustInserted)
            {
                ModelEntryMetaData.MetaData.IsChanged = false;

                ExtendedIndirectCommand NewIndirectCommand{};
                NewIndirectCommand.IndexCount = MeshEntryMetaData.DrawInfo.IndexCount;
                NewIndirectCommand.FirstIndex = MeshEntryMetaData.DrawInfo.FirstIndex;
                NewIndirectCommand.InstanceCount = ModelEntryMetaData.MetaData.ReferenceCount;
                NewIndirectCommand.VertexOffset = MeshEntryMetaData.DrawInfo.VertexOffset;
                NewIndirectCommand.FirstInstance = DrawIndexIterator;
                NewIndirectCommand.BoundingBox = MeshEntryPtr->BoundingBox;

                RENDERER_CORE::MemoryRegion AllocatedRegion = StagingBufferAllocator.Allocate(SizeOfIndirectCommand);
                memcpy(StagingBufferPtr + AllocatedRegion.Offset, &NewIndirectCommand, AllocatedRegion.Size);

                VkBufferCopy CopyRegion{};
                CopyRegion.dstOffset = MeshEntryMetaData.MemoryRegions[2].Offset;
                CopyRegion.size = AllocatedRegion.Size;
                CopyRegion.srcOffset = AllocatedRegion.Offset;
                CopyInfos[INDIRECT_COPY].CopyRegions.push_back(CopyRegion);
            }
            DrawIndexIterator += ModelEntryMetaData.MetaData.ReferenceCount;
            CurrentMesh++;
        }
        ModelIterator += ModelEntryMetaData.MetaData.ReferenceCount;
    }
    CopyInfos[VERTEX_COPY].SourceBuffer = StagingBuffer.Buffer.BufferObject;
    CopyInfos[VERTEX_COPY].DestinationBuffer = VertexBuffer.Buffer.BufferObject;
    CopyInfos[INDEX_COPY].SourceBuffer = StagingBuffer.Buffer.BufferObject;
    CopyInfos[INDEX_COPY].DestinationBuffer = IndexBuffer.Buffer.BufferObject;
    CopyInfos[INDIRECT_COPY].SourceBuffer = StagingBuffer.Buffer.BufferObject;
    CopyInfos[INDIRECT_COPY].DestinationBuffer = IndirectBuffer.Buffer.BufferObject;
    CopyInfos[DRAWMETA_COPY].SourceBuffer = StagingBuffer.Buffer.BufferObject;
    CopyInfos[DRAWMETA_COPY].DestinationBuffer = DrawMetaDataBuffer.Buffer.BufferObject;
    
    //Execute copy operations 
    RENDERER_CORE::CopyBuffer(
        CopyInfos,
        RendererContext->DeviceContext.logicalDevice, 
        RendererContext->CommandPool.commandPool, 
        RendererContext->DeviceContext.GraphicsQueue
    );

    StagingBuffer.Destroy(RendererContext->DeviceContext.logicalDevice);
}

void SCENE::MeshManager::EraseModels(MeshEraseInfo Info)
{
    auto& CurrentFrame = Info.FrameIndex;

    auto& CurrentFrameModelEntries = ModelEntries[CurrentFrame];
    if (!CurrentFrameModelEntries.ModelEntries.size())
    {
        LOG_FILE(GLOBAL_LOG_FILE_PATH, COMMON::LOG_SEVERITY_WARNING, "Invalid model erasing operation. No existing model detected. Returning...");
        return;
    }

    auto& EnabledMeshCount = PerformanceModeBuffers.EnabledMeshCount[CurrentFrame];

    auto& VertexBuffer = PerformanceModeBuffers.VertexBuffers[CurrentFrame];
    auto& IndexBuffer = PerformanceModeBuffers.IndexBuffers[CurrentFrame];
    auto& IndirectBuffer = PerformanceModeBuffers.IndirectBuffers[CurrentFrame];
    auto& ModelMatricesBuffer = PerformanceModeBuffers.ModelMatricesBuffers[CurrentFrame];
    auto& DrawMetaDataBuffer = PerformanceModeBuffers.DrawMetaDataBuffer[CurrentFrame];

    auto& VertexBufferAllocator = VertexBuffer.Allocator;
    auto& IndexBufferAllocator = IndexBuffer.Allocator;
    auto& IndirectBufferAllocator = IndirectBuffer.Allocator;
    auto& ModelMatricesBufferAllocator = ModelMatricesBuffer.Allocator;
    auto& DrawMetaDataBufferAllocator = DrawMetaDataBuffer.Allocator;

    size_t SizeOfDrawMetaData = sizeof(DrawMetadata) , SizeOfMat4 = sizeof(glm::mat4);

    //Check if any of the indirect commands are changed
    bool AreIndirectCommandsChanged = false;
    for (auto& ModelInstancePtr : Info.ModelInstances)
    {
        if (!ModelInstancePtr || !ModelInstancePtr->Source) continue;

        auto& ModelIterator = CurrentFrameModelEntries.ModelEntries.find(ModelInstancePtr->Source);
        if (ModelIterator == CurrentFrameModelEntries.ModelEntries.end()) continue;
        ModelIterator->second.MetaData.IsChanged = false;

        auto& ModelInstanceIterator = ModelIterator->second.Instances.find(ModelInstancePtr);
        if (ModelInstanceIterator == ModelIterator->second.Instances.end()) continue;

        ModelMatricesBufferAllocator.Free(ModelInstanceIterator->second[0]);
        ModelIterator->second.MetaData.ReferenceCount--;
        DrawMetaDataBufferAllocator.Free(ModelInstanceIterator->second[1]);
        ModelIterator->second.Instances.erase(ModelInstancePtr);

        if (ModelIterator->second.MetaData.ReferenceCount)
        {
            ModelIterator->second.MetaData.IsChanged = true;
            AreIndirectCommandsChanged = true;
            continue;
        }

        for (auto& MeshEntry : ModelIterator->second.MeshEntries)
        {
            const RENDERER_CORE::MemoryRegion& VertexMemoryRegion = MeshEntry.MetaData.MemoryRegions[0];
            const RENDERER_CORE::MemoryRegion& IndexMemoryRegion = MeshEntry.MetaData.MemoryRegions[1];
            const RENDERER_CORE::MemoryRegion& IndirectMemoryRegion = MeshEntry.MetaData.MemoryRegions[2];

            VertexBufferAllocator.Free(VertexMemoryRegion);
            IndexBufferAllocator.Free(IndexMemoryRegion);
            IndirectBufferAllocator.Free(IndirectMemoryRegion);

            EnabledMeshCount--;
        }
        CurrentFrameModelEntries.ModelEntries.erase(ModelInstancePtr->Source);
    }

    //Return in case all the meshes were erased.
    if (!CurrentFrameModelEntries.ModelEntries.size()) return;

    //Decide whether defragmentation is required or not
    double VertexFragmentationPercent = VertexBufferAllocator.GetFragmentationPercent(),
        IndexFragmentationPercent = IndexBufferAllocator.GetFragmentationPercent(),
        IndirectFragmentationPercent = IndirectBufferAllocator.GetFragmentationPercent();

    double Threshold = 0.8;
    bool VertexBufferNeedsDefragmentation = VertexFragmentationPercent > Threshold,
        IndexBufferNeedsDefragmentation = IndexFragmentationPercent > Threshold,
        IndirectBufferNeedsDefragmentation = IndirectFragmentationPercent > 0.0;

    bool ShouldDefragment = VertexBufferNeedsDefragmentation || IndexBufferNeedsDefragmentation || IndirectBufferNeedsDefragmentation;
    
    std::vector<RENDERER_CORE::MemoryRegion*> VertexAllocatedRegions;
    std::vector<RENDERER_CORE::MemoryRegion*> IndexAllocatedRegions;
    std::vector<RENDERER_CORE::MemoryRegion*> IndirectCommandAllocatedRegions;
    VertexAllocatedRegions.reserve(EnabledMeshCount);
    IndexAllocatedRegions.reserve(EnabledMeshCount);
    IndirectCommandAllocatedRegions.reserve(EnabledMeshCount);

    size_t VertexStagingBufferSize = VertexBufferAllocator.GetCapacity() - VertexBufferAllocator.GetTotalFreeSpace(),
        IndexStagingBufferSize = IndexBufferAllocator.GetCapacity() - IndexBufferAllocator.GetTotalFreeSpace(),
        IndirectStagingBufferSize = IndirectBufferAllocator.GetCapacity() - IndirectBufferAllocator.GetTotalFreeSpace(),
        DrawMetaDataStagingBufferSize = DrawMetaDataBufferAllocator.GetCapacity() - DrawMetaDataBufferAllocator.GetTotalFreeSpace();

    size_t StagingBufferSize = DrawMetaDataStagingBufferSize;
    if (VertexBufferNeedsDefragmentation) StagingBufferSize += VertexStagingBufferSize;
    if (IndexBufferNeedsDefragmentation) StagingBufferSize += IndexStagingBufferSize;
    if (IndirectBufferNeedsDefragmentation) StagingBufferSize += IndirectStagingBufferSize;

    if (!DrawMetaDataStagingBufferSize || !StagingBufferSize)
    {
        LOG_FILE(GLOBAL_LOG_FILE_PATH, COMMON::LOG_SEVERITY_VERBOSE, "Unable to proceed model erasing operation, faulty staging buffer!");
        throw std::runtime_error("Faulty staging buffer!");
    }

    RENDERER_CORE::VirtualArenaAllocator StagingBufferAllocator(StagingBufferSize);
    RENDERER_CORE::PersistentBuffer StagingBuffer;
    uint8_t* StagingBufferPtr = nullptr;
    if (StagingBufferSize)
    {
        RENDERER_CORE::CreateStagingBuffer(
            RendererContext->DeviceContext.physicalDevice,
            RendererContext->DeviceContext.logicalDevice,
            StagingBufferSize,
            StagingBuffer.Buffer
        );

        StagingBuffer.Map(RendererContext->DeviceContext.logicalDevice, 0, StagingBufferSize, 0);
        StagingBufferPtr = reinterpret_cast<uint8_t*>(StagingBuffer.MappedMemory);
    }
    if (!StagingBufferPtr)
    {
        LOG_FILE(GLOBAL_LOG_FILE_PATH, COMMON::LOG_SEVERITY_ERROR, "Unable to proceed model erasing operation, failed staging buffer creation!");
        throw std::runtime_error("Failed staging buffer creation!");
    }

    std::vector<RENDERER_CORE::BufferCopyInfo> CopyInfos(4);
    //Redistribute the model matrixes.
    size_t ModelIterator = 0;
    uint32_t CurrentMesh = 0;

    DrawMetaDataBufferAllocator.Reset();
    for (auto& [ModelPtr, ModelEntryMetaData] : CurrentFrameModelEntries.ModelEntries)
    {
        //Gather memory regions to defragment. 
        for (auto& MeshEntry : ModelEntryMetaData.MeshEntries)
        {
            //Local instance index iterator
            size_t InstanceIterator = 0;
            for (auto& [InstancePtr, AllocatedMemoryRegions] : ModelEntryMetaData.Instances)
            {
                DrawMetadata NewDrawMetaData{};
                NewDrawMetaData.MeshID = CurrentMesh;
                NewDrawMetaData.ModelMatrixIndex = AllocatedMemoryRegions[0].Offset / SizeOfMat4;

                RENDERER_CORE::MemoryRegion DrawMetaDataAllocatedRegion = DrawMetaDataBufferAllocator.Allocate(SizeOfDrawMetaData);
                RENDERER_CORE::MemoryRegion DrawMetaDataStagingAllocatedRegion = StagingBufferAllocator.Allocate(SizeOfDrawMetaData);
                AllocatedMemoryRegions[1] = DrawMetaDataAllocatedRegion;

                memcpy(StagingBufferPtr + DrawMetaDataStagingAllocatedRegion.Offset, &NewDrawMetaData, DrawMetaDataAllocatedRegion.Size);

                VkBufferCopy CopyRegion{};
                CopyRegion.dstOffset = DrawMetaDataAllocatedRegion.Offset;
                CopyRegion.size = DrawMetaDataAllocatedRegion.Size;
                CopyRegion.srcOffset = DrawMetaDataStagingAllocatedRegion.Offset;
                CopyInfos[DRAWMETA_COPY].CopyRegions.push_back(CopyRegion);

                InstanceIterator++;
            }
 
            if (!ShouldDefragment) continue;

            if (VertexBufferNeedsDefragmentation) VertexAllocatedRegions.push_back(&MeshEntry.MetaData.MemoryRegions[0]);
            if (IndexBufferNeedsDefragmentation) IndexAllocatedRegions.push_back(&MeshEntry.MetaData.MemoryRegions[1]);
            if ((VertexBufferNeedsDefragmentation || IndexBufferNeedsDefragmentation || IndirectBufferNeedsDefragmentation)) IndirectCommandAllocatedRegions.push_back(&MeshEntry.MetaData.MemoryRegions[2]);
        }
        ModelIterator += ModelEntryMetaData.MetaData.ReferenceCount;
    }

    if (ShouldDefragment || AreIndirectCommandsChanged)
    {
        //Defragmenting the buffer allocators
        if (VertexBufferNeedsDefragmentation) VertexBufferAllocator.Defragment(VertexAllocatedRegions);
        if (IndexBufferNeedsDefragmentation) IndexBufferAllocator.Defragment(IndexAllocatedRegions);
        if ((VertexBufferNeedsDefragmentation || IndexBufferNeedsDefragmentation || IndirectBufferNeedsDefragmentation)) IndirectBufferAllocator.Defragment(IndirectCommandAllocatedRegions);

        size_t DrawIndexIterator = 0;
        CurrentMesh = 0;
        //Produce copy informations
        for (auto& [ModelPtr, ModelEntryMetaData] : CurrentFrameModelEntries.ModelEntries)
        {
            for (auto& MeshEntry : ModelEntryMetaData.MeshEntries)
            {
                auto& MeshEntryPtr = MeshEntry.MeshPtr;
                auto& MeshEntryMetaData = MeshEntry.MetaData;

                if (VertexBufferNeedsDefragmentation)
                {
                    const RENDERER_CORE::MemoryRegion& AllocatedRegion = MeshEntryMetaData.MemoryRegions[0];
                    const RENDERER_CORE::MemoryRegion& StagingBufferAllocatedRegion = StagingBufferAllocator.Allocate(AllocatedRegion.Size);
                    memcpy(StagingBufferPtr + StagingBufferAllocatedRegion.Offset, MeshEntryPtr->Vertices.data(), StagingBufferAllocatedRegion.Size);

                    VkBufferCopy CopyRegion{};
                    CopyRegion.dstOffset = AllocatedRegion.Offset;
                    CopyRegion.size = AllocatedRegion.Size;
                    CopyRegion.srcOffset = StagingBufferAllocatedRegion.Offset;
                    CopyInfos[0].CopyRegions.push_back(CopyRegion);

                    MeshEntryMetaData.DrawInfo.VertexOffset = AllocatedRegion.Offset / sizeof(Vertex3D);
                }
                if (IndexBufferNeedsDefragmentation)
                {
                    const RENDERER_CORE::MemoryRegion& AllocatedRegion = MeshEntryMetaData.MemoryRegions[1];
                    const RENDERER_CORE::MemoryRegion& StagingBufferAllocatedRegion = StagingBufferAllocator.Allocate(AllocatedRegion.Size);
                    memcpy(StagingBufferPtr + StagingBufferAllocatedRegion.Offset, MeshEntryPtr->Indices.data(), StagingBufferAllocatedRegion.Size);

                    VkBufferCopy CopyRegion{};
                    CopyRegion.dstOffset = AllocatedRegion.Offset;
                    CopyRegion.size = AllocatedRegion.Size;
                    CopyRegion.srcOffset = StagingBufferAllocatedRegion.Offset;
                    CopyInfos[1].CopyRegions.push_back(CopyRegion);

                    MeshEntryMetaData.DrawInfo.FirstIndex = AllocatedRegion.Offset / sizeof(uint32_t);
                }
                if (ModelEntryMetaData.MetaData.IsChanged || VertexBufferNeedsDefragmentation || IndexBufferNeedsDefragmentation || IndirectBufferNeedsDefragmentation)
                {
                    ModelEntryMetaData.MetaData.IsChanged = false;

                    ExtendedIndirectCommand NewIndirectCommand{};
                    NewIndirectCommand.IndexCount = MeshEntryMetaData.DrawInfo.IndexCount;
                    NewIndirectCommand.FirstIndex = MeshEntryMetaData.DrawInfo.FirstIndex;
                    NewIndirectCommand.InstanceCount = ModelEntryMetaData.MetaData.ReferenceCount;
                    NewIndirectCommand.VertexOffset = MeshEntryMetaData.DrawInfo.VertexOffset;
                    NewIndirectCommand.BoundingBox = MeshEntryPtr->BoundingBox;
                    NewIndirectCommand.FirstInstance = DrawIndexIterator;

                    const RENDERER_CORE::MemoryRegion& AllocatedRegion = MeshEntryMetaData.MemoryRegions[2];
                    const RENDERER_CORE::MemoryRegion& StagingBufferAllocatedRegion = StagingBufferAllocator.Allocate(AllocatedRegion.Size);
                    memcpy(StagingBufferPtr + StagingBufferAllocatedRegion.Offset, &NewIndirectCommand, StagingBufferAllocatedRegion.Size);

                    VkBufferCopy CopyRegion{};
                    CopyRegion.dstOffset = AllocatedRegion.Offset;
                    CopyRegion.size = AllocatedRegion.Size;
                    CopyRegion.srcOffset = StagingBufferAllocatedRegion.Offset;
                    CopyInfos[2].CopyRegions.push_back(CopyRegion);
                }
                CurrentMesh++;
                DrawIndexIterator += ModelEntryMetaData.MetaData.ReferenceCount;
            }
        }
    }
    CopyInfos[VERTEX_COPY].SourceBuffer = StagingBuffer.Buffer.BufferObject;
    CopyInfos[VERTEX_COPY].DestinationBuffer = VertexBuffer.Buffer.BufferObject;
    CopyInfos[INDEX_COPY].SourceBuffer = StagingBuffer.Buffer.BufferObject;
    CopyInfos[INDEX_COPY].DestinationBuffer = IndexBuffer.Buffer.BufferObject;
    CopyInfos[INDIRECT_COPY].SourceBuffer = StagingBuffer.Buffer.BufferObject;
    CopyInfos[INDIRECT_COPY].DestinationBuffer = IndirectBuffer.Buffer.BufferObject;
    CopyInfos[DRAWMETA_COPY].SourceBuffer = StagingBuffer.Buffer.BufferObject;
    CopyInfos[DRAWMETA_COPY].DestinationBuffer = DrawMetaDataBuffer.Buffer.BufferObject;

    //Execute copy operations 
    RENDERER_CORE::CopyBuffer(
        CopyInfos,
        RendererContext->DeviceContext.logicalDevice,
        RendererContext->CommandPool.commandPool,
        RendererContext->DeviceContext.GraphicsQueue
    );

    StagingBuffer.Destroy(RendererContext->DeviceContext.logicalDevice);
}


void SCENE::MeshManager::UpdateTextureDescriptors(MeshTextureUpdateInfo Info)
{
    auto FrameIndex = Info.FrameIndex;
    auto& TextureImportManager = *Info.TextureImportManagerPtr;
    auto& DescriptorSets = Info.TargetDescriptorSets;

    auto& CurrentDescriptorSet = DescriptorSets[FrameIndex];

    TextureImportManager.UpdateDescriptors(FrameIndex);
    auto& CurrentFrameEntries = ModelEntries[FrameIndex];

    if (CurrentFrameEntries.MaterialUpdateList.empty()) return;

    auto& CurrentTextureIndexBuffer = PerformanceModeBuffers.TexturesIndexBuffers[FrameIndex];
    auto& TextureIndexBufferAllocator = CurrentTextureIndexBuffer.Allocator;
    auto Capacity = TextureIndexBufferAllocator.GetCapacity() - TextureIndexBufferAllocator.GetTotalFreeSpace();
    auto& TexturesIndexBufferReallocated = PerformanceModeBuffers.TexturesIndexBuffersReallocated[FrameIndex];

    uint32_t MaterialTextureTypeCount = static_cast<uint32_t>(MATERIAL_TEXTURE_TYPE_META_DATA_SIZE);
    uint32_t Inserted = 0;
    size_t SizeOfTextureIndices = MaterialTextureTypeCount * sizeof(int);

    RENDERER_CORE::BufferCopyInfo CopyInfo{};
    for (auto& ModelInstancePtr : CurrentFrameEntries.MaterialUpdateList)
    {
        auto& MaterialMetaDataIterator = CurrentFrameEntries.InstanceMaterialMetaDatas.find(ModelInstancePtr);
        for (auto& MetaData : MaterialMetaDataIterator->second)
        {
            std::cout << "MetaData.TextureIndexMemoryRegion.Offset: " << MetaData.TextureIndexMemoryRegion.Offset << std::endl;
            for (uint32_t i = 0; i < MaterialTextureTypeCount; i++)
            {
                auto TextureIndex = MetaData.MaterialPtr->GetTexture(static_cast<MaterialTextureType>(i));
                if (TextureIndex)
                {
                    auto Iterator = TextureImportManager.TextureDatas.find(TextureIndex);
                    if (Iterator == TextureImportManager.TextureDatas.end())
                    {
                        MetaData.TextureIndexes[i] = -1;
                        continue;
                    }
                    auto& TextureDataEntry = TextureImportManager.TextureDatas[TextureIndex];

                    MetaData.TextureIndexes[i] = TextureDataEntry.DescriptorSlots[FrameIndex];
                }
                else MetaData.TextureIndexes[i] = -1;
            }
        }
    }
     
    if (TexturesIndexBufferReallocated)
    {
        CurrentTextureIndexBuffer.Buffer.Destroy(RendererContext->DeviceContext.logicalDevice);
        RENDERER_CORE::CreateBuffer(
            RendererContext->DeviceContext.physicalDevice,
            RendererContext->DeviceContext.logicalDevice,
            TextureIndexBufferAllocator.GetCapacity(),
            VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
            VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
            CurrentTextureIndexBuffer.Buffer
        );

        RENDERER_CORE::DescriptorSetWriteBuffer DrawMetaDataBufferWrite(
            CurrentTextureIndexBuffer.Buffer,
            TextureIndexBufferAllocator.GetCapacity(),
            0,
            CurrentDescriptorSet,
            VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
        );

        RENDERER_CORE::WriteDescriptorSets(
            RendererContext->DeviceContext.logicalDevice,
            { DrawMetaDataBufferWrite },
            {}
        );
    }

    RENDERER_CORE::PersistentBuffer TextureIndexStagingBuffer;
    size_t StagingBufferSize = TexturesIndexBufferReallocated ? Capacity :
                               CurrentFrameEntries.MaterialUpdateList.size() * SizeOfTextureIndices;
    RENDERER_CORE::VirtualArenaAllocator StagingBufferAllocator(StagingBufferSize);
    RENDERER_CORE::CreateStagingBuffer(
        RendererContext->DeviceContext.physicalDevice,
        RendererContext->DeviceContext.logicalDevice,
        StagingBufferSize,
        TextureIndexStagingBuffer.Buffer
    );
    TextureIndexStagingBuffer.Map(RendererContext->DeviceContext.logicalDevice, 0, StagingBufferSize, 0);
    auto StagingBufferPtr = reinterpret_cast<uint8_t*>(TextureIndexStagingBuffer.MappedMemory);

    if (!StagingBufferPtr) return;

    if (TexturesIndexBufferReallocated)
    {
        for (auto& [ModelInstancePtr,MaterialMetaDatas] : CurrentFrameEntries.InstanceMaterialMetaDatas)
        {
            for (auto& MetaData : MaterialMetaDatas)
            {
                auto Region = StagingBufferAllocator.Allocate(SizeOfTextureIndices);
                memcpy(StagingBufferPtr + Region.Offset, MetaData.TextureIndexes.data(), Region.Size);

                VkBufferCopy CopyRegion{};
                CopyRegion.dstOffset = MetaData.TextureIndexMemoryRegion.Offset;
                CopyRegion.size = Region.Size;
                CopyRegion.srcOffset = Region.Offset;
                CopyInfo.CopyRegions.push_back(CopyRegion);
            }
        }
    }
    else
    {
        for (auto& ModelInstancePtr : CurrentFrameEntries.MaterialUpdateList)
        {
            auto& MaterialMetaDataIterator = CurrentFrameEntries.InstanceMaterialMetaDatas.find(ModelInstancePtr);
            for (auto& MetaData : MaterialMetaDataIterator->second)
            {
                auto Region = StagingBufferAllocator.Allocate(SizeOfTextureIndices);
                memcpy(StagingBufferPtr + Region.Offset, MetaData.TextureIndexes.data(), Region.Size);

                VkBufferCopy CopyRegion{};
                CopyRegion.dstOffset = MetaData.TextureIndexMemoryRegion.Offset;
                CopyRegion.size = Region.Size;
                CopyRegion.srcOffset = Region.Offset;
                CopyInfo.CopyRegions.push_back(CopyRegion);
            }
        }
    }
    CopyInfo.SourceBuffer = TextureIndexStagingBuffer.Buffer.BufferObject;
    CopyInfo.DestinationBuffer = CurrentTextureIndexBuffer.Buffer.BufferObject;
  
    RENDERER_CORE::CopyBuffer(
        { CopyInfo },
        RendererContext->DeviceContext.logicalDevice,
        RendererContext->CommandPool.commandPool,
        RendererContext->DeviceContext.GraphicsQueue
    );

    TextureIndexStagingBuffer.Destroy(RendererContext->DeviceContext.logicalDevice);
    TexturesIndexBufferReallocated = false;
    CurrentFrameEntries.MaterialUpdateList.clear();
}
Editor is loading...
Leave a Comment