From 259a9d5897937dcaaca1b4b294bb8d5250371e76 Mon Sep 17 00:00:00 2001 From: azhirnov Date: Thu, 15 Oct 2020 20:55:38 +0300 Subject: Added GraphicsPipelineCreateInfo and ComputePipelineCreateInfo instead of single PipelineCreateInfo. Some optimizations for dynamic memory allocations in PipelineState. --- Common/interface/LinearAllocator.hpp | 208 +++++++++++++++++++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 Common/interface/LinearAllocator.hpp (limited to 'Common/interface') diff --git a/Common/interface/LinearAllocator.hpp b/Common/interface/LinearAllocator.hpp new file mode 100644 index 00000000..9d580f0b --- /dev/null +++ b/Common/interface/LinearAllocator.hpp @@ -0,0 +1,208 @@ +/* + * 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 +/// Defines Diligent::LinearAllocator class + +#include "../../Primitives/interface/BasicTypes.h" +#include "../../Primitives/interface/MemoryAllocator.h" +#include "../../Platforms/Basic/interface/DebugUtilities.hpp" +#include "Align.hpp" + +namespace Diligent +{ + +/// Implementation of a linear allocator on a fixed-size memory page +class LinearAllocator +{ +public: + // clang-format off + LinearAllocator (const LinearAllocator&) = delete; + LinearAllocator& operator=(const LinearAllocator&) = delete; + LinearAllocator& operator=(LinearAllocator&&) = delete; + // clang-format on + + LinearAllocator(IMemoryAllocator& Allocator) : + m_pAllocator{&Allocator} + {} + + LinearAllocator(LinearAllocator&& Other) : + // clang-format off + m_pBuffer {Other.m_pBuffer }, + m_pCurrPtr {Other.m_pCurrPtr }, + m_RequiredSize{Other.m_RequiredSize}, + m_pAllocator {Other.m_pAllocator } + // clang-format on + { + Other.m_pBuffer = nullptr; + Other.m_pCurrPtr = nullptr; + Other.m_RequiredSize = 0; + Other.m_pAllocator = nullptr; + } + + ~LinearAllocator() + { + Free(); + } + + void Free() + { + if (m_pBuffer != nullptr && m_pAllocator != nullptr) + { + m_pAllocator->Free(m_pBuffer); + } + + m_pBuffer = nullptr; + m_pCurrPtr = nullptr; + m_RequiredSize = 0; + m_pAllocator = nullptr; + } + + void* Release() + { + void* Ptr = m_pBuffer; + m_pBuffer = nullptr; + m_pCurrPtr = nullptr; + m_RequiredSize = 0; + return Ptr; + } + + void AddRequiredSize(size_t size, size_t align) + { + VERIFY(m_pBuffer == nullptr, "Memory already allocated"); + if (size > 0) + { + m_RequiredSize = Align(m_RequiredSize, align) + size; + + // Reserve additional space for pointer alignment + m_RequiredSize += (align > sizeof(void*) ? align : 0); + } + } + + template + void AddRequiredSize(size_t count) + { + AddRequiredSize(sizeof(T) * count, alignof(T)); + } + + void Reserve(size_t size) + { + VERIFY(m_RequiredSize == 0, "Required size will be overrided by input argument"); + m_RequiredSize = size; + Reserve(); + } + + void Reserve() + { + VERIFY(m_pBuffer == nullptr, "Memory already allocated"); + VERIFY(m_pAllocator != nullptr, "Allocator must not be null"); + if (m_RequiredSize > 0) + { + m_pBuffer = reinterpret_cast(m_pAllocator->Allocate(m_RequiredSize, "Memory for linear allocator", __FILE__, __LINE__)); + m_pCurrPtr = m_pBuffer; + } + } + + void* Allocate(size_t size, size_t align) + { + if (size == 0) + return nullptr; + + uint8_t* Ptr = reinterpret_cast(Align(reinterpret_cast(m_pCurrPtr), align)); + m_pCurrPtr = Ptr + size; + VERIFY(m_pCurrPtr <= m_pBuffer + m_RequiredSize, "Not enough space in the buffer"); + return Ptr; + } + + template + T* Allocate(size_t count) + { + return reinterpret_cast(Allocate(sizeof(T) * count, alignof(T))); + } + + template + T* Construct(Args&&... args) + { + T* Ptr = Allocate(1); + new (Ptr) T{std::forward(args)...}; + return Ptr; + } + + template + T* ConstructArray(size_t count, Args&&... args) + { + T* Ptr = Allocate(count); + for (size_t i = 0; i < count; ++i) + { + new (Ptr + i) T{std::forward(args)...}; + } + return Ptr; + } + + template + T* CopyArray(const T* Src, size_t count) + { + T* Dst = reinterpret_cast(Align(reinterpret_cast(m_pCurrPtr), alignof(T))); + m_pCurrPtr = reinterpret_cast(Dst + count); + VERIFY(m_pCurrPtr <= m_pBuffer + m_RequiredSize, "Not enough space in the buffer"); + + for (size_t i = 0; i < count; ++i) + { + new (Dst + i) T{Src[i]}; + } + return Dst; + } + + Char* CopyString(const char* Str) + { + if (Str == nullptr) + return nullptr; + + Char* Ptr = reinterpret_cast(m_pCurrPtr); + Char* Dst = Ptr; + while (*Str != 0 && Dst < reinterpret_cast(m_pBuffer + m_RequiredSize)) + { + *(Dst++) = *(Str++); + } + if (Dst < reinterpret_cast(m_pBuffer + m_RequiredSize)) + *(Dst++) = 0; + else + UNEXPECTED("Not enough space reserved in the string pool"); + m_pCurrPtr = reinterpret_cast(Dst); + return Ptr; + } + +private: + uint8_t* m_pBuffer = nullptr; + uint8_t* m_pCurrPtr = nullptr; + size_t m_RequiredSize = 0; + IMemoryAllocator* m_pAllocator = nullptr; +}; + +} // namespace Diligent -- cgit v1.2.3 From e8f439dc0f87f6820e3db53ecd8ee41cc878d90c Mon Sep 17 00:00:00 2001 From: azhirnov Date: Sat, 17 Oct 2020 20:02:58 +0300 Subject: Fixed compilation, some fixes after review --- Common/interface/LinearAllocator.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Common/interface') diff --git a/Common/interface/LinearAllocator.hpp b/Common/interface/LinearAllocator.hpp index 9d580f0b..00f94ee3 100644 --- a/Common/interface/LinearAllocator.hpp +++ b/Common/interface/LinearAllocator.hpp @@ -98,10 +98,11 @@ public: VERIFY(m_pBuffer == nullptr, "Memory already allocated"); if (size > 0) { + size = Align(size, align); m_RequiredSize = Align(m_RequiredSize, align) + size; // Reserve additional space for pointer alignment - m_RequiredSize += (align > sizeof(void*) ? align : 0); + m_RequiredSize += (align > sizeof(void*) ? align - sizeof(void*) : 0); } } -- cgit v1.2.3 From 849d2758d7b9e0f3b5c1c11ef2f8f7a06d012c2d Mon Sep 17 00:00:00 2001 From: assiduous Date: Sun, 18 Oct 2020 10:02:51 -0700 Subject: Implemented Align for pointers; added tests --- Common/interface/Align.hpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'Common/interface') diff --git a/Common/interface/Align.hpp b/Common/interface/Align.hpp index 1d0d43cc..658ec7ca 100644 --- a/Common/interface/Align.hpp +++ b/Common/interface/Align.hpp @@ -30,6 +30,8 @@ /// \file /// Alignment utilities +#include + #include "../../Platforms/Basic/interface/DebugUtilities.hpp" namespace Diligent @@ -48,6 +50,12 @@ inline T Align(T val, T alignment) return (val + (alignment - 1)) & ~(alignment - 1); } +template +inline T* Align(T* val, size_t alignment) +{ + return reinterpret_cast(Align(reinterpret_cast(val), static_cast(alignment))); +} + template inline T AlignDown(T val, T alignment) { @@ -55,4 +63,10 @@ inline T AlignDown(T val, T alignment) return val & ~(alignment - 1); } +template +inline T* AlignDown(T* val, size_t alignment) +{ + return reinterpret_cast(AlignDown(reinterpret_cast(val), static_cast(alignment))); +} + } // namespace Diligent -- cgit v1.2.3 From 6517f42bf79f13c69ff81a2ccd704c5167cadc15 Mon Sep 17 00:00:00 2001 From: assiduous Date: Sun, 18 Oct 2020 10:40:16 -0700 Subject: Refactored LinearAllocator --- Common/interface/LinearAllocator.hpp | 210 +++++++++++++++++++++++++---------- 1 file changed, 153 insertions(+), 57 deletions(-) (limited to 'Common/interface') diff --git a/Common/interface/LinearAllocator.hpp b/Common/interface/LinearAllocator.hpp index 00f94ee3..c04fdb4e 100644 --- a/Common/interface/LinearAllocator.hpp +++ b/Common/interface/LinearAllocator.hpp @@ -30,6 +30,8 @@ /// \file /// Defines Diligent::LinearAllocator class +#include + #include "../../Primitives/interface/BasicTypes.h" #include "../../Primitives/interface/MemoryAllocator.h" #include "../../Platforms/Basic/interface/DebugUtilities.hpp" @@ -54,16 +56,16 @@ public: LinearAllocator(LinearAllocator&& Other) : // clang-format off - m_pBuffer {Other.m_pBuffer }, - m_pCurrPtr {Other.m_pCurrPtr }, - m_RequiredSize{Other.m_RequiredSize}, - m_pAllocator {Other.m_pAllocator } + m_pDataStart {Other.m_pDataStart}, + m_pCurrPtr {Other.m_pCurrPtr }, + m_pDataEnd {Other.m_pDataEnd }, + m_pAllocator {Other.m_pAllocator} // clang-format on { - Other.m_pBuffer = nullptr; - Other.m_pCurrPtr = nullptr; - Other.m_RequiredSize = 0; - Other.m_pAllocator = nullptr; + Other.m_pDataStart = nullptr; + Other.m_pCurrPtr = nullptr; + Other.m_pDataEnd = nullptr; + Other.m_pAllocator = nullptr; } ~LinearAllocator() @@ -73,60 +75,71 @@ public: void Free() { - if (m_pBuffer != nullptr && m_pAllocator != nullptr) + if (m_pDataStart != nullptr && m_pDataStart != GetDummyMemory() && m_pAllocator != nullptr) { - m_pAllocator->Free(m_pBuffer); + m_pAllocator->Free(m_pDataStart); } - m_pBuffer = nullptr; - m_pCurrPtr = nullptr; - m_RequiredSize = 0; - m_pAllocator = nullptr; + m_pDataStart = nullptr; + m_pCurrPtr = nullptr; + m_pDataEnd = nullptr; + m_pAllocator = nullptr; } void* Release() { - void* Ptr = m_pBuffer; - m_pBuffer = nullptr; - m_pCurrPtr = nullptr; - m_RequiredSize = 0; + void* Ptr = m_pDataStart; + m_pDataStart = nullptr; + m_pCurrPtr = nullptr; + m_pDataEnd = nullptr; + m_pAllocator = nullptr; return Ptr; } - void AddRequiredSize(size_t size, size_t align) + void AddSpace(size_t size, size_t align) { - VERIFY(m_pBuffer == nullptr, "Memory already allocated"); - if (size > 0) - { - size = Align(size, align); - m_RequiredSize = Align(m_RequiredSize, align) + size; - - // Reserve additional space for pointer alignment - m_RequiredSize += (align > sizeof(void*) ? align - sizeof(void*) : 0); - } + VERIFY(m_pDataStart == nullptr || m_pDataStart == GetDummyMemory(), "Memory has already been allocated"); + AllocateInternal(size, align); } template - void AddRequiredSize(size_t count) + void AddSpace(size_t count = 1) + { + AddSpace(sizeof(T) * count, alignof(T)); + } + + void AddSpaceForString(const Char* str) { - AddRequiredSize(sizeof(T) * count, alignof(T)); + VERIFY_EXPR(str != nullptr); + AddSpace(strlen(str) + 1, 1); + } + + void AddSpaceForString(const String& str) + { + AddSpaceForString(str.c_str()); } void Reserve(size_t size) { - VERIFY(m_RequiredSize == 0, "Required size will be overrided by input argument"); - m_RequiredSize = size; + VERIFY(m_pDataStart == nullptr || m_pDataStart == GetDummyMemory(), "Memory has already been allocated"); + VERIFY(m_pCurrPtr == nullptr, "Space has been added to the allocator and will be overriden"); + m_pCurrPtr = m_pDataStart + size; Reserve(); } void Reserve() { - VERIFY(m_pBuffer == nullptr, "Memory already allocated"); + VERIFY(m_pDataStart == nullptr || m_pDataStart == GetDummyMemory(), "Memory has already been allocated"); VERIFY(m_pAllocator != nullptr, "Allocator must not be null"); - if (m_RequiredSize > 0) + // Make sure the data size is at least sizeof(void*)-aligned + auto DataSize = Align(static_cast(m_pCurrPtr - m_pDataStart), sizeof(void*)); + if (DataSize > 0) { - m_pBuffer = reinterpret_cast(m_pAllocator->Allocate(m_RequiredSize, "Memory for linear allocator", __FILE__, __LINE__)); - m_pCurrPtr = m_pBuffer; + m_pDataStart = reinterpret_cast(m_pAllocator->Allocate(DataSize, "Raw memory for linear allocator", __FILE__, __LINE__)); + VERIFY(m_pDataStart == Align(m_pDataStart, sizeof(void*)), "Memory pointer must be at least sizeof(void*)-aligned"); + + m_pCurrPtr = m_pDataStart; + m_pDataEnd = m_pDataStart + DataSize; } } @@ -135,14 +148,12 @@ public: if (size == 0) return nullptr; - uint8_t* Ptr = reinterpret_cast(Align(reinterpret_cast(m_pCurrPtr), align)); - m_pCurrPtr = Ptr + size; - VERIFY(m_pCurrPtr <= m_pBuffer + m_RequiredSize, "Not enough space in the buffer"); - return Ptr; + VERIFY(m_pDataStart != nullptr && m_pDataStart != GetDummyMemory(), "Memory has not been allocated"); + return AllocateInternal(size, align); } template - T* Allocate(size_t count) + T* Allocate(size_t count = 1) { return reinterpret_cast(Allocate(sizeof(T) * count, alignof(T))); } @@ -150,29 +161,32 @@ public: template T* Construct(Args&&... args) { - T* Ptr = Allocate(1); + T* Ptr = Allocate(); new (Ptr) T{std::forward(args)...}; return Ptr; } template - T* ConstructArray(size_t count, Args&&... args) + T* ConstructArray(size_t count, const Args&... args) { T* Ptr = Allocate(count); for (size_t i = 0; i < count; ++i) { - new (Ptr + i) T{std::forward(args)...}; + new (Ptr + i) T{args...}; } return Ptr; } template - T* CopyArray(const T* Src, size_t count) + T* Copy(const T& Src) { - T* Dst = reinterpret_cast(Align(reinterpret_cast(m_pCurrPtr), alignof(T))); - m_pCurrPtr = reinterpret_cast(Dst + count); - VERIFY(m_pCurrPtr <= m_pBuffer + m_RequiredSize, "Not enough space in the buffer"); + return Construct(Src); + } + template + T* CopyArray(const T* Src, size_t count) + { + T* Dst = Allocate(count); for (size_t i = 0; i < count; ++i) { new (Dst + i) T{Src[i]}; @@ -185,25 +199,107 @@ public: if (Str == nullptr) return nullptr; - Char* Ptr = reinterpret_cast(m_pCurrPtr); + auto* Ptr = reinterpret_cast(AllocateInternal(strlen(Str) + 1, 1)); Char* Dst = Ptr; - while (*Str != 0 && Dst < reinterpret_cast(m_pBuffer + m_RequiredSize)) + while (*Str != 0 && Dst < reinterpret_cast(m_pDataEnd)) { *(Dst++) = *(Str++); } - if (Dst < reinterpret_cast(m_pBuffer + m_RequiredSize)) + if (Dst < reinterpret_cast(m_pDataEnd)) *(Dst++) = 0; else - UNEXPECTED("Not enough space reserved in the string pool"); - m_pCurrPtr = reinterpret_cast(Dst); + UNEXPECTED("Not enough space reserved for the string"); + VERIFY_EXPR(reinterpret_cast(m_pCurrPtr) == Dst); return Ptr; } + Char* CopyString(const std::string& Str) + { + return CopyString(Str.c_str()); + } + + size_t GetCurrentSize() const + { + return static_cast(m_pCurrPtr - m_pDataStart); + } + + size_t GetReservedSize() const + { + return static_cast(m_pDataEnd - m_pDataStart); + } + private: - uint8_t* m_pBuffer = nullptr; - uint8_t* m_pCurrPtr = nullptr; - size_t m_RequiredSize = 0; - IMemoryAllocator* m_pAllocator = nullptr; + void* AllocateInternal(size_t size, size_t align) + { + VERIFY(IsPowerOfTwo(align), "Alignment is not a power of two!"); + if (size == 0) + return m_pCurrPtr; + + if (m_pCurrPtr == nullptr) + { + VERIFY_EXPR(m_pDataStart == nullptr); + m_pDataStart = m_pCurrPtr = GetDummyMemory(); + } + + m_pCurrPtr = Align(m_pCurrPtr, align); + auto* ptr = m_pCurrPtr; + +#if DILIGENT_DEBUG + if (m_pDataStart == GetDummyMemory()) + { + m_DbgAllocations.emplace_back(size, align, m_pCurrPtr - m_pDataStart); + } + else + { + VERIFY(m_DbgCurrAllocation < m_DbgAllocations.size(), "Allocation number exceed the number of allocations that were originally reserved."); + const auto& CurrAllocation = m_DbgAllocations[m_DbgCurrAllocation++]; + VERIFY(CurrAllocation.size == size, "Allocation size (", size, ") does not match the initially requested size (", CurrAllocation.size, ")"); + VERIFY(CurrAllocation.alignment == align, "Allocation alignment (", align, ") does not match initially requested alignment (", CurrAllocation.alignment, ")"); + + auto CurrOffset = m_pCurrPtr - m_pDataStart; + VERIFY(CurrOffset <= CurrAllocation.offset, + "Allocation offset exceed the offset that was initially computed. " + "This should never happen as long as the allocated memory is sizeof(void*)-aligned."); + } +#endif + + m_pCurrPtr += size; + + VERIFY(m_pDataEnd == nullptr || m_pCurrPtr <= m_pDataEnd, "Allocation size exceeds the reserved space"); + + return ptr; + } + + static uint8_t* GetDummyMemory() + { + // Simulate that allocated memory is only sizeof(void*)-aligned + auto* DummyMemory = reinterpret_cast(sizeof(void*)); + VERIFY_EXPR(DummyMemory != nullptr); + return DummyMemory; + } + + uint8_t* m_pDataStart = nullptr; + uint8_t* m_pCurrPtr = nullptr; + uint8_t* m_pDataEnd = nullptr; + IMemoryAllocator* m_pAllocator = nullptr; + +#if DILIGENT_DEBUG + size_t m_DbgCurrAllocation = 0; + struct DbgAllocationInfo + { + const size_t size; + const size_t alignment; + const ptrdiff_t offset; + + DbgAllocationInfo(size_t _size, size_t _alignment, ptrdiff_t _offset) : + size{_size}, + alignment{_alignment}, + offset{_offset} + { + } + }; + std::vector m_DbgAllocations; +#endif }; } // namespace Diligent -- cgit v1.2.3 From 9ea9a53c4e0c414aa4eb2c7d9b5e22221fd78c5e Mon Sep 17 00:00:00 2001 From: assiduous Date: Sun, 18 Oct 2020 13:14:08 -0700 Subject: Fixed Codacy issue --- Common/interface/LinearAllocator.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Common/interface') diff --git a/Common/interface/LinearAllocator.hpp b/Common/interface/LinearAllocator.hpp index c04fdb4e..b38563af 100644 --- a/Common/interface/LinearAllocator.hpp +++ b/Common/interface/LinearAllocator.hpp @@ -50,7 +50,7 @@ public: LinearAllocator& operator=(LinearAllocator&&) = delete; // clang-format on - LinearAllocator(IMemoryAllocator& Allocator) : + explicit LinearAllocator(IMemoryAllocator& Allocator) : m_pAllocator{&Allocator} {} -- cgit v1.2.3 From 3638b2e425f316202686511bd28922a4a0f7e594 Mon Sep 17 00:00:00 2001 From: assiduous Date: Sun, 18 Oct 2020 16:41:15 -0700 Subject: Fixed issues with alignment in linear allocator --- Common/interface/LinearAllocator.hpp | 185 ++++++++++++++++++----------------- 1 file changed, 93 insertions(+), 92 deletions(-) (limited to 'Common/interface') diff --git a/Common/interface/LinearAllocator.hpp b/Common/interface/LinearAllocator.hpp index b38563af..f8f779e5 100644 --- a/Common/interface/LinearAllocator.hpp +++ b/Common/interface/LinearAllocator.hpp @@ -56,16 +56,14 @@ public: LinearAllocator(LinearAllocator&& Other) : // clang-format off - m_pDataStart {Other.m_pDataStart}, - m_pCurrPtr {Other.m_pCurrPtr }, - m_pDataEnd {Other.m_pDataEnd }, - m_pAllocator {Other.m_pAllocator} + m_pDataStart {Other.m_pDataStart }, + m_pCurrPtr {Other.m_pCurrPtr }, + m_ReservedSize {Other.m_ReservedSize }, + m_CurrAlignment{Other.m_CurrAlignment}, + m_pAllocator {Other.m_pAllocator } // clang-format on { - Other.m_pDataStart = nullptr; - Other.m_pCurrPtr = nullptr; - Other.m_pDataEnd = nullptr; - Other.m_pAllocator = nullptr; + Other.Reset(); } ~LinearAllocator() @@ -75,31 +73,47 @@ public: void Free() { - if (m_pDataStart != nullptr && m_pDataStart != GetDummyMemory() && m_pAllocator != nullptr) + if (m_pDataStart != nullptr && m_pAllocator != nullptr) { m_pAllocator->Free(m_pDataStart); } - - m_pDataStart = nullptr; - m_pCurrPtr = nullptr; - m_pDataEnd = nullptr; - m_pAllocator = nullptr; + Reset(); } void* Release() { - void* Ptr = m_pDataStart; - m_pDataStart = nullptr; - m_pCurrPtr = nullptr; - m_pDataEnd = nullptr; - m_pAllocator = nullptr; + void* Ptr = m_pDataStart; + Reset(); return Ptr; } - void AddSpace(size_t size, size_t align) + void AddSpace(size_t size, size_t alignment) { - VERIFY(m_pDataStart == nullptr || m_pDataStart == GetDummyMemory(), "Memory has already been allocated"); - AllocateInternal(size, align); + VERIFY(m_pDataStart == nullptr, "Memory has already been allocated"); + VERIFY(IsPowerOfTwo(alignment), "Alignment is not a power of two!"); + + if (size == 0) + return; + + if (m_CurrAlignment == 0) + { + VERIFY(m_ReservedSize == 0, "This is expected to be a very first time the space is added"); + m_CurrAlignment = sizeof(void*); + } + + if (alignment > m_CurrAlignment) + { + // Reserve extra space that may be needed for alignment + m_ReservedSize += alignment - m_CurrAlignment; + } + m_CurrAlignment = alignment; + + size = Align(size, alignment); + m_ReservedSize += size; + +#if DILIGENT_DEBUG + m_DbgAllocations.emplace_back(size, alignment, m_ReservedSize); +#endif } template @@ -121,35 +135,58 @@ public: void Reserve(size_t size) { - VERIFY(m_pDataStart == nullptr || m_pDataStart == GetDummyMemory(), "Memory has already been allocated"); - VERIFY(m_pCurrPtr == nullptr, "Space has been added to the allocator and will be overriden"); - m_pCurrPtr = m_pDataStart + size; + VERIFY(m_pDataStart == nullptr, "Memory has already been allocated"); + VERIFY(m_ReservedSize == 0, "Space has been added to the allocator and will be overriden"); + m_ReservedSize = size; Reserve(); } void Reserve() { - VERIFY(m_pDataStart == nullptr || m_pDataStart == GetDummyMemory(), "Memory has already been allocated"); + VERIFY(m_pDataStart == nullptr, "Memory has already been allocated"); VERIFY(m_pAllocator != nullptr, "Allocator must not be null"); // Make sure the data size is at least sizeof(void*)-aligned - auto DataSize = Align(static_cast(m_pCurrPtr - m_pDataStart), sizeof(void*)); - if (DataSize > 0) + m_ReservedSize = Align(m_ReservedSize, sizeof(void*)); + if (m_ReservedSize > 0) { - m_pDataStart = reinterpret_cast(m_pAllocator->Allocate(DataSize, "Raw memory for linear allocator", __FILE__, __LINE__)); + m_pDataStart = reinterpret_cast(m_pAllocator->Allocate(m_ReservedSize, "Raw memory for linear allocator", __FILE__, __LINE__)); VERIFY(m_pDataStart == Align(m_pDataStart, sizeof(void*)), "Memory pointer must be at least sizeof(void*)-aligned"); m_pCurrPtr = m_pDataStart; - m_pDataEnd = m_pDataStart + DataSize; } + m_CurrAlignment = sizeof(void*); } - void* Allocate(size_t size, size_t align) + void* Allocate(size_t size, size_t alignment) { + VERIFY(size == 0 || m_pDataStart != nullptr, "Memory has not been allocated"); + VERIFY(IsPowerOfTwo(alignment), "Alignment is not a power of two!"); + if (size == 0) return nullptr; - VERIFY(m_pDataStart != nullptr && m_pDataStart != GetDummyMemory(), "Memory has not been allocated"); - return AllocateInternal(size, align); + size = Align(size, alignment); + +#if DILIGENT_DEBUG + VERIFY(m_DbgCurrAllocation < m_DbgAllocations.size(), "Allocation number exceed the number of allocations that were originally reserved."); + const auto& CurrAllocation = m_DbgAllocations[m_DbgCurrAllocation++]; + VERIFY(CurrAllocation.size == size, "Allocation size (", size, ") does not match the initially requested size (", CurrAllocation.size, ")"); + VERIFY(CurrAllocation.alignment == alignment, "Allocation alignment (", alignment, ") does not match the initially requested alignment (", CurrAllocation.alignment, ")"); +#endif + + VERIFY(Align(m_pCurrPtr, m_CurrAlignment) == m_pCurrPtr, "Current pointer is not aligned as expected"); + m_pCurrPtr = Align(m_pCurrPtr, alignment); + m_CurrAlignment = alignment; + + VERIFY(m_pCurrPtr + size <= m_pDataStart + CurrAllocation.reserved_size, + "Allocation size exceeds the initially reserved space. This is likely a bug."); + + auto* ptr = m_pCurrPtr; + m_pCurrPtr += size; + + VERIFY(m_pCurrPtr <= m_pDataStart + m_ReservedSize, "Allocation size exceeds the reserved space"); + + return ptr; } template @@ -199,16 +236,19 @@ public: if (Str == nullptr) return nullptr; - auto* Ptr = reinterpret_cast(AllocateInternal(strlen(Str) + 1, 1)); + auto* Ptr = reinterpret_cast(Allocate(strlen(Str) + 1, 1)); Char* Dst = Ptr; - while (*Str != 0 && Dst < reinterpret_cast(m_pDataEnd)) + + const auto* pDataEnd = reinterpret_cast(m_pDataStart) + m_ReservedSize; + while (*Str != 0 && Dst < pDataEnd) { *(Dst++) = *(Str++); } - if (Dst < reinterpret_cast(m_pDataEnd)) + if (Dst < pDataEnd) *(Dst++) = 0; else UNEXPECTED("Not enough space reserved for the string"); + VERIFY_EXPR(reinterpret_cast(m_pCurrPtr) == Dst); return Ptr; } @@ -225,76 +265,37 @@ public: size_t GetReservedSize() const { - return static_cast(m_pDataEnd - m_pDataStart); + return m_ReservedSize; } private: - void* AllocateInternal(size_t size, size_t align) - { - VERIFY(IsPowerOfTwo(align), "Alignment is not a power of two!"); - if (size == 0) - return m_pCurrPtr; - - if (m_pCurrPtr == nullptr) - { - VERIFY_EXPR(m_pDataStart == nullptr); - m_pDataStart = m_pCurrPtr = GetDummyMemory(); - } - - m_pCurrPtr = Align(m_pCurrPtr, align); - auto* ptr = m_pCurrPtr; - -#if DILIGENT_DEBUG - if (m_pDataStart == GetDummyMemory()) - { - m_DbgAllocations.emplace_back(size, align, m_pCurrPtr - m_pDataStart); - } - else - { - VERIFY(m_DbgCurrAllocation < m_DbgAllocations.size(), "Allocation number exceed the number of allocations that were originally reserved."); - const auto& CurrAllocation = m_DbgAllocations[m_DbgCurrAllocation++]; - VERIFY(CurrAllocation.size == size, "Allocation size (", size, ") does not match the initially requested size (", CurrAllocation.size, ")"); - VERIFY(CurrAllocation.alignment == align, "Allocation alignment (", align, ") does not match initially requested alignment (", CurrAllocation.alignment, ")"); - - auto CurrOffset = m_pCurrPtr - m_pDataStart; - VERIFY(CurrOffset <= CurrAllocation.offset, - "Allocation offset exceed the offset that was initially computed. " - "This should never happen as long as the allocated memory is sizeof(void*)-aligned."); - } -#endif - - m_pCurrPtr += size; - - VERIFY(m_pDataEnd == nullptr || m_pCurrPtr <= m_pDataEnd, "Allocation size exceeds the reserved space"); - - return ptr; - } - - static uint8_t* GetDummyMemory() + void Reset() { - // Simulate that allocated memory is only sizeof(void*)-aligned - auto* DummyMemory = reinterpret_cast(sizeof(void*)); - VERIFY_EXPR(DummyMemory != nullptr); - return DummyMemory; + m_pDataStart = nullptr; + m_pCurrPtr = nullptr; + m_ReservedSize = 0; + m_CurrAlignment = 0; + m_pAllocator = nullptr; } - uint8_t* m_pDataStart = nullptr; - uint8_t* m_pCurrPtr = nullptr; - uint8_t* m_pDataEnd = nullptr; - IMemoryAllocator* m_pAllocator = nullptr; + uint8_t* m_pDataStart = nullptr; + uint8_t* m_pCurrPtr = nullptr; + size_t m_ReservedSize = 0; + size_t m_CurrAlignment = 0; + IMemoryAllocator* m_pAllocator = nullptr; #if DILIGENT_DEBUG size_t m_DbgCurrAllocation = 0; struct DbgAllocationInfo { - const size_t size; - const size_t alignment; - const ptrdiff_t offset; + const size_t size; + const size_t alignment; + const size_t reserved_size; - DbgAllocationInfo(size_t _size, size_t _alignment, ptrdiff_t _offset) : + DbgAllocationInfo(size_t _size, size_t _alignment, size_t _reserved_size) : size{_size}, alignment{_alignment}, - offset{_offset} + reserved_size{_reserved_size} { } }; -- cgit v1.2.3 From 13b0b54987db2684e46e337d2e5be5b81366083b Mon Sep 17 00:00:00 2001 From: assiduous Date: Tue, 20 Oct 2020 13:26:21 -0700 Subject: Improved exception safety of pipeline state object construction --- Common/interface/LinearAllocator.hpp | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'Common/interface') diff --git a/Common/interface/LinearAllocator.hpp b/Common/interface/LinearAllocator.hpp index f8f779e5..dd137c47 100644 --- a/Common/interface/LinearAllocator.hpp +++ b/Common/interface/LinearAllocator.hpp @@ -50,11 +50,11 @@ public: LinearAllocator& operator=(LinearAllocator&&) = delete; // clang-format on - explicit LinearAllocator(IMemoryAllocator& Allocator) : + explicit LinearAllocator(IMemoryAllocator& Allocator) noexcept : m_pAllocator{&Allocator} {} - LinearAllocator(LinearAllocator&& Other) : + LinearAllocator(LinearAllocator&& Other) noexcept : // clang-format off m_pDataStart {Other.m_pDataStart }, m_pCurrPtr {Other.m_pCurrPtr }, @@ -87,7 +87,18 @@ public: return Ptr; } - void AddSpace(size_t size, size_t alignment) + void* ReleaseOwnership() noexcept + { + m_pAllocator = nullptr; + return GetDataPtr(); + } + + void* GetDataPtr() const noexcept + { + return m_pDataStart; + } + + void AddSpace(size_t size, size_t alignment) noexcept { VERIFY(m_pDataStart == nullptr, "Memory has already been allocated"); VERIFY(IsPowerOfTwo(alignment), "Alignment is not a power of two!"); @@ -117,18 +128,18 @@ public: } template - void AddSpace(size_t count = 1) + void AddSpace(size_t count = 1) noexcept { AddSpace(sizeof(T) * count, alignof(T)); } - void AddSpaceForString(const Char* str) + void AddSpaceForString(const Char* str) noexcept { VERIFY_EXPR(str != nullptr); AddSpace(strlen(str) + 1, 1); } - void AddSpaceForString(const String& str) + void AddSpaceForString(const String& str) noexcept { AddSpaceForString(str.c_str()); } -- cgit v1.2.3