diff options
| author | assiduous <assiduous@diligentgraphics.com> | 2020-12-07 01:37:38 +0000 |
|---|---|---|
| committer | assiduous <assiduous@diligentgraphics.com> | 2020-12-07 01:37:38 +0000 |
| commit | 02df8a289626a39551528d5019b0b259933b811c (patch) | |
| tree | e97a2ca3e089664b8321d72f9d0e1687ab2d7ad6 /Graphics/GraphicsTools | |
| parent | GraphicsTools: added DynamicBuffer class (diff) | |
| download | DiligentCore-02df8a289626a39551528d5019b0b259933b811c.tar.gz DiligentCore-02df8a289626a39551528d5019b0b259933b811c.zip | |
GraphicsTools: added IBufferSuballocator
Diffstat (limited to 'Graphics/GraphicsTools')
| -rw-r--r-- | Graphics/GraphicsTools/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | Graphics/GraphicsTools/interface/BufferSuballocator.h | 149 | ||||
| -rw-r--r-- | Graphics/GraphicsTools/interface/DynamicBuffer.hpp | 4 | ||||
| -rw-r--r-- | Graphics/GraphicsTools/src/BufferSuballocator.cpp | 228 |
4 files changed, 381 insertions, 2 deletions
diff --git a/Graphics/GraphicsTools/CMakeLists.txt b/Graphics/GraphicsTools/CMakeLists.txt index 1bc9c9e7..2b39f073 100644 --- a/Graphics/GraphicsTools/CMakeLists.txt +++ b/Graphics/GraphicsTools/CMakeLists.txt @@ -3,6 +3,7 @@ cmake_minimum_required (VERSION 3.6) project(Diligent-GraphicsTools CXX) set(INTERFACE + interface/BufferSuballocator.h interface/CommonlyUsedStates.h interface/DynamicBuffer.hpp interface/DurationQueryHelper.hpp @@ -18,6 +19,7 @@ set(INTERFACE ) set(SOURCE + src/BufferSuballocator.cpp src/DurationQueryHelper.cpp src/DynamicBuffer.cpp src/GraphicsUtilities.cpp diff --git a/Graphics/GraphicsTools/interface/BufferSuballocator.h b/Graphics/GraphicsTools/interface/BufferSuballocator.h new file mode 100644 index 00000000..c1017110 --- /dev/null +++ b/Graphics/GraphicsTools/interface/BufferSuballocator.h @@ -0,0 +1,149 @@ +/* + * 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 BufferSuballocator interface and related data structures + +#include "../../GraphicsEngine/interface/RenderDevice.h" +#include "../../GraphicsEngine/interface/DeviceContext.h" +#include "../../GraphicsEngine/interface/Buffer.h" + +namespace Diligent +{ + +struct IBufferSuballocator; + +// {562552DA-67F0-40C2-A4AF-F286DFCA1626} +static const INTERFACE_ID IID_BufferSuballocation = + {0x562552da, 0x67f0, 0x40c2, {0xa4, 0xaf, 0xf2, 0x86, 0xdf, 0xca, 0x16, 0x26}}; + + +// {71F59B50-7D13-49A7-A4F7-FC986715FFAC} +static const INTERFACE_ID IID_BufferSuballocator = + {0x71f59b50, 0x7d13, 0x49a7, {0xa4, 0xf7, 0xfc, 0x98, 0x67, 0x15, 0xff, 0xac}}; + + +/// Buffer suballocation interface. +struct IBufferSuballocation : public IObject +{ + /// Returns the start offset of the suballocation. + virtual Uint32 GetOffset() const = 0; + + /// Returns the suballocation size. + virtual Uint32 GetSize() const = 0; + + /// Returns the pointer to the parent allocator. + virtual IBufferSuballocator* GetAllocator() = 0; +}; + + +/// Buffer suballocator interface. +struct IBufferSuballocator : public IObject +{ + /// Returns the pointer to the internal buffer object. + + /// \param[in] pDevice - Pointer to the render device that will be used to + /// create new internal buffer, if necessary. + /// \param[in] pContext - Pointer to the device context that will be used to + /// copy existing buffer contents to the new buffer, if + /// necessary. + /// + /// \remarks If the internal buffer needs to be resized, pDevice and pContext will + /// be used to create a new buffer and copy existing contents to the new buffer. + virtual IBuffer* GetBuffer(IRenderDevice* pDevice, IDeviceContext* pContext) = 0; + + + /// Performs suballocation from the buffer. + + /// \param[in] Size - Suballocation size. + /// \param[in] Alignment - Requried alignment. + /// \param[in] pDevice - Pointer to the render device that will be used to create + /// new internal buffer, if necessary. May be null (see remarks). + /// \param[in] pContext - Pointer to the device context that will be used to + /// copy existing buffer contents to the new buffer, 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 buffer, it will need to be expanded. + /// An application may provide non-null pDevice and pContext to resize the buffer + /// immediately. Otherwise the buffer will be resized when GetBuffer() is called. + /// In this case an application must provide non-null pDevice and pContext to GetBuffer(). + /// + /// 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. + virtual void Allocate(Uint32 Size, + Uint32 Alignment, + IRenderDevice* pDevice, + IDeviceContext* pContext, + IBufferSuballocation** ppSuballocation) = 0; + + + /// Returns the total remaining free size. + + /// \note Due to fragmentation total free size may be split between + /// mutliple free chunks. + virtual Uint32 GetFreeSize() = 0; + + + /// Returns internal buffer version. The version is incremented every time + /// the buffer is expanded. + virtual Uint32 GetVersion() const = 0; +}; + +/// Buffer suballocator create information. +struct BufferSuballocatorCreateInfo +{ + /// Pointer to the render device. + /// May be null, in which case internal buffer initialization will + /// be postponed. + IRenderDevice* pDevice = nullptr; + + + /// Buffer description + BufferDesc Desc; + + + /// Buffer expansion size, in bytes. + + /// When non-zero, the buffer will be expanded by the specified amount every time + /// there is insufficient space. If zero, the buffer size will be doubled when + /// more space is needed. + Uint32 ExpansionSize = 0; + + + /// Allocation granularity for IBufferSuballocator objects. + Uint32 SuballocationObjAllocationGranularity = 64; +}; + +/// Creates a new buffer suballocator. +void CreateBufferSuballocator(BufferSuballocatorCreateInfo& CreateInfo, IBufferSuballocator** ppBufferSuballocator); + +} // namespace Diligent diff --git a/Graphics/GraphicsTools/interface/DynamicBuffer.hpp b/Graphics/GraphicsTools/interface/DynamicBuffer.hpp index 86615ca8..86165295 100644 --- a/Graphics/GraphicsTools/interface/DynamicBuffer.hpp +++ b/Graphics/GraphicsTools/interface/DynamicBuffer.hpp @@ -55,8 +55,8 @@ public: // clang-format off DynamicBuffer (const DynamicBuffer&) = delete; DynamicBuffer& operator=(const DynamicBuffer&) = delete; - DynamicBuffer ( DynamicBuffer&&) = default; - DynamicBuffer& operator=( DynamicBuffer&&) = default; + DynamicBuffer ( DynamicBuffer&&) = delete; + DynamicBuffer& operator=( DynamicBuffer&&) = delete; // clang-format on diff --git a/Graphics/GraphicsTools/src/BufferSuballocator.cpp b/Graphics/GraphicsTools/src/BufferSuballocator.cpp new file mode 100644 index 00000000..6669ca31 --- /dev/null +++ b/Graphics/GraphicsTools/src/BufferSuballocator.cpp @@ -0,0 +1,228 @@ +/* + * 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 "BufferSuballocator.h" + +#include <mutex> + +#include "DebugUtilities.hpp" +#include "ObjectBase.hpp" +#include "RefCntAutoPtr.hpp" +#include "DynamicBuffer.hpp" +#include "VariableSizeAllocationsManager.hpp" +#include "Align.hpp" +#include "DefaultRawMemoryAllocator.hpp" +#include "FixedBlockMemoryAllocator.hpp" + +namespace Diligent +{ + +class BufferSuballocatorImpl; + +class BufferSuballocationImpl final : public ObjectBase<IBufferSuballocation> +{ +public: + using TBase = ObjectBase<IBufferSuballocation>; + BufferSuballocationImpl(IReferenceCounters* pRefCounters, + BufferSuballocatorImpl* pParentAllocator, + Uint32 Offset, + Uint32 Size, + VariableSizeAllocationsManager::Allocation&& Subregion) : + // clang-format off + TBase {pRefCounters}, + m_pParentAllocator{pParentAllocator}, + m_Subregion {std::move(Subregion)}, + m_Offset {Offset}, + m_Size {Size} + // clang-format on + { + VERIFY_EXPR(m_pParentAllocator); + VERIFY_EXPR(m_Subregion.IsValid()); + } + + ~BufferSuballocationImpl(); + + IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_BufferSuballocation, TBase) + + virtual Uint32 GetOffset() const override final + { + return m_Offset; + } + + virtual Uint32 GetSize() const override final + { + return m_Size; + } + + virtual IBufferSuballocator* GetAllocator() override final; + +private: + RefCntAutoPtr<BufferSuballocatorImpl> m_pParentAllocator; + + const Uint32 m_Offset; + const Uint32 m_Size; + + VariableSizeAllocationsManager::Allocation m_Subregion; +}; + +class BufferSuballocatorImpl final : public ObjectBase<IBufferSuballocator> +{ +public: + using TBase = ObjectBase<IBufferSuballocator>; + + IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_BufferSuballocator, TBase) + + BufferSuballocatorImpl(IReferenceCounters* pRefCounters, + BufferSuballocatorCreateInfo& CreateInfo) : + // clang-format off + TBase {pRefCounters}, + m_Mgr {CreateInfo.Desc.uiSizeInBytes, DefaultRawMemoryAllocator::GetAllocator()}, + m_Buffer {CreateInfo.pDevice, CreateInfo.Desc}, + m_ExpansionSize {CreateInfo.ExpansionSize}, + m_SuballocationsAllocator + { + DefaultRawMemoryAllocator::GetAllocator(), + sizeof(BufferSuballocationImpl), + CreateInfo.SuballocationObjAllocationGranularity + } + // clang-format on + {} + + virtual IBuffer* GetBuffer(IRenderDevice* pDevice, IDeviceContext* pContext) override final + { + return m_Buffer.GetBuffer(pDevice, pContext); + } + + void Allocate(Uint32 Size, + Uint32 Alignment, + IRenderDevice* pDevice, + IDeviceContext* pContext, + IBufferSuballocation** ppSuballocation) + { + if (Size == 0) + { + UNEXPECTED("Size must not be zero"); + return; + } + + if (!IsPowerOfTwo(Alignment)) + { + UNEXPECTED("Alignment (", Alignment, ") is not a power of two"); + return; + } + + VariableSizeAllocationsManager::Allocation Subregion; + { + std::lock_guard<std::mutex> Lock{m_MgrMtx}; + Subregion = m_Mgr.Allocate(Size, Alignment); + + bool WasExpanded = false; + while (!Subregion.IsValid()) + { + auto ExtraSize = m_ExpansionSize != 0 ? + std::max(m_ExpansionSize, Align(Size, Alignment)) : + m_Mgr.GetMaxSize(); + + m_Mgr.Extend(ExtraSize); + WasExpanded = true; + Subregion = m_Mgr.Allocate(Size, Alignment); + } + if (WasExpanded) + { + m_Buffer.Resize(pDevice, pContext, static_cast<Uint32>(m_Mgr.GetMaxSize())); + } + } + + // clang-format off + BufferSuballocationImpl* pSuballocation{ + NEW_RC_OBJ(m_SuballocationsAllocator, "BufferSuballocationImpl instance", BufferSuballocationImpl) + ( + this, + Align(static_cast<Uint32>(Subregion.UnalignedOffset), Alignment), + Size, + std::move(Subregion) + ) + }; + // clang-format on + + pSuballocation->QueryInterface(IID_BufferSuballocation, reinterpret_cast<IObject**>(ppSuballocation)); + } + + void Free(VariableSizeAllocationsManager::Allocation&& Subregion) + { + std::lock_guard<std::mutex> Lock{m_MgrMtx}; + m_Mgr.Free(std::move(Subregion)); + } + + virtual Uint32 GetVersion() const override final + { + return m_Buffer.GetVersion(); + } + + virtual Uint32 GetFreeSize() override final + { + std::lock_guard<std::mutex> Lock{m_MgrMtx}; + return static_cast<Uint32>(m_Mgr.GetFreeSize()); + } + +private: + std::mutex m_MgrMtx; + VariableSizeAllocationsManager m_Mgr; + + DynamicBuffer m_Buffer; + + const Uint32 m_ExpansionSize; + + FixedBlockMemoryAllocator m_SuballocationsAllocator; +}; + + +BufferSuballocationImpl::~BufferSuballocationImpl() +{ + m_pParentAllocator->Free(std::move(m_Subregion)); +} + +IBufferSuballocator* BufferSuballocationImpl::GetAllocator() +{ + return m_pParentAllocator; +} + + +void CreateBufferSuballocator(BufferSuballocatorCreateInfo& CreateInfo, IBufferSuballocator** ppBufferSuballocator) +{ + try + { + auto* pAllocator = MakeNewRCObj<BufferSuballocatorImpl>()(CreateInfo); + pAllocator->QueryInterface(IID_BufferSuballocator, reinterpret_cast<IObject**>(ppBufferSuballocator)); + } + catch (...) + { + LOG_ERROR_MESSAGE("Failed to create buffer suballocator"); + } +} + +} // namespace Diligent |
