diff options
| author | assiduous <assiduous@diligentgraphics.com> | 2020-12-07 06:13:42 +0000 |
|---|---|---|
| committer | assiduous <assiduous@diligentgraphics.com> | 2020-12-07 06:13:42 +0000 |
| commit | 512a111585b6e10968c8b31704c4ea5f3b7775a0 (patch) | |
| tree | 6deefc3b35e3f1b0e2c199cb67b16f050e71ceb9 /Graphics/GraphicsTools | |
| parent | GraphicsTools: added IBufferSuballocator (diff) | |
| download | DiligentCore-512a111585b6e10968c8b31704c4ea5f3b7775a0.tar.gz DiligentCore-512a111585b6e10968c8b31704c4ea5f3b7775a0.zip | |
Graphics tools: added Dynamic Texture Atlas
Diffstat (limited to 'Graphics/GraphicsTools')
| -rw-r--r-- | Graphics/GraphicsTools/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | Graphics/GraphicsTools/interface/BufferSuballocator.h | 2 | ||||
| -rw-r--r-- | Graphics/GraphicsTools/interface/DynamicBuffer.hpp | 2 | ||||
| -rw-r--r-- | Graphics/GraphicsTools/interface/DynamicTextureAtlas.h | 168 | ||||
| -rw-r--r-- | Graphics/GraphicsTools/src/BufferSuballocator.cpp | 14 | ||||
| -rw-r--r-- | Graphics/GraphicsTools/src/DynamicTextureAtlas.cpp | 411 |
6 files changed, 592 insertions, 7 deletions
diff --git a/Graphics/GraphicsTools/CMakeLists.txt b/Graphics/GraphicsTools/CMakeLists.txt index 2b39f073..aeb4131f 100644 --- a/Graphics/GraphicsTools/CMakeLists.txt +++ b/Graphics/GraphicsTools/CMakeLists.txt @@ -6,6 +6,7 @@ set(INTERFACE interface/BufferSuballocator.h interface/CommonlyUsedStates.h interface/DynamicBuffer.hpp + interface/DynamicTextureAtlas.h interface/DurationQueryHelper.hpp interface/GraphicsUtilities.h interface/MapHelper.hpp @@ -22,6 +23,7 @@ set(SOURCE src/BufferSuballocator.cpp src/DurationQueryHelper.cpp src/DynamicBuffer.cpp + src/DynamicTextureAtlas.cpp src/GraphicsUtilities.cpp src/ScopedQueryHelper.cpp src/ScreenCapture.cpp diff --git a/Graphics/GraphicsTools/interface/BufferSuballocator.h b/Graphics/GraphicsTools/interface/BufferSuballocator.h index c1017110..ce7f2c8e 100644 --- a/Graphics/GraphicsTools/interface/BufferSuballocator.h +++ b/Graphics/GraphicsTools/interface/BufferSuballocator.h @@ -99,6 +99,8 @@ struct IBufferSuballocator : public IObject /// The method itself is thread-safe and can be called from multiple threads simultaneously. /// However, if non-null pDevice and pContext are provided, an appliction must externally /// synchronize access to these objects. + /// + /// Typically pDevice and pContext should be null when the method is called from a worker thread. virtual void Allocate(Uint32 Size, Uint32 Alignment, IRenderDevice* pDevice, diff --git a/Graphics/GraphicsTools/interface/DynamicBuffer.hpp b/Graphics/GraphicsTools/interface/DynamicBuffer.hpp index 86165295..940dbcf4 100644 --- a/Graphics/GraphicsTools/interface/DynamicBuffer.hpp +++ b/Graphics/GraphicsTools/interface/DynamicBuffer.hpp @@ -81,6 +81,8 @@ public: /// An application must provide non-null device and device context when calling /// GetBuffer(). /// + /// Typically pDevice and pContext should be null when the method is called from a worker thread. + /// /// If NewSize is zero, internal buffer will be released. IBuffer* Resize(IRenderDevice* pDevice, IDeviceContext* pContext, diff --git a/Graphics/GraphicsTools/interface/DynamicTextureAtlas.h b/Graphics/GraphicsTools/interface/DynamicTextureAtlas.h new file mode 100644 index 00000000..39c1cb82 --- /dev/null +++ b/Graphics/GraphicsTools/interface/DynamicTextureAtlas.h @@ -0,0 +1,168 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +/// \file +/// Declaration of DynamicTextureAtlas interface and related data structures + +#include "../../GraphicsEngine/interface/RenderDevice.h" +#include "../../GraphicsEngine/interface/DeviceContext.h" +#include "../../GraphicsEngine/interface/Texture.h" +#include "../../../Common/interface/BasicMath.hpp" + +namespace Diligent +{ + +struct IDynamicTextureAtlas; + +// {F7ACDCFB-074F-4E31-94C5-DD4C988E4532} +static const INTERFACE_ID IID_TextureAtlasSuballocation = + {0xf7acdcfb, 0x74f, 0x4e31, {0x94, 0xc5, 0xdd, 0x4c, 0x98, 0x8e, 0x45, 0x32}}; + + +// {00E1D6FA-47B4-4062-B96C-D3E191A02351} +static const INTERFACE_ID IID_DynamicTextureAtlas = + {0xe1d6fa, 0x47b4, 0x4062, {0xb9, 0x6c, 0xd3, 0xe1, 0x91, 0xa0, 0x23, 0x51}}; + + +/// Texture atlas suballocation interface. +struct ITextureAtlasSuballocation : public IObject +{ + /// Returns the suballocation origin. + virtual uint2 GetOrigin() const = 0; + + /// Returns the suballocation slice. + virtual Uint32 GetSlice() const = 0; + + /// Returns the suballocation size. + virtual uint2 GetSize() const = 0; + + /// Returns the texture coordinate scale (xy) and bias (zw). + virtual float4 GetUVScaleBias() const = 0; + + /// Returns the pointer to the parent texture atlas. + virtual IDynamicTextureAtlas* GetAtlas() = 0; +}; + +/// Dynamic texture atlas interface. +struct IDynamicTextureAtlas : public IObject +{ + /// Returns the pointer to the internal texture object. + + /// \param[in] pDevice - Pointer to the render device that will be used to + /// create new internal texture array, if necessary. + /// \param[in] pContext - Pointer to the device context that will be used to + /// copy existing contents to the new texture array, if + /// necessary. + /// + /// \remarks If the internal texture needs to be resized, pDevice and pContext will + /// be used to create a new texture and copy existing contents to the new texture. + virtual ITexture* GetTexture(IRenderDevice* pDevice, IDeviceContext* pContext) = 0; + + + /// Performs suballocation from the atlas. + + /// \param[in] Width - Suballocation width. + /// \param[in] Height - Suballocation height. + /// \param[in] pDevice - Pointer to the render device that will be used to create + /// new internal texture array, if necessary. May be null (see remarks). + /// \param[in] pContext - Pointer to the device context that will be used to + /// copy existing contents to the new texture array, if + /// necessary. May be null (see remarks). + /// \param[out] ppSuballocation - Memory location where pointer to the new suballocation will be + /// stored. + /// + /// \remarks If there is not enough space in the internal texture array, it will need to be expanded. + /// An application may provide non-null pDevice and pContext to resize the array + /// immediately. Otherwise the texture will be resized when GetTexture() is called. + /// In this case an application must provide non-null pDevice and pContext to GetTexture(). + /// + /// The method itself is thread-safe and can be called from multiple threads simultaneously. + /// However, if non-null pDevice and pContext are provided, an appliction must externally + /// synchronize access to these objects. + /// + /// Typically pDevice and pContext should be null when the method is called from a worker thread. + virtual void Allocate(Uint32 Width, + Uint32 Height, + IRenderDevice* pDevice, + IDeviceContext* pContext, + ITextureAtlasSuballocation** ppSuballocation) = 0; + + + /// Returns the texture atlas description + const TextureDesc& GetAtlasDesc() const; + + /// Returns internal texture array version. The version is incremented every time + /// the array is expanded. + virtual Uint32 GetVersion() const = 0; +}; + + +/// Dynamic texture atlas create information. +struct DynamicTextureAtlasCreateInfo +{ + /// Pointer to the render device. + /// May be null, in which case internal texture initialization will + /// be postponed. + IRenderDevice* pDevice = nullptr; + + + /// Texture description + + /// Texture type must be 2D or 2D array. When the type is + /// texture 2D, resizes will be disallowed + TextureDesc Desc; + + + /// Texture region allocation granularity. + + /// The width and height of the texture region will be aligned to the + /// TextureGranularity value. + /// Texture granularity must be power of two. + Uint32 TextureGranularity = 128; + + /// The number of extra slices. + + /// When non-zero, the array will be expanded by the specified number of slices every time + /// there is insufficient space. If zero, the array size will be doubled when + /// more space is needed. + Uint32 ExtraSliceCount = 0; + + + /// Maximum number of slices in texture array. + Uint32 MaxSliceCount = 2048; + + + /// Allocation granularity for ITextureAtlasSuballocation objects. + Uint32 SuballocationObjAllocationGranularity = 64; +}; + +/// Creates a new dynamic texture atlas. +void CreateDynamicTextureAtlas(DynamicTextureAtlasCreateInfo& CreateInfo, IDynamicTextureAtlas** ppAtlas); + +} // namespace Diligent diff --git a/Graphics/GraphicsTools/src/BufferSuballocator.cpp b/Graphics/GraphicsTools/src/BufferSuballocator.cpp index 6669ca31..a87c9ae2 100644 --- a/Graphics/GraphicsTools/src/BufferSuballocator.cpp +++ b/Graphics/GraphicsTools/src/BufferSuballocator.cpp @@ -83,10 +83,10 @@ public: private: RefCntAutoPtr<BufferSuballocatorImpl> m_pParentAllocator; + VariableSizeAllocationsManager::Allocation m_Subregion; + const Uint32 m_Offset; const Uint32 m_Size; - - VariableSizeAllocationsManager::Allocation m_Subregion; }; class BufferSuballocatorImpl final : public ObjectBase<IBufferSuballocator> @@ -117,11 +117,11 @@ public: return m_Buffer.GetBuffer(pDevice, pContext); } - void Allocate(Uint32 Size, - Uint32 Alignment, - IRenderDevice* pDevice, - IDeviceContext* pContext, - IBufferSuballocation** ppSuballocation) + virtual void Allocate(Uint32 Size, + Uint32 Alignment, + IRenderDevice* pDevice, + IDeviceContext* pContext, + IBufferSuballocation** ppSuballocation) override final { if (Size == 0) { diff --git a/Graphics/GraphicsTools/src/DynamicTextureAtlas.cpp b/Graphics/GraphicsTools/src/DynamicTextureAtlas.cpp new file mode 100644 index 00000000..fb771c0e --- /dev/null +++ b/Graphics/GraphicsTools/src/DynamicTextureAtlas.cpp @@ -0,0 +1,411 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "DynamicTextureAtlas.h" + +#include <mutex> +#include <algorithm> +#include <atomic> + +#include "DynamicAtlasManager.hpp" +#include "ObjectBase.hpp" +#include "RefCntAutoPtr.hpp" +#include "FixedBlockMemoryAllocator.hpp" +#include "DefaultRawMemoryAllocator.hpp" +#include "GraphicsAccessories.hpp" +#include "Align.hpp" + +namespace Diligent +{ + +class DynamicTextureAtlasImpl; + +class TextureAtlasSuballocationImpl final : public ObjectBase<ITextureAtlasSuballocation> +{ +public: + using TBase = ObjectBase<ITextureAtlasSuballocation>; + TextureAtlasSuballocationImpl(IReferenceCounters* pRefCounters, + DynamicTextureAtlasImpl* pParentAtlas, + DynamicAtlasManager::Region&& Subregion, + Uint32 Slice, + const uint2& Size) : + // clang-format off + TBase {pRefCounters}, + m_pParentAtlas{pParentAtlas}, + m_Subregion {std::move(Subregion)}, + m_Slice {Slice}, + m_Size {Size} + // clang-format on + { + VERIFY_EXPR(m_pParentAtlas); + VERIFY_EXPR(!m_Subregion.IsEmpty()); + } + + ~TextureAtlasSuballocationImpl(); + + IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_TextureAtlasSuballocation, TBase) + + virtual uint2 GetOrigin() const override final + { + return uint2{m_Subregion.x, m_Subregion.y}; + } + + virtual Uint32 GetSlice() const override final + { + return m_Slice; + } + + virtual uint2 GetSize() const override final + { + return m_Size; + } + + virtual float4 GetUVScaleBias() const override final; + + /// Returns the pointer to the parent texture atlas. + virtual IDynamicTextureAtlas* GetAtlas() override final; + +private: + RefCntAutoPtr<DynamicTextureAtlasImpl> m_pParentAtlas; + + DynamicAtlasManager::Region m_Subregion; + + const Uint32 m_Slice; + const uint2 m_Size; +}; + + +class DynamicTextureAtlasImpl final : public ObjectBase<IDynamicTextureAtlas> +{ +public: + using TBase = ObjectBase<IDynamicTextureAtlas>; + + IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_DynamicTextureAtlas, TBase) + + DynamicTextureAtlasImpl(IReferenceCounters* pRefCounters, + DynamicTextureAtlasCreateInfo& CreateInfo) : + // clang-format off + TBase {pRefCounters}, + m_Desc {CreateInfo.Desc}, + m_Granularity {CreateInfo.TextureGranularity}, + m_ExtraSliceCount {CreateInfo.ExtraSliceCount}, + m_MaxSliceCount {CreateInfo.Desc.Type == RESOURCE_DIM_TEX_2D_ARRAY ? std::min(CreateInfo.MaxSliceCount, Uint32{2048}) : 1}, + m_SuballocationsAllocator + { + DefaultRawMemoryAllocator::GetAllocator(), + sizeof(TextureAtlasSuballocationImpl), + CreateInfo.SuballocationObjAllocationGranularity + } + // clang-format on + { + if (m_Desc.Type != RESOURCE_DIM_TEX_2D && m_Desc.Type != RESOURCE_DIM_TEX_2D_ARRAY) + LOG_ERROR_AND_THROW(GetResourceDimString(m_Desc.Type), " is not a valid resource dimension. Only 2D and 2D array textures are allowed"); + + if (m_Desc.Format == TEX_FORMAT_UNKNOWN) + LOG_ERROR_AND_THROW("Texture format must not be UNKNOWN"); + + if (m_Granularity == 0) + LOG_ERROR_AND_THROW("Texture granularity can't be zero"); + + if (!IsPowerOfTwo(m_Granularity)) + LOG_ERROR_AND_THROW("Texture granularity (", m_Granularity, ") is not power of two"); + + if (m_Desc.Width == 0) + LOG_ERROR_AND_THROW("Texture width must not be zero"); + + if (m_Desc.Height == 0) + LOG_ERROR_AND_THROW("Texture height must not be zero"); + + if ((m_Desc.Width % m_Granularity) != 0) + LOG_ERROR_AND_THROW("Texture width (", m_Desc.Width, ") is not multiple of granularity (", m_Granularity, ")"); + + if ((m_Desc.Height % m_Granularity) != 0) + LOG_ERROR_AND_THROW("Texture height (", m_Desc.Height, ") is not multiple of granularity (", m_Granularity, ")"); + + m_Name = m_Desc.Name; + m_Desc.Name = m_Name.c_str(); + + for (Uint32 slice = 0; slice < m_Desc.ArraySize; ++slice) + { + m_Slices.emplace_back(new SliceManager{m_Desc.Width / m_Granularity, m_Desc.Height / m_Granularity}); + } + + if (m_Desc.ArraySize > 0 && CreateInfo.pDevice != nullptr) + { + CreateInfo.pDevice->CreateTexture(m_Desc, nullptr, &m_pTexture); + if (!m_pTexture) + LOG_ERROR_AND_THROW("Failed to create texture atlas texture"); + } + + m_Version.store(0); + } + + + virtual ITexture* GetTexture(IRenderDevice* pDevice, IDeviceContext* pContext) override final + { + CommitResize(pDevice, pContext); + + return m_pTexture; + } + + virtual void Allocate(Uint32 Width, + Uint32 Height, + IRenderDevice* pDevice, + IDeviceContext* pContext, + ITextureAtlasSuballocation** ppSuballocation) override final + { + if (Width == 0 || Height == 0) + { + UNEXPECTED("Subregion size must not be zero"); + return; + } + + if (Width > m_Desc.Width || Height > m_Desc.Height) + { + LOG_ERROR_MESSAGE("Requested size ", Width, " x ", Height, " exceeds the atlas dimensions ", m_Desc.Width, " x ", m_Desc.Height); + return; + } + + DynamicAtlasManager::Region Subregion; + + Uint32 Slice = 0; + while (Slice < m_MaxSliceCount) + { + SliceManager* pSliceMgr = nullptr; + { + std::lock_guard<std::mutex> Lock{m_SlicesMtx}; + if (Slice == m_Slices.size() && Slice + 1 < m_MaxSliceCount) + { + const auto ExtraSliceCount = m_ExtraSliceCount != 0 ? + m_ExtraSliceCount : + static_cast<Uint32>(m_Slices.size()); + + for (Uint32 ExtraSlice = 1; ExtraSlice <= ExtraSliceCount && Slice + ExtraSlice < m_MaxSliceCount; ++ExtraSlice) + { + m_Slices.emplace_back(new SliceManager{m_Desc.Width / m_Granularity, m_Desc.Height / m_Granularity}); + } + } + pSliceMgr = m_Slices[Slice].get(); + + if (m_Slices.size() > m_Desc.ArraySize) + { + m_Desc.ArraySize = static_cast<Uint32>(m_Slices.size()); + if (pDevice != nullptr && pContext != nullptr) + { + CommitResize(pDevice, pContext); + } + } + } + + Subregion = pSliceMgr->Allocate((Width + m_Granularity - 1) / m_Granularity, + (Height + m_Granularity - 1) / m_Granularity); + if (!Subregion.IsEmpty()) + break; + else + ++Slice; + } + + if (Subregion.IsEmpty()) + { + LOG_ERROR_MESSAGE("Failed to suballocate texture subregion ", Width, " x ", Height, " from texture atlas"); + return; + } + + Subregion.x *= m_Granularity; + Subregion.y *= m_Granularity; + Subregion.width *= m_Granularity; + Subregion.height *= m_Granularity; + + // clang-format off + TextureAtlasSuballocationImpl* pSuballocation{ + NEW_RC_OBJ(m_SuballocationsAllocator, "TextureAtlasSuballocationImpl instance", TextureAtlasSuballocationImpl) + ( + this, + std::move(Subregion), + Slice, + uint2{Width, Height} + ) + }; + // clang-format on + + pSuballocation->QueryInterface(IID_TextureAtlasSuballocation, reinterpret_cast<IObject**>(ppSuballocation)); + } + + virtual void Free(Uint32 Slice, DynamicAtlasManager::Region&& Subregion) + { + VERIFY((Subregion.x % m_Granularity) == 0, "Subregion x (", Subregion.x, ") is not multiple of granularity (", m_Granularity, ")"); + VERIFY((Subregion.y % m_Granularity) == 0, "Subregion y (", Subregion.y, ") is not multiple of granularity (", m_Granularity, ")"); + VERIFY((Subregion.width % m_Granularity) == 0, "Subregion width (", Subregion.width, ") is not multiple of granularity (", m_Granularity, ")"); + VERIFY((Subregion.height % m_Granularity) == 0, "Subregion height (", Subregion.height, ") is not multiple of granularity (", m_Granularity, ")"); + + Subregion.x /= m_Granularity; + Subregion.y /= m_Granularity; + Subregion.width /= m_Granularity; + Subregion.height /= m_Granularity; + + SliceManager* pSliceMgr = nullptr; + { + std::lock_guard<std::mutex> Lock{m_SlicesMtx}; + pSliceMgr = m_Slices[Slice].get(); + } + pSliceMgr->Free(std::move(Subregion)); + } + + virtual const TextureDesc& GetAtlasDesc() const + { + return m_Desc; + } + + virtual Uint32 GetVersion() const override final + { + return m_Version.load(); + } + +private: + void CommitResize(IRenderDevice* pDevice, + IDeviceContext* pContext) + { + VERIFY_EXPR(pDevice != nullptr && pContext != nullptr); + + if (m_pTexture->GetDesc().ArraySize == m_Desc.ArraySize) + return; + + RefCntAutoPtr<ITexture> pNewTexture; + pDevice->CreateTexture(m_Desc, nullptr, &pNewTexture); + VERIFY_EXPR(pNewTexture); + m_Version.fetch_add(1); + + LOG_INFO_MESSAGE("Dynamic texture atlas: expanding texture array '", m_Desc.Name, + "' (", m_Desc.Width, " x ", m_Desc.Height, " ", m_Desc.MipLevels, "-mip ", + GetTextureFormatAttribs(m_Desc.Format).Name, ") to ", + m_Desc.ArraySize, " slices. Version: ", GetVersion()); + + const auto& StaleTexDesc = m_pTexture->GetDesc(); + + if (m_pTexture) + { + 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 < StaleTexDesc.ArraySize; ++slice) + { + for (Uint32 mip = 0; mip < StaleTexDesc.MipLevels; ++mip) + { + CopyAttribs.SrcSlice = slice; + CopyAttribs.DstSlice = slice; + CopyAttribs.SrcMipLevel = mip; + CopyAttribs.DstMipLevel = mip; + pContext->CopyTexture(CopyAttribs); + } + } + } + + m_pTexture = std::move(pNewTexture); + } + + TextureDesc m_Desc; + std::string m_Name; + + const Uint32 m_Granularity; + const Uint32 m_ExtraSliceCount; + const Uint32 m_MaxSliceCount; + + RefCntAutoPtr<ITexture> m_pTexture; + + FixedBlockMemoryAllocator m_SuballocationsAllocator; + + std::atomic_uint32_t m_Version = {}; + + + 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; +}; + + +TextureAtlasSuballocationImpl::~TextureAtlasSuballocationImpl() +{ + m_pParentAtlas->Free(m_Slice, std::move(m_Subregion)); +} + +IDynamicTextureAtlas* TextureAtlasSuballocationImpl::GetAtlas() +{ + return m_pParentAtlas; +} + +float4 TextureAtlasSuballocationImpl::GetUVScaleBias() const +{ + const auto Origin = GetOrigin().Recast<float>(); + const auto Size = GetSize().Recast<float>(); + const auto& AtlasDesc = m_pParentAtlas->GetAtlasDesc(); + return float4 // + { + Size.x / static_cast<float>(AtlasDesc.Width), + Size.y / static_cast<float>(AtlasDesc.Height), + Origin.x / static_cast<float>(AtlasDesc.Width), + Origin.y / static_cast<float>(AtlasDesc.Height) // + }; +} + + +void CreateDynamicTextureAtlas(DynamicTextureAtlasCreateInfo& CreateInfo, IDynamicTextureAtlas** ppAtlas) +{ + try + { + auto* pAllocator = MakeNewRCObj<DynamicTextureAtlasImpl>()(CreateInfo); + pAllocator->QueryInterface(IID_DynamicTextureAtlas, reinterpret_cast<IObject**>(ppAtlas)); + } + catch (...) + { + LOG_ERROR_MESSAGE("Failed to create buffer suballocator"); + } +} + +} // namespace Diligent |
