summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsTools
diff options
context:
space:
mode:
authorassiduous <assiduous@diligentgraphics.com>2020-12-07 01:37:38 +0000
committerassiduous <assiduous@diligentgraphics.com>2020-12-07 01:37:38 +0000
commit02df8a289626a39551528d5019b0b259933b811c (patch)
treee97a2ca3e089664b8321d72f9d0e1687ab2d7ad6 /Graphics/GraphicsTools
parentGraphicsTools: added DynamicBuffer class (diff)
downloadDiligentCore-02df8a289626a39551528d5019b0b259933b811c.tar.gz
DiligentCore-02df8a289626a39551528d5019b0b259933b811c.zip
GraphicsTools: added IBufferSuballocator
Diffstat (limited to 'Graphics/GraphicsTools')
-rw-r--r--Graphics/GraphicsTools/CMakeLists.txt2
-rw-r--r--Graphics/GraphicsTools/interface/BufferSuballocator.h149
-rw-r--r--Graphics/GraphicsTools/interface/DynamicBuffer.hpp4
-rw-r--r--Graphics/GraphicsTools/src/BufferSuballocator.cpp228
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