diff options
| author | assiduous <assiduous@diligentgraphics.com> | 2020-12-09 02:48:28 +0000 |
|---|---|---|
| committer | assiduous <assiduous@diligentgraphics.com> | 2020-12-09 02:48:28 +0000 |
| commit | 60ce41d5b736dbb7c5799897bdadfc2a34d6c16a (patch) | |
| tree | eaa25323ad47521d745a1a354754ed99907c6d38 /AssetLoader | |
| parent | GLTF Loader: enabled caching compressed textures (diff) | |
| download | DiligentTools-60ce41d5b736dbb7c5799897bdadfc2a34d6c16a.tar.gz DiligentTools-60ce41d5b736dbb7c5799897bdadfc2a34d6c16a.zip | |
Reworked GLTF resource manager to use BufferSuballocator and DynamicTextureAtlas
Diffstat (limited to 'AssetLoader')
| -rw-r--r-- | AssetLoader/interface/GLTFLoader.hpp | 65 | ||||
| -rw-r--r-- | AssetLoader/interface/GLTFResourceManager.hpp | 296 | ||||
| -rw-r--r-- | AssetLoader/src/GLTFLoader.cpp | 115 | ||||
| -rw-r--r-- | AssetLoader/src/GLTFResourceManager.cpp | 274 |
4 files changed, 180 insertions, 570 deletions
diff --git a/AssetLoader/interface/GLTFLoader.hpp b/AssetLoader/interface/GLTFLoader.hpp index 68747c5..cbfd3b0 100644 --- a/AssetLoader/interface/GLTFLoader.hpp +++ b/AssetLoader/interface/GLTFLoader.hpp @@ -56,7 +56,7 @@ namespace GLTF struct GLTFCacheInfo { - GLTFResourceManager* pResourceMgr = nullptr; + ResourceManager* pResourceMgr = nullptr; Uint8 IndexBufferIdx = 0; Uint8 VertexBuffer0Idx = 0; @@ -346,59 +346,36 @@ struct Model void PrepareGPUResources(IRenderDevice* pDevice, IDeviceContext* pCtx); - IBuffer* GetBuffer(BUFFER_ID BuffId, IRenderDevice* pDevice, IDeviceContext* pCtx) + IBuffer* GetBuffer(BUFFER_ID BuffId) { - VERIFY_EXPR(BuffId < BUFFER_ID_NUM_BUFFERS); - auto& Buff = Buffers[BuffId]; - if (Buff.pBuffer) - return Buff.pBuffer; - else if (Buff.pCacheAllocation) - return Buff.pCacheAllocation->GetBuffer(pDevice, pCtx); - else - return nullptr; + return Buffers[BuffId].pBuffer; + } + + ITexture* GetTexture(Uint32 Index) + { + return Textures[Index].pTexture; } Uint32 GetFirstIndexLocation() const { auto& IndBuff = Buffers[BUFFER_ID_INDEX]; - VERIFY(!IndBuff.pCacheAllocation || IndBuff.pCacheAllocation->GetRegion().UnalignedOffset % sizeof(Uint32) == 0, + VERIFY(!IndBuff.pSuballocation || IndBuff.pSuballocation->GetOffset() % sizeof(Uint32) == 0, "Allocation offset is not multiple of sizeof(Uint32)"); - return IndBuff.pCacheAllocation ? - static_cast<Uint32>(IndBuff.pCacheAllocation->GetRegion().UnalignedOffset / sizeof(Uint32)) : + return IndBuff.pSuballocation ? + static_cast<Uint32>(IndBuff.pSuballocation->GetOffset() / sizeof(Uint32)) : 0; } Uint32 GetBaseVertex() const { auto& VertBuff = Buffers[BUFFER_ID_VERTEX0]; - VERIFY(!VertBuff.pCacheAllocation || VertBuff.pCacheAllocation->GetRegion().UnalignedOffset % sizeof(VertexAttribs0) == 0, + VERIFY(!VertBuff.pSuballocation || VertBuff.pSuballocation->GetOffset() % sizeof(VertexAttribs0) == 0, "Allocation offset is not multiple of sizeof(VertexAttribs0)"); - return VertBuff.pCacheAllocation ? - static_cast<Uint32>(VertBuff.pCacheAllocation->GetRegion().UnalignedOffset / sizeof(VertexAttribs0)) : + return VertBuff.pSuballocation ? + static_cast<Uint32>(VertBuff.pSuballocation->GetOffset() / sizeof(VertexAttribs0)) : 0; } - ITexture* GetTexture(Uint32 Index, IRenderDevice* pDevice, IDeviceContext* pCtx) - { - auto& TexInfo = Textures[Index]; - if (TexInfo.pTexture) - return TexInfo.pTexture; - else if (TexInfo.pCacheAllocation) - return TexInfo.pCacheAllocation->GetTexture(pDevice, pCtx); - else - return nullptr; - } - - const float4& GetUVScaleBias(Uint32 Index) - { - return Textures[Index].UVScaleBias; - } - - float GetSlice(Uint32 Index) - { - return Textures[Index].Slice; - } - private: void LoadFromFile(IRenderDevice* pDevice, IDeviceContext* pContext, @@ -434,23 +411,19 @@ private: struct BufferInfo { - RefCntAutoPtr<IBuffer> pBuffer; - - RefCntAutoPtr<GLTFResourceManager::BufferAllocation> pCacheAllocation; + RefCntAutoPtr<IBuffer> pBuffer; + RefCntAutoPtr<IBufferSuballocation> pSuballocation; }; std::array<BufferInfo, BUFFER_ID_NUM_BUFFERS> Buffers; struct TextureInfo { - RefCntAutoPtr<ITexture> pTexture; - float4 UVScaleBias{1, 1, 0, 0}; - float Slice = 0; - - RefCntAutoPtr<GLTFResourceManager::TextureAllocation> pCacheAllocation; + RefCntAutoPtr<ITexture> pTexture; + RefCntAutoPtr<ITextureAtlasSuballocation> pAtlasSuballocation; bool IsValid() const { - return pTexture || pCacheAllocation; + return pTexture || pAtlasSuballocation; } }; std::vector<TextureInfo> Textures; diff --git a/AssetLoader/interface/GLTFResourceManager.hpp b/AssetLoader/interface/GLTFResourceManager.hpp index a6c2a82..db386f1 100644 --- a/AssetLoader/interface/GLTFResourceManager.hpp +++ b/AssetLoader/interface/GLTFResourceManager.hpp @@ -36,297 +36,103 @@ #include "../../../DiligentCore/Graphics/GraphicsEngine/interface/DeviceContext.h" #include "../../../DiligentCore/Common/interface/RefCntAutoPtr.hpp" #include "../../../DiligentCore/Common/interface/ObjectBase.hpp" -#include "../../../DiligentCore/Graphics/GraphicsAccessories/interface/VariableSizeAllocationsManager.hpp" -#include "../../../DiligentCore/Graphics/GraphicsAccessories/interface/DynamicAtlasManager.hpp" +#include "../../../DiligentCore/Graphics/GraphicsTools/interface/BufferSuballocator.h" +#include "../../../DiligentCore/Graphics/GraphicsTools/interface/DynamicTextureAtlas.h" namespace Diligent { -/// GLTF resource manager -class GLTFResourceManager final : public ObjectBase<IObject> +namespace GLTF { - class BufferCache; - class TextureCache; +/// GLTF resource manager +class ResourceManager final : public ObjectBase<IObject> +{ public: using TBase = ObjectBase<IObject>; - class BufferAllocation final : public ObjectBase<IObject> - { - public: - BufferAllocation(IReferenceCounters* pRefCounters, - RefCntAutoPtr<GLTFResourceManager> pResourceMg, - BufferCache& ParentCache, - VariableSizeAllocationsManager::Allocation&& Region) : - // clang-format off - ObjectBase<IObject>{pRefCounters}, - m_pResMgr {std::move(pResourceMg)}, - m_ParentCache {ParentCache}, - m_Region {std::move(Region)} - // clang-format on - { - VERIFY_EXPR(m_Region.IsValid()); - } - - ~BufferAllocation() - { - m_ParentCache.FreeAllocation(std::move(m_Region)); - } - - IBuffer* GetBuffer(IRenderDevice* pDevice, IDeviceContext* pContext) const - { - return m_ParentCache.GetBuffer(pDevice, pContext); - } - - const VariableSizeAllocationsManager::Allocation& GetRegion() const - { - return m_Region; - } - - private: - RefCntAutoPtr<GLTFResourceManager> m_pResMgr; - BufferCache& m_ParentCache; - VariableSizeAllocationsManager::Allocation m_Region; - }; - - class TextureAllocation final : public ObjectBase<IObject> - { - public: - TextureAllocation(IReferenceCounters* pRefCounters, - RefCntAutoPtr<GLTFResourceManager> pResourceMg, - TextureCache& ParentCache, - Uint32 Width, - Uint32 Height, - Uint32 Slice, - DynamicAtlasManager::Region&& Region) : - // clang-format off - ObjectBase<IObject>{pRefCounters}, - m_pResMgr {std::move(pResourceMg)}, - m_ParentCache {ParentCache}, - m_Width {Width}, - m_Height {Height}, - m_Slice {Slice}, - m_Region {std::move(Region)} - // clang-format on - { - VERIFY_EXPR(!m_Region.IsEmpty()); - } - - ~TextureAllocation() - { - m_ParentCache.FreeAllocation(m_Slice, std::move(m_Region)); - } - - ITexture* GetTexture(IRenderDevice* pDevice, IDeviceContext* pContext) const - { - return m_ParentCache.GetTexture(pDevice, pContext); - } - - const TextureDesc& GetTexDesc() const - { - return m_ParentCache.GetTexDesc(); - } - - const DynamicAtlasManager::Region& GetRegion() - { - return m_Region; - } - - Uint32 GetWidth() const { return m_Width; } - Uint32 GetHeight() const { return m_Height; } - Uint32 GetSlice() const { return m_Slice; } - - private: - RefCntAutoPtr<GLTFResourceManager> m_pResMgr; - TextureCache& m_ParentCache; - const Uint32 m_Width; - const Uint32 m_Height; - const Uint32 m_Slice; - DynamicAtlasManager::Region m_Region; - }; - - struct TextureCacheAttribs - { - TextureDesc Desc; - - Uint32 Granularity = 128; - Uint32 ExtraSliceCount = 2; - Uint32 MaxSlices = 2048; - }; struct CreateInfo { - const BufferDesc* Buffers = nullptr; // [NumBuffers] - Uint32 NumBuffers = 0; + const BufferSuballocatorCreateInfo* BuffSuballocators = nullptr; // [NumBuffSuballocators] + const DynamicTextureAtlasCreateInfo* TexAtlases = nullptr; // [NumTexAtlases] - const TextureCacheAttribs* Textures = nullptr; // [NumTextures] - Uint32 NumTextures = 0; + Uint32 NumBuffSuballocators = 0; + Uint32 NumTexAtlases = 0; - TextureDesc DefaultTexDesc; - - Uint32 DefaultExtraSliceCount = 1; + DynamicTextureAtlasCreateInfo DefaultAtlasDesc; }; - static RefCntAutoPtr<GLTFResourceManager> Create(IRenderDevice* pDevice, - const CreateInfo& CI); + static RefCntAutoPtr<ResourceManager> Create(IRenderDevice* pDevice, + const CreateInfo& CI); - RefCntAutoPtr<BufferAllocation> AllocateBufferSpace(Uint32 BufferIndex, Uint32 Size, Uint32 Alignment) + RefCntAutoPtr<IBufferSuballocation> AllocateBufferSpace(Uint32 BufferIndex, + Uint32 Size, + Uint32 Alignment) { - return m_Buffers[BufferIndex].Allocate(Size, Alignment); + RefCntAutoPtr<IBufferSuballocation> pSuballoc; + m_BufferSuballocators[BufferIndex]->Allocate(Size, Alignment, &pSuballoc); + return pSuballoc; } - RefCntAutoPtr<TextureAllocation> AllocateTextureSpace(TEXTURE_FORMAT Fmt, Uint32 Width, Uint32 Height, const char* CacheId = nullptr); + RefCntAutoPtr<ITextureAtlasSuballocation> AllocateTextureSpace(TEXTURE_FORMAT Fmt, + Uint32 Width, + Uint32 Height, + const char* CacheId = nullptr); - RefCntAutoPtr<TextureAllocation> FindAllocation(const char* CacheId); + RefCntAutoPtr<ITextureAtlasSuballocation> FindAllocation(const char* CacheId); - Uint32 GetResourceVersion() const + Uint32 GetResourceVersion() { - return m_ResourceVersion.load(); + Uint32 Version = 0; + + std::lock_guard<std::mutex> Lock{m_AtlasesMtx}; + for (auto atlas_it : m_Atlases) + Version += atlas_it.second->GetVersion(); + + return Version; } IBuffer* GetBuffer(Uint32 Index, IRenderDevice* pDevice, IDeviceContext* pContext) { - return m_Buffers[Index].GetBuffer(pDevice, pContext); + return m_BufferSuballocators[Index]->GetBuffer(pDevice, pContext); } + ITexture* GetTexture(TEXTURE_FORMAT Fmt, IRenderDevice* pDevice, IDeviceContext* pContext) { - decltype(m_Textures)::iterator cache_it; // NB: can't initialize it without locking the mutex + decltype(m_Atlases)::iterator cache_it; // NB: can't initialize it without locking the mutex { - std::lock_guard<std::mutex> Lock{m_TexturesMtx}; - cache_it = m_Textures.find(Fmt); - if (cache_it == m_Textures.end()) + std::lock_guard<std::mutex> Lock{m_AtlasesMtx}; + cache_it = m_Atlases.find(Fmt); + if (cache_it == m_Atlases.end()) return nullptr; } - return cache_it->second.GetTexture(pDevice, pContext); + return cache_it->second->GetTexture(pDevice, pContext); } private: template <typename AllocatorType, typename ObjectType> friend class MakeNewRCObj; - GLTFResourceManager(IReferenceCounters* pRefCounters, - IRenderDevice* pDevice, - const CreateInfo& CI); - - class BufferCache - { - public: - BufferCache(GLTFResourceManager& Owner, IRenderDevice* pDevice, const BufferDesc& BuffDesc); - - // clang-format off - BufferCache (const BufferCache&) = delete; - BufferCache& operator=(const BufferCache&) = delete; - BufferCache& operator=(BufferCache&&) = delete; - // clang-format on - - BufferCache(BufferCache&& Cache) noexcept : - // clang-format off - m_Owner {Cache.m_Owner}, - m_Mgr {std::move(Cache.m_Mgr)}, - m_pBuffer{std::move(Cache.m_pBuffer)} - // clang-format on - {} - - IBuffer* GetBuffer(IRenderDevice* pDevice, IDeviceContext* pContext); - - RefCntAutoPtr<BufferAllocation> Allocate(Uint32 Size, Uint32 Alignment); + ResourceManager(IReferenceCounters* pRefCounters, + IRenderDevice* pDevice, + const CreateInfo& CI); - void FreeAllocation(VariableSizeAllocationsManager::Allocation&& Allocation) - { - std::lock_guard<std::mutex> Lock{m_Mtx}; - m_Mgr.Free(std::move(Allocation)); - } - - private: - GLTFResourceManager& m_Owner; - - std::mutex m_Mtx; - VariableSizeAllocationsManager m_Mgr; - RefCntAutoPtr<IBuffer> m_pBuffer; - }; - std::vector<BufferCache> m_Buffers; + std::vector<RefCntAutoPtr<IBufferSuballocator>> m_BufferSuballocators; + DynamicTextureAtlasCreateInfo m_DefaultAtlasDesc; + const std::string m_DefaultAtlasName; - class TextureCache - { - public: - TextureCache(GLTFResourceManager& Owner, IRenderDevice* pDevice, const TextureCacheAttribs& CacheCI); - - // clang-format off - TextureCache (const TextureCache&) = delete; - TextureCache& operator=(const TextureCache&) = delete; - TextureCache& operator=(TextureCache&&) = delete; - // clang-format on - - TextureCache(TextureCache&& Cache) noexcept : - // clang-format off - m_Owner {Cache.m_Owner}, - m_Attribs {Cache.m_Attribs}, - m_TexName {std::move(m_TexName)}, - m_Slices {std::move(Cache.m_Slices)}, - m_pTexture{std::move(Cache.m_pTexture)} - // clang-format on - { - m_Attribs.Desc.Name = m_TexName.c_str(); - } + std::mutex m_AtlasesMtx; + std::unordered_map<TEXTURE_FORMAT, RefCntAutoPtr<IDynamicTextureAtlas>> m_Atlases; - ITexture* GetTexture(IRenderDevice* pDevice, IDeviceContext* pContext); - - const TextureDesc& GetTexDesc() const - { - return m_Attribs.Desc; - } - - RefCntAutoPtr<TextureAllocation> Allocate(Uint32 Width, Uint32 Height); - - void FreeAllocation(Uint32 Slice, DynamicAtlasManager::Region&& Allocation); - - private: - GLTFResourceManager& m_Owner; - - TextureCacheAttribs m_Attribs; - - std::string m_TexName; - - struct SliceManager - { - SliceManager(Uint32 Width, Uint32 Height) : - Mgr{Width, Height} - {} - - DynamicAtlasManager::Region Allocate(Uint32 Width, Uint32 Height) - { - std::lock_guard<std::mutex> Lock{Mtx}; - return Mgr.Allocate(Width, Height); - } - void Free(DynamicAtlasManager::Region&& Region) - { - std::lock_guard<std::mutex> Lock{Mtx}; - Mgr.Free(std::move(Region)); - } - - private: - std::mutex Mtx; - DynamicAtlasManager Mgr; - }; - std::mutex m_SlicesMtx; - std::vector<std::unique_ptr<SliceManager>> m_Slices; - - RefCntAutoPtr<ITexture> m_pTexture; - }; - - TextureDesc m_DefaultTexDesc; - const Uint32 m_DefaultExtraSliceCount; - - - std::mutex m_TexturesMtx; - std::unordered_map<TEXTURE_FORMAT, TextureCache> m_Textures; - - std::mutex m_AllocationsMtx; - std::unordered_map<std::string, RefCntWeakPtr<TextureAllocation>> m_Allocations; + std::mutex m_TexAllocationsMtx; + std::unordered_map<std::string, RefCntWeakPtr<ITextureAtlasSuballocation>> m_TexAllocations; std::atomic_uint32_t m_ResourceVersion = {}; }; +} // namespace GLTF + } // namespace Diligent diff --git a/AssetLoader/src/GLTFLoader.cpp b/AssetLoader/src/GLTFLoader.cpp index 9b18bd1..c138eed 100644 --- a/AssetLoader/src/GLTFLoader.cpp +++ b/AssetLoader/src/GLTFLoader.cpp @@ -682,25 +682,18 @@ void Model::LoadTextures(IRenderDevice* pDevice, const tinygltf::Image& gltf_image = gltf_model.images[gltf_tex.source]; // TODO: simplify path - const auto CacheId = BaseDir + gltf_image.uri; + const auto CacheId = !gltf_image.uri.empty() ? BaseDir + gltf_image.uri : ""; TextureInfo TexInfo; if (CacheInfo.pResourceMgr != nullptr) { - TexInfo.pCacheAllocation = CacheInfo.pResourceMgr->FindAllocation(CacheId.c_str()); - if (TexInfo.pCacheAllocation) + TexInfo.pAtlasSuballocation = CacheInfo.pResourceMgr->FindAllocation(CacheId.c_str()); + if (TexInfo.pAtlasSuballocation) { - const auto& TexDesc = TexInfo.pCacheAllocation->GetTexDesc(); - const auto& Region = TexInfo.pCacheAllocation->GetRegion(); - VERIFY_EXPR(gltf_image.width == static_cast<int>(TexInfo.pCacheAllocation->GetWidth())); - VERIFY_EXPR(gltf_image.height == static_cast<int>(TexInfo.pCacheAllocation->GetHeight())); - - TexInfo.UVScaleBias.x = static_cast<float>(gltf_image.width) / static_cast<float>(TexDesc.Width); - TexInfo.UVScaleBias.y = static_cast<float>(gltf_image.height) / static_cast<float>(TexDesc.Height); - TexInfo.UVScaleBias.z = static_cast<float>(Region.x) / static_cast<float>(TexDesc.Width); - TexInfo.UVScaleBias.w = static_cast<float>(Region.y) / static_cast<float>(TexDesc.Height); - - TexInfo.Slice = static_cast<float>(TexInfo.pCacheAllocation->GetSlice()); + // Note that the texture may appear in the cache after the call to LoadImageData because + // it can be loaded by another thread + VERIFY_EXPR(gltf_image.width == -1 || gltf_image.width == static_cast<int>(TexInfo.pAtlasSuballocation->GetSize().x)); + VERIFY_EXPR(gltf_image.height == -1 || gltf_image.height == static_cast<int>(TexInfo.pAtlasSuballocation->GetSize().y)); } } else if (pTextureCache != nullptr) @@ -751,7 +744,8 @@ void Model::LoadTextures(IRenderDevice* pDevice, { if (CacheInfo.pResourceMgr != nullptr) { - TexInfo.pCacheAllocation = CacheInfo.pResourceMgr->AllocateTextureSpace(TEX_FORMAT_RGBA8_UNORM, gltf_image.width, gltf_image.height); + TexInfo.pAtlasSuballocation = + CacheInfo.pResourceMgr->AllocateTextureSpace(TEX_FORMAT_RGBA8_UNORM, gltf_image.width, gltf_image.height, CacheId.c_str()); } else { @@ -768,8 +762,6 @@ void Model::LoadTextures(IRenderDevice* pDevice, pDevice->CreateTexture(TexDesc, nullptr, &TexInfo.pTexture); TexInfo.pTexture->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE)->SetSampler(pSampler); - TexInfo.UVScaleBias = float4{1, 1, 0, 0}; - TexInfo.Slice = 0; TexInitData = PrepareGLTFTextureInitData(gltf_image, AlphaCutoff, 0, 0, 1); } @@ -782,6 +774,7 @@ void Model::LoadTextures(IRenderDevice* pDevice, TextureLoadInfo LoadInfo; if (CacheInfo.pResourceMgr != nullptr) { + LoadInfo.Name = "Staging upload texture for compressed"; LoadInfo.Usage = USAGE_STAGING; LoadInfo.BindFlags = BIND_NONE; LoadInfo.CPUAccessFlags = CPU_ACCESS_WRITE; @@ -801,27 +794,20 @@ void Model::LoadTextures(IRenderDevice* pDevice, } if (CacheInfo.pResourceMgr != nullptr && TexInitData.pStagingTex) { - const auto& TexDesc = TexInitData.pStagingTex->GetDesc(); - TexInfo.pCacheAllocation = CacheInfo.pResourceMgr->AllocateTextureSpace(TexDesc.Format, TexDesc.Width, TexDesc.Height); + const auto& TexDesc = TexInitData.pStagingTex->GetDesc(); + TexInfo.pAtlasSuballocation = CacheInfo.pResourceMgr->AllocateTextureSpace(TexDesc.Format, TexDesc.Width, TexDesc.Height, CacheId.c_str()); } } - if (TexInfo.pCacheAllocation) + if (TexInfo.pAtlasSuballocation) { - const auto& AtlasDesc = TexInfo.pCacheAllocation->GetTexDesc(); + const auto& AtlasDesc = TexInfo.pAtlasSuballocation->GetAtlas()->GetAtlasDesc(); + const auto& Origin = TexInfo.pAtlasSuballocation->GetOrigin(); - const auto& Region = TexInfo.pCacheAllocation->GetRegion(); if (!TexInitData.pStagingTex) { - TexInitData = PrepareGLTFTextureInitData(gltf_image, AlphaCutoff, Region.x, Region.y, AtlasDesc.MipLevels); + TexInitData = PrepareGLTFTextureInitData(gltf_image, AlphaCutoff, Origin.x, Origin.y, AtlasDesc.MipLevels); } - - TexInfo.UVScaleBias.x = static_cast<float>(gltf_image.width) / static_cast<float>(AtlasDesc.Width); - TexInfo.UVScaleBias.y = static_cast<float>(gltf_image.height) / static_cast<float>(AtlasDesc.Height); - TexInfo.UVScaleBias.z = static_cast<float>(Region.x) / static_cast<float>(AtlasDesc.Width); - TexInfo.UVScaleBias.w = static_cast<float>(Region.y) / static_cast<float>(AtlasDesc.Height); - - TexInfo.Slice = static_cast<float>(TexInfo.pCacheAllocation->GetSlice()); } if (!InitData) @@ -866,14 +852,17 @@ void Model::PrepareGPUResources(IRenderDevice* pDevice, IDeviceContext* pCtx) VERIFY_EXPR(InitData->Textures.size() == Textures.size()); for (Uint32 i = 0; i < Textures.size(); ++i) { - auto* pTexture = GetTexture(i, pDevice, pCtx); + auto& TexInfo = Textures[i]; + ITexture* pTexture = TexInfo.pAtlasSuballocation ? + TexInfo.pAtlasSuballocation->GetAtlas()->GetTexture(pDevice, pCtx) : + TexInfo.pTexture; if (!pTexture) continue; auto& TexData = InitData->Textures[i]; const auto& Levels = TexData.Levels; - const auto DstSlice = static_cast<Uint32>(Textures[i].Slice); + const auto DstSlice = TexInfo.pAtlasSuballocation ? TexInfo.pAtlasSuballocation->GetSlice() : 0; if (!Levels.empty()) { VERIFY_EXPR(Levels.size() == 1 || Levels.size() == pTexture->GetDesc().MipLevels); @@ -903,15 +892,24 @@ void Model::PrepareGPUResources(IRenderDevice* pDevice, IDeviceContext* pCtx) CopyAttribs.pDstTexture = pTexture; CopyAttribs.SrcTextureTransitionMode = RESOURCE_STATE_TRANSITION_MODE_TRANSITION; CopyAttribs.DstTextureTransitionMode = RESOURCE_STATE_TRANSITION_MODE_TRANSITION; + CopyAttribs.SrcSlice = 0; + CopyAttribs.DstSlice = DstSlice; - const auto& DstTexDesc = pTexture->GetDesc(); - for (Uint32 mip = 0; mip < DstTexDesc.MipLevels; ++mip) + if (Textures[i].pAtlasSuballocation) + { + const auto& Origin = Textures[i].pAtlasSuballocation->GetOrigin(); + CopyAttribs.DstX = Origin.x; + CopyAttribs.DstY = Origin.y; + } + const auto& DstTexDesc = pTexture->GetDesc(); + auto NumMipLevels = std::min(DstTexDesc.MipLevels, TexData.pStagingTex->GetDesc().MipLevels); + for (Uint32 mip = 0; mip < NumMipLevels; ++mip) { - CopyAttribs.SrcSlice = 0; - CopyAttribs.DstSlice = DstSlice; CopyAttribs.SrcMipLevel = mip; CopyAttribs.DstMipLevel = mip; pCtx->CopyTexture(CopyAttribs); + CopyAttribs.DstX /= 2; + CopyAttribs.DstY /= 2; } } else @@ -923,10 +921,20 @@ void Model::PrepareGPUResources(IRenderDevice* pDevice, IDeviceContext* pCtx) auto UpdateBuffer = [&](BUFFER_ID BuffId, const void* pData, size_t Size) // { - auto* pBuffer = GetBuffer(BuffId, pDevice, pCtx); - VERIFY_EXPR(pBuffer != nullptr); - auto Offset = Buffers[BuffId].pCacheAllocation ? Buffers[BuffId].pCacheAllocation->GetRegion().UnalignedOffset : 0; - pCtx->UpdateBuffer(pBuffer, static_cast<Uint32>(Offset), static_cast<Uint32>(Size), pData, RESOURCE_STATE_TRANSITION_MODE_TRANSITION); + auto& BuffInfo = Buffers[BuffId]; + IBuffer* pBuffer = nullptr; + Uint32 Offset = 0; + if (BuffInfo.pSuballocation) + { + pBuffer = BuffInfo.pSuballocation->GetAllocator()->GetBuffer(pDevice, pCtx); + Offset = BuffInfo.pSuballocation->GetOffset(); + } + else + { + pBuffer = BuffInfo.pBuffer; + } + + pCtx->UpdateBuffer(pBuffer, Offset, static_cast<Uint32>(Size), pData, RESOURCE_STATE_TRANSITION_MODE_TRANSITION); if (Buffers[BuffId].pBuffer != nullptr) { VERIFY_EXPR(Buffers[BuffId].pBuffer == pBuffer); @@ -1163,8 +1171,12 @@ void Model::LoadMaterials(const tinygltf::Model& gltf_model) auto TexIndex = Mat.TextureIds[Param.TextureId]; if (TexIndex >= 0) { - Param.UVScaleBias = GetUVScaleBias(TexIndex); - Param.Slice = GetSlice(TexIndex); + const auto& TexInfo = Textures[TexIndex]; + if (TexInfo.pAtlasSuballocation) + { + Param.UVScaleBias = TexInfo.pAtlasSuballocation->GetUVScaleBias(); + Param.Slice = static_cast<float>(TexInfo.pAtlasSuballocation->GetSlice()); + } } } @@ -1321,12 +1333,12 @@ namespace struct ImageLoaderData { - using TexAllocationsVector = std::vector<RefCntAutoPtr<GLTFResourceManager::TextureAllocation>>; + using TexAllocationsVector = std::vector<RefCntAutoPtr<ITextureAtlasSuballocation>>; using TexturesVector = std::vector<RefCntAutoPtr<ITexture>>; Model::TextureCacheType* const pTextureCache; TexturesVector* const pTextureHold; - GLTFResourceManager* const pResourceMgr; + ResourceManager* const pResourceMgr; TexAllocationsVector* const pTextureAllocationsHold; std::string BaseDir; @@ -1349,17 +1361,18 @@ bool LoadImageData(tinygltf::Image* gltf_image, if (pLoaderData != nullptr) { // TODO: simplify path - auto CacheId = pLoaderData->BaseDir + gltf_image->uri; + auto CacheId = !gltf_image->uri.empty() ? pLoaderData->BaseDir + gltf_image->uri : ""; if (pLoaderData->pResourceMgr != nullptr) { if (auto pAllocation = pLoaderData->pResourceMgr->FindAllocation(CacheId.c_str())) { - const auto& TexDesc = pAllocation->GetTexDesc(); + const auto& TexDesc = pAllocation->GetAtlas()->GetAtlasDesc(); const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format); + const auto Size = pAllocation->GetSize(); - gltf_image->width = pAllocation->GetWidth(); - gltf_image->height = pAllocation->GetHeight(); + gltf_image->width = Size.x; + gltf_image->height = Size.y; gltf_image->component = FmtAttribs.NumComponents; gltf_image->bits = FmtAttribs.ComponentSize * 8; gltf_image->pixel_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE; @@ -1660,7 +1673,7 @@ void Model::LoadFromFile(IRenderDevice* pDevice, auto BufferSize = static_cast<Uint32>(VertexData0.size() * sizeof(VertexData0[0])); if (CacheInfo.pResourceMgr != nullptr) { - Buffers[BUFFER_ID_VERTEX0].pCacheAllocation = CacheInfo.pResourceMgr->AllocateBufferSpace(CacheInfo.VertexBuffer0Idx, BufferSize, 1); + Buffers[BUFFER_ID_VERTEX0].pSuballocation = CacheInfo.pResourceMgr->AllocateBufferSpace(CacheInfo.VertexBuffer0Idx, BufferSize, 1); } else { @@ -1684,7 +1697,7 @@ void Model::LoadFromFile(IRenderDevice* pDevice, auto BufferSize = static_cast<Uint32>(VertexData1.size() * sizeof(VertexData1[0])); if (CacheInfo.pResourceMgr != nullptr) { - Buffers[BUFFER_ID_VERTEX1].pCacheAllocation = CacheInfo.pResourceMgr->AllocateBufferSpace(CacheInfo.VertexBuffer1Idx, BufferSize, 1); + Buffers[BUFFER_ID_VERTEX1].pSuballocation = CacheInfo.pResourceMgr->AllocateBufferSpace(CacheInfo.VertexBuffer1Idx, BufferSize, 1); } else { @@ -1709,7 +1722,7 @@ void Model::LoadFromFile(IRenderDevice* pDevice, auto BufferSize = static_cast<Uint32>(IndexBuffer.size() * sizeof(IndexBuffer[0])); if (CacheInfo.pResourceMgr != nullptr) { - Buffers[BUFFER_ID_INDEX].pCacheAllocation = CacheInfo.pResourceMgr->AllocateBufferSpace(CacheInfo.IndexBufferIdx, BufferSize, 1); + Buffers[BUFFER_ID_INDEX].pSuballocation = CacheInfo.pResourceMgr->AllocateBufferSpace(CacheInfo.IndexBufferIdx, BufferSize, 1); } else { diff --git a/AssetLoader/src/GLTFResourceManager.cpp b/AssetLoader/src/GLTFResourceManager.cpp index e9b37a3..a30e265 100644 --- a/AssetLoader/src/GLTFResourceManager.cpp +++ b/AssetLoader/src/GLTFResourceManager.cpp @@ -28,256 +28,67 @@ #include "GLTFResourceManager.hpp" #include "DefaultRawMemoryAllocator.hpp" #include "Align.hpp" +#include "GraphicsAccessories.hpp" namespace Diligent { -GLTFResourceManager::BufferCache::BufferCache(GLTFResourceManager& Owner, - IRenderDevice* pDevice, - const BufferDesc& BuffDesc) : - m_Owner{Owner}, - m_Mgr{BuffDesc.uiSizeInBytes, DefaultRawMemoryAllocator::GetAllocator()} +namespace GLTF { - pDevice->CreateBuffer(BuffDesc, nullptr, &m_pBuffer); -} - -IBuffer* GLTFResourceManager::BufferCache::GetBuffer(IRenderDevice* pDevice, IDeviceContext* pContext) -{ - std::lock_guard<std::mutex> Lock{m_Mtx}; - - const auto& BuffDesc = m_pBuffer->GetDesc(); - const auto MgrSize = m_Mgr.GetMaxSize(); - if (BuffDesc.uiSizeInBytes < MgrSize) - { - // Extend the buffer - auto NewBuffDesc = BuffDesc; - - NewBuffDesc.uiSizeInBytes = static_cast<Uint32>(MgrSize); - - RefCntAutoPtr<IBuffer> pNewBuffer; - pDevice->CreateBuffer(NewBuffDesc, nullptr, &pNewBuffer); - pContext->CopyBuffer(m_pBuffer, 0, RESOURCE_STATE_TRANSITION_MODE_TRANSITION, - pNewBuffer, 0, BuffDesc.uiSizeInBytes, RESOURCE_STATE_TRANSITION_MODE_TRANSITION); - - m_pBuffer = std::move(pNewBuffer); - } - - return m_pBuffer.RawPtr(); -} - -RefCntAutoPtr<GLTFResourceManager::BufferAllocation> GLTFResourceManager::BufferCache::Allocate(Uint32 Size, Uint32 Alignment) -{ - VERIFY_EXPR(Size > 0 && IsPowerOfTwo(Alignment)); - - std::lock_guard<std::mutex> Lock{m_Mtx}; - - auto Region = m_Mgr.Allocate(Size, Alignment); - while (!Region.IsValid()) - { - m_Mgr.Extend(m_Mgr.GetMaxSize()); - Region = m_Mgr.Allocate(Size, Alignment); - } - - return RefCntAutoPtr<BufferAllocation>{ - MakeNewRCObj<BufferAllocation>()( - RefCntAutoPtr<GLTFResourceManager>{&m_Owner}, - *this, - std::move(Region) // - ) // - }; -} - -GLTFResourceManager::TextureCache::TextureCache(GLTFResourceManager& Owner, - IRenderDevice* pDevice, - const TextureCacheAttribs& CacheCI) : - m_Owner{Owner}, - m_Attribs{CacheCI} -{ - m_Attribs.Desc.Name = m_TexName.c_str(); - - const auto& Desc = m_Attribs.Desc; - for (Uint32 slice = 0; slice < Desc.ArraySize; ++slice) - { - m_Slices.emplace_back(new SliceManager{Desc.Width / m_Attribs.Granularity, Desc.Height / m_Attribs.Granularity}); - } - - DEV_CHECK_ERR(IsPowerOfTwo(m_Attribs.Granularity), "Granularity (", m_Attribs.Granularity, ") must be a power of two"); - DEV_CHECK_ERR((Desc.Width % m_Attribs.Granularity) == 0, "Atlas width (", Desc.Width, ") is not multiple of granularity (", m_Attribs.Granularity, ")"); - DEV_CHECK_ERR((Desc.Height % m_Attribs.Granularity) == 0, "Atlas height (", Desc.Height, ") is not multiple of granularity (", m_Attribs.Granularity, ")"); - - if (pDevice != nullptr) - { - pDevice->CreateTexture(Desc, nullptr, &m_pTexture); - } -} - - -ITexture* GLTFResourceManager::TextureCache::GetTexture(IRenderDevice* pDevice, IDeviceContext* pContext) -{ - RefCntAutoPtr<ITexture> pNewTexture; - { - std::lock_guard<std::mutex> Lock{m_SlicesMtx}; - if (!m_pTexture || m_pTexture->GetDesc().ArraySize < m_Slices.size()) - { - m_Attribs.Desc.ArraySize = static_cast<Uint32>(m_Slices.size()); - VERIFY_EXPR(pDevice != nullptr); - pDevice->CreateTexture(m_Attribs.Desc, nullptr, &pNewTexture); - } - if (pNewTexture) - { - if (m_pTexture) - { - const auto& OldDesc = m_pTexture->GetDesc(); - - CopyTextureAttribs CopyAttribs; - CopyAttribs.pSrcTexture = m_pTexture; - CopyAttribs.pDstTexture = pNewTexture; - CopyAttribs.SrcTextureTransitionMode = RESOURCE_STATE_TRANSITION_MODE_TRANSITION; - CopyAttribs.DstTextureTransitionMode = RESOURCE_STATE_TRANSITION_MODE_TRANSITION; - - for (Uint32 slice = 0; slice < OldDesc.ArraySize; ++slice) - { - for (Uint32 mip = 0; mip < OldDesc.MipLevels; ++mip) - { - CopyAttribs.SrcSlice = slice; - CopyAttribs.DstSlice = slice; - CopyAttribs.SrcMipLevel = mip; - CopyAttribs.DstMipLevel = mip; - pContext->CopyTexture(CopyAttribs); - } - } - } - m_pTexture = std::move(pNewTexture); - m_Owner.m_ResourceVersion.fetch_add(1); - } - } - - return m_pTexture; -} - -RefCntAutoPtr<GLTFResourceManager::TextureAllocation> GLTFResourceManager::TextureCache::Allocate(Uint32 Width, Uint32 Height) -{ - VERIFY_EXPR(Width > 0 && Height > 0); - const auto& TexDesc = m_Attribs.Desc; - if (Width > TexDesc.Width || Height > TexDesc.Height) - { - LOG_ERROR_MESSAGE("Requested size ", Width, " x ", Height, " exceeds the texture size ", TexDesc.Width, " x ", TexDesc.Height); - return {}; - } - - const auto Granularity = m_Attribs.Granularity; - for (Uint32 Slice = 0; Slice < m_Attribs.MaxSlices; ++Slice) - { - SliceManager* pSliceMgr = nullptr; - { - std::lock_guard<std::mutex> Lock{m_SlicesMtx}; - if (Slice == m_Slices.size()) - { - for (Uint32 ExtraSlice = 0; ExtraSlice < m_Attribs.ExtraSliceCount && Slice + ExtraSlice < m_Attribs.MaxSlices; ++ExtraSlice) - { - m_Slices.emplace_back(new SliceManager{TexDesc.Width / Granularity, TexDesc.Height / Granularity}); - } - } - pSliceMgr = m_Slices[Slice].get(); - } - auto Region = pSliceMgr->Allocate((Width + Granularity - 1) / Granularity, (Height + Granularity - 1) / Granularity); - if (!Region.IsEmpty()) - { - Region.x *= Granularity; - Region.y *= Granularity; - Region.width *= Granularity; - Region.height *= Granularity; - - return RefCntAutoPtr<TextureAllocation>{ - MakeNewRCObj<TextureAllocation>()( - RefCntAutoPtr<GLTFResourceManager>{&m_Owner}, - *this, - Width, - Height, - Slice, - std::move(Region) // - ) // - }; - } - } - - return RefCntAutoPtr<TextureAllocation>{}; -} - -void GLTFResourceManager::TextureCache::FreeAllocation(Uint32 Slice, DynamicAtlasManager::Region&& Allocation) -{ - const auto Granularity = m_Attribs.Granularity; - VERIFY((Allocation.x % Granularity) == 0, "Allocation x (", Allocation.x, ") is not multiple of granularity (", Granularity, ")"); - VERIFY((Allocation.y % Granularity) == 0, "Allocation y (", Allocation.y, ") is not multiple of granularity (", Granularity, ")"); - VERIFY((Allocation.width % Granularity) == 0, "Allocation width (", Allocation.width, ") is not multiple of granularity (", Granularity, ")"); - VERIFY((Allocation.height % Granularity) == 0, "Allocation height (", Allocation.height, ") is not multiple of granularity (", Granularity, ")"); - - Allocation.x /= Granularity; - Allocation.y /= Granularity; - Allocation.width /= Granularity; - Allocation.height /= Granularity; - - SliceManager* pSliceMgr = nullptr; - { - std::lock_guard<std::mutex> Lock{m_SlicesMtx}; - pSliceMgr = m_Slices[Slice].get(); - } - pSliceMgr->Free(std::move(Allocation)); -} - - - -RefCntAutoPtr<GLTFResourceManager> GLTFResourceManager::Create(IRenderDevice* pDevice, - const CreateInfo& CI) +RefCntAutoPtr<ResourceManager> ResourceManager::Create(IRenderDevice* pDevice, + const CreateInfo& CI) { - return RefCntAutoPtr<GLTFResourceManager>{MakeNewRCObj<GLTFResourceManager>()(pDevice, CI)}; + return RefCntAutoPtr<ResourceManager>{MakeNewRCObj<ResourceManager>()(pDevice, CI)}; } -GLTFResourceManager::GLTFResourceManager(IReferenceCounters* pRefCounters, - IRenderDevice* pDevice, - const CreateInfo& CI) : +ResourceManager::ResourceManager(IReferenceCounters* pRefCounters, + IRenderDevice* pDevice, + const CreateInfo& CI) : TBase{pRefCounters}, - m_DefaultTexDesc{CI.DefaultTexDesc}, - m_DefaultExtraSliceCount{CI.DefaultExtraSliceCount} + m_DefaultAtlasDesc{CI.DefaultAtlasDesc}, + m_DefaultAtlasName{CI.DefaultAtlasDesc.Desc.Name != nullptr ? CI.DefaultAtlasDesc.Desc.Name : "GLTF texture atlas"} { - m_Buffers.reserve(CI.NumBuffers); - for (Uint32 i = 0; i < CI.NumBuffers; ++i) + m_DefaultAtlasDesc.Desc.Name = m_DefaultAtlasName.c_str(); + m_BufferSuballocators.resize(CI.NumBuffSuballocators); + for (Uint32 i = 0; i < CI.NumBuffSuballocators; ++i) { - m_Buffers.emplace_back(*this, pDevice, CI.Buffers[i]); + CreateBufferSuballocator(pDevice, CI.BuffSuballocators[i], &m_BufferSuballocators[i]); } - m_Textures.reserve(CI.NumTextures); - for (Uint32 i = 0; i < CI.NumTextures; ++i) + m_Atlases.reserve(CI.NumTexAtlases); + for (Uint32 i = 0; i < CI.NumTexAtlases; ++i) { - m_Textures.emplace(CI.Textures[i].Desc.Format, TextureCache{*this, pDevice, CI.Textures[i]}); + RefCntAutoPtr<IDynamicTextureAtlas> pAtlas; + CreateDynamicTextureAtlas(pDevice, CI.TexAtlases[i], &pAtlas); + m_Atlases.emplace(CI.TexAtlases[i].Desc.Format, std::move(pAtlas)); } } -RefCntAutoPtr<GLTFResourceManager::TextureAllocation> GLTFResourceManager::FindAllocation(const char* CacheId) +RefCntAutoPtr<ITextureAtlasSuballocation> ResourceManager::FindAllocation(const char* CacheId) { - RefCntAutoPtr<TextureAllocation> pAllocation; + RefCntAutoPtr<ITextureAtlasSuballocation> pAllocation; - std::lock_guard<std::mutex> Lock{m_AllocationsMtx}; + std::lock_guard<std::mutex> Lock{m_TexAllocationsMtx}; - auto it = m_Allocations.find(CacheId); - if (it != m_Allocations.end()) + auto it = m_TexAllocations.find(CacheId); + if (it != m_TexAllocations.end()) { pAllocation = it->second.Lock(); if (!pAllocation) - m_Allocations.erase(it); + m_TexAllocations.erase(it); } return pAllocation; } -RefCntAutoPtr<GLTFResourceManager::TextureAllocation> GLTFResourceManager::AllocateTextureSpace( +RefCntAutoPtr<ITextureAtlasSuballocation> ResourceManager::AllocateTextureSpace( TEXTURE_FORMAT Fmt, Uint32 Width, Uint32 Height, const char* CacheId) { - RefCntAutoPtr<TextureAllocation> pAllocation; + RefCntAutoPtr<ITextureAtlasSuballocation> pAllocation; if (CacheId != nullptr && *CacheId != 0) { pAllocation = FindAllocation(CacheId); @@ -285,33 +96,40 @@ RefCntAutoPtr<GLTFResourceManager::TextureAllocation> GLTFResourceManager::Alloc if (!pAllocation) { - decltype(m_Textures)::iterator cache_it; // NB: can't initialize it without locking the mutex + decltype(m_Atlases)::iterator cache_it; // NB: can't initialize it without locking the mutex { - std::lock_guard<std::mutex> Lock{m_TexturesMtx}; - cache_it = m_Textures.find(Fmt); - if (cache_it == m_Textures.end()) + std::lock_guard<std::mutex> Lock{m_AtlasesMtx}; + cache_it = m_Atlases.find(Fmt); + if (cache_it == m_Atlases.end()) { - DEV_CHECK_ERR(m_DefaultTexDesc.Width > 0 && m_DefaultTexDesc.Height > 0, "Default texture description is not initialized"); - TextureCacheAttribs NewCacheAttribs; - NewCacheAttribs.Desc = m_DefaultTexDesc; + DEV_CHECK_ERR(m_DefaultAtlasDesc.Desc.Width > 0 && + m_DefaultAtlasDesc.Desc.Height > 0 && + m_DefaultAtlasDesc.Desc.Type != RESOURCE_DIM_UNDEFINED, + "Default texture description is not initialized"); - NewCacheAttribs.Desc.Name = "GLTF Texture cache"; - NewCacheAttribs.Desc.Format = Fmt; + auto AtalsCreateInfo = m_DefaultAtlasDesc; + AtalsCreateInfo.Desc.Format = Fmt; - cache_it = m_Textures.emplace(Fmt, TextureCache{*this, nullptr, NewCacheAttribs}).first; + RefCntAutoPtr<IDynamicTextureAtlas> pAtlas; + CreateDynamicTextureAtlas(nullptr, AtalsCreateInfo, &pAtlas); + DEV_CHECK_ERR(pAtlas, "Failed to create new texture atlas"); + + cache_it = m_Atlases.emplace(Fmt, std::move(pAtlas)).first; } } // Allocate outside of mutex - pAllocation = cache_it->second.Allocate(Width, Height); + cache_it->second->Allocate(Width, Height, &pAllocation); } if (CacheId != nullptr && *CacheId != 0) { - auto inserted = m_Allocations.emplace(CacheId, pAllocation).second; + auto inserted = m_TexAllocations.emplace(CacheId, pAllocation).second; VERIFY_EXPR(inserted); } return pAllocation; } +} // namespace GLTF + } // namespace Diligent |
