<commit_before>// Do not include this in headers, please
#ifndef __IRR_I_GPU_OBJECT_FROM_ASSET_CONVERTER_H_INCLUDED__
#define __IRR_I_GPU_OBJECT_FROM_ASSET_CONVERTER_H_INCLUDED__

#include "irr/core/Types.h"
#include "irr/asset/IAssetManager.h"
#include "IDriver.h"
#include "IDriverMemoryBacked.h"
#include "irr/video/SGPUMesh.h"
#include "irr/video/CGPUSkinnedMesh.h"
#include "irr/asset/ICPUSkinnedMeshBuffer.h"
#include "CLogger.h"
#include "irr/video/asset_traits.h"
#include "irr/core/alloc/LinearAddressAllocator.h"

namespace irr 
{
namespace video
{

class IGPUObjectFromAssetConverter
{
protected:
    asset::IAssetManager* m_assetManager;
    video::IDriver* m_driver;

public:
    IGPUObjectFromAssetConverter(asset::IAssetManager* _assetMgr, video::IDriver* _drv) : m_assetManager{_assetMgr}, m_driver{_drv} {}

    virtual ~IGPUObjectFromAssetConverter() = default;

    inline virtual core::vector<typename video::asset_traits<asset::ICPUBuffer>::GPUObjectType*> create(asset::ICPUBuffer** const _begin, asset::ICPUBuffer** const _end);
    inline virtual core::vector<typename video::asset_traits<asset::ICPUMeshBuffer>::GPUObjectType*> create(asset::ICPUMeshBuffer** const _begin, asset::ICPUMeshBuffer** const _end);
    inline virtual core::vector<typename video::asset_traits<asset::ICPUMesh>::GPUObjectType*> create(asset::ICPUMesh** const _begin, asset::ICPUMesh** const _end);
    inline virtual core::vector<typename video::asset_traits<asset::ICPUTexture>::GPUObjectType*> create(asset::ICPUTexture** const _begin, asset::ICPUTexture** const _end);

    template<typename AssetType>
    core::vector<typename video::asset_traits<AssetType>::GPUObjectType*> getGPUObjectsFromAssets(AssetType** const _begin, AssetType** const _end)
    {
        core::vector<AssetType*> notFound;
        core::vector<size_t> pos;
        core::vector<typename video::asset_traits<AssetType>::GPUObjectType*> res;
        AssetType** it = _begin;
        while (it != _end)
        {
            core::IReferenceCounted* gpu = m_assetManager->findGPUObject(*it);
            if (!gpu)
            {
                notFound.push_back(*it);
                pos.push_back(it - _begin);
            }
            else res.push_back(dynamic_cast<typename video::asset_traits<AssetType>::GPUObjectType*>(gpu));
            ++it;
        }

        core::vector<typename video::asset_traits<AssetType>::GPUObjectType*> created = create(notFound.data(), notFound.data() + notFound.size());
        for (size_t i = 0u; i < created.size(); ++i)
        {
            m_assetManager->convertAssetToEmptyCacheHandle(notFound[i], created[i]);
            res.insert(res.begin() + pos[i], created[i]);
            irr::static_if<std::is_same_v<asset::ICPUTexture, AssetType>>(
                [&created, i](auto f) { created[i]->drop(); } // IGPUTexture is not grabbed when set in SGPUMaterial, so we have to drop it after inserting into cache (done by convertAssetToEmptyCacheHandle)
            );
        }

        return res;
    }

protected:
    template<typename T>
    static inline core::vector<size_t> eliminateDuplicatesAndGenRedirs(core::vector<T*>& _input)
    {
        core::vector<size_t> redirs;

        core::unordered_map<T*, size_t> firstOccur;
        size_t i = 0u;
        for (T* el : _input)
        {
            auto r = firstOccur.insert({ el, i });
            redirs.push_back(r.first->second);
            if (r.second)
                ++i;
        }
        for (const auto& p : firstOccur)
            _input.push_back(p.first);
        _input.erase(_input.begin(), _input.begin() + (_input.size() - firstOccur.size()));
        std::sort(_input.begin(), _input.end(), [&firstOccur](T* a, T* b) { return firstOccur[a] < firstOccur[b]; });

        return redirs;
    }
};

auto IGPUObjectFromAssetConverter::create(asset::ICPUBuffer** const _begin, asset::ICPUBuffer** const _end) -> core::vector<typename video::asset_traits<asset::ICPUBuffer>::GPUObjectType*>
{
    const uint64_t alignment = 
        std::max(
            std::max(m_driver->getRequiredTBOAlignment(), m_driver->getRequiredUBOAlignment()),
            std::max(m_driver->getRequiredSSBOAlignment(), 16u)
        );

    core::vector<typename video::asset_traits<asset::ICPUBuffer>::GPUObjectType*> res;
    res.reserve(_end-_begin);

    core::LinearAddressAllocator<uint64_t> addrAllctr(nullptr, nullptr, alignment, m_driver->getMaxBufferSize());
    asset::ICPUBuffer** it = _begin;
    while (it != _end)
    {
        const uint64_t addr = addrAllctr.alloc_addr((*it)->getSize(), alignment);
        assert(addr != decltype(addrAllctr)::invalid_address);
        if (addr == decltype(addrAllctr)::invalid_address)
            return {};
        res.push_back(new typename video::asset_traits<asset::ICPUBuffer>::GPUObjectType{addr});
        ++it;
    }

    auto reqs = m_driver->getDeviceLocalGPUMemoryReqs();
    reqs.vulkanReqs.size = addrAllctr.get_allocated_size();
    reqs.vulkanReqs.alignment = alignment;

    IGPUBuffer* gpubuffer = m_driver->createGPUBufferOnDedMem(reqs, true);

    for (size_t i = 0u; i < res.size(); ++i)
    {
        res[i]->setBuffer(gpubuffer);
        gpubuffer->updateSubRange(video::IDriverMemoryAllocation::MemoryRange(res[i]->getOffset(), _begin[i]->getSize()), _begin[i]->getPointer());
    }
    gpubuffer->drop();

    return res;
}<commit_msg>Little fix due to addr alocator api change<commit_after>// Do not include this in headers, please
#ifndef __IRR_I_GPU_OBJECT_FROM_ASSET_CONVERTER_H_INCLUDED__
#define __IRR_I_GPU_OBJECT_FROM_ASSET_CONVERTER_H_INCLUDED__

#include "irr/core/Types.h"
#include "irr/asset/IAssetManager.h"
#include "IDriver.h"
#include "IDriverMemoryBacked.h"
#include "irr/video/SGPUMesh.h"
#include "irr/video/CGPUSkinnedMesh.h"
#include "irr/asset/ICPUSkinnedMeshBuffer.h"
#include "CLogger.h"
#include "irr/video/asset_traits.h"
#include "irr/core/alloc/LinearAddressAllocator.h"

namespace irr 
{
namespace video
{

class IGPUObjectFromAssetConverter
{
protected:
    asset::IAssetManager* m_assetManager;
    video::IDriver* m_driver;

public:
    IGPUObjectFromAssetConverter(asset::IAssetManager* _assetMgr, video::IDriver* _drv) : m_assetManager{_assetMgr}, m_driver{_drv} {}

    virtual ~IGPUObjectFromAssetConverter() = default;

    inline virtual core::vector<typename video::asset_traits<asset::ICPUBuffer>::GPUObjectType*> create(asset::ICPUBuffer** const _begin, asset::ICPUBuffer** const _end);
    inline virtual core::vector<typename video::asset_traits<asset::ICPUMeshBuffer>::GPUObjectType*> create(asset::ICPUMeshBuffer** const _begin, asset::ICPUMeshBuffer** const _end);
    inline virtual core::vector<typename video::asset_traits<asset::ICPUMesh>::GPUObjectType*> create(asset::ICPUMesh** const _begin, asset::ICPUMesh** const _end);
    inline virtual core::vector<typename video::asset_traits<asset::ICPUTexture>::GPUObjectType*> create(asset::ICPUTexture** const _begin, asset::ICPUTexture** const _end);

    template<typename AssetType>
    core::vector<typename video::asset_traits<AssetType>::GPUObjectType*> getGPUObjectsFromAssets(AssetType** const _begin, AssetType** const _end)
    {
        core::vector<AssetType*> notFound;
        core::vector<size_t> pos;
        core::vector<typename video::asset_traits<AssetType>::GPUObjectType*> res;
        AssetType** it = _begin;
        while (it != _end)
        {
            core::IReferenceCounted* gpu = m_assetManager->findGPUObject(*it);
            if (!gpu)
            {
                notFound.push_back(*it);
                pos.push_back(it - _begin);
            }
            else res.push_back(dynamic_cast<typename video::asset_traits<AssetType>::GPUObjectType*>(gpu));
            ++it;
        }

        core::vector<typename video::asset_traits<AssetType>::GPUObjectType*> created = create(notFound.data(), notFound.data() + notFound.size());
        for (size_t i = 0u; i < created.size(); ++i)
        {
            m_assetManager->convertAssetToEmptyCacheHandle(notFound[i], created[i]);
            res.insert(res.begin() + pos[i], created[i]);
            irr::static_if<std::is_same_v<asset::ICPUTexture, AssetType>>(
                [&created, i](auto f) { created[i]->drop(); } // IGPUTexture is not grabbed when set in SGPUMaterial, so we have to drop it after inserting into cache (done by convertAssetToEmptyCacheHandle)
            );
        }

        return res;
    }

protected:
    template<typename T>
    static inline core::vector<size_t> eliminateDuplicatesAndGenRedirs(core::vector<T*>& _input)
    {
        core::vector<size_t> redirs;

        core::unordered_map<T*, size_t> firstOccur;
        size_t i = 0u;
        for (T* el : _input)
        {
            auto r = firstOccur.insert({ el, i });
            redirs.push_back(r.first->second);
            if (r.second)
                ++i;
        }
        for (const auto& p : firstOccur)
            _input.push_back(p.first);
        _input.erase(_input.begin(), _input.begin() + (_input.size() - firstOccur.size()));
        std::sort(_input.begin(), _input.end(), [&firstOccur](T* a, T* b) { return firstOccur[a] < firstOccur[b]; });

        return redirs;
    }
};

auto IGPUObjectFromAssetConverter::create(asset::ICPUBuffer** const _begin, asset::ICPUBuffer** const _end) -> core::vector<typename video::asset_traits<asset::ICPUBuffer>::GPUObjectType*>
{
    const uint64_t alignment = 
        std::max(
            std::max(m_driver->getRequiredTBOAlignment(), m_driver->getRequiredUBOAlignment()),
            std::max(m_driver->getRequiredSSBOAlignment(), 16u)
        );

    core::vector<typename video::asset_traits<asset::ICPUBuffer>::GPUObjectType*> res;
    res.reserve(_end-_begin);

    core::LinearAddressAllocator<uint64_t> addrAllctr(nullptr, 0u, 0u, alignment, m_driver->getMaxBufferSize());
    asset::ICPUBuffer** it = _begin;
    while (it != _end)
    {
        const uint64_t addr = addrAllctr.alloc_addr((*it)->getSize(), alignment);
        assert(addr != decltype(addrAllctr)::invalid_address);
        if (addr == decltype(addrAllctr)::invalid_address)
            return {};
        res.push_back(new typename video::asset_traits<asset::ICPUBuffer>::GPUObjectType{addr});
        ++it;
    }

    auto reqs = m_driver->getDeviceLocalGPUMemoryReqs();
    reqs.vulkanReqs.size = addrAllctr.get_allocated_size();
    reqs.vulkanReqs.alignment = alignment;

    IGPUBuffer* gpubuffer = m_driver->createGPUBufferOnDedMem(reqs, true);

    for (size_t i = 0u; i < res.size(); ++i)
    {
        res[i]->setBuffer(gpubuffer);
        gpubuffer->updateSubRange(video::IDriverMemoryAllocation::MemoryRange(res[i]->getOffset(), _begin[i]->getSize()), _begin[i]->getPointer());
    }
    gpubuffer->drop();

    return res;
}
{'fraction_non_alphanumeric': 0.13864224935257122, 'fraction_numerical': 0.0022197558268590455, 'mean_word_length': 3.855410866636731, 'pattern_counts': {'":': 0, '<': 73, '<?xml version=': 0, '>': 103, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3010923', 'n_tokens_mistral': 3523, 'n_tokens_neox': 3456, 'n_words': 602}