diff --git a/src/ZoneCommon/Zone/XBlock.cpp b/src/ZoneCommon/Zone/XBlock.cpp index 239ab536..fbe8f66d 100644 --- a/src/ZoneCommon/Zone/XBlock.cpp +++ b/src/ZoneCommon/Zone/XBlock.cpp @@ -1,5 +1,19 @@ #include "XBlock.h" +#include + +namespace +{ + // This must be higher or equal to the highest alignment value in any game struct. + // The games always seem to align to 4096 up to T6 so we'll keep parity. + constexpr std::align_val_t XBLOCK_BUFFER_ALIGNMENT{4096u}; +} // namespace + +void XBlockBufferDeleter::operator()(std::uint8_t* buffer) const noexcept +{ + ::operator delete[](buffer, XBLOCK_BUFFER_ALIGNMENT); +} + XBlock::XBlock(std::string name, const unsigned index, const XBlockType type) : m_name(std::move(name)), m_index(index), @@ -12,7 +26,7 @@ void XBlock::Alloc(const size_t blockSize) { if (blockSize > 0) { - m_buffer = std::make_unique(blockSize); + m_buffer.reset(static_cast(::operator new[](blockSize, XBLOCK_BUFFER_ALIGNMENT))); m_buffer_size = blockSize; } else diff --git a/src/ZoneCommon/Zone/XBlock.h b/src/ZoneCommon/Zone/XBlock.h index a1cb17c4..a15128f3 100644 --- a/src/ZoneCommon/Zone/XBlock.h +++ b/src/ZoneCommon/Zone/XBlock.h @@ -13,6 +13,11 @@ enum class XBlockType : std::uint8_t BLOCK_TYPE_NORMAL }; +struct XBlockBufferDeleter +{ + void operator()(std::uint8_t* buffer) const noexcept; +}; + class XBlock { public: @@ -24,6 +29,6 @@ public: unsigned m_index; XBlockType m_type; - std::unique_ptr m_buffer; + std::unique_ptr m_buffer; size_t m_buffer_size; }; diff --git a/test/ZoneCommonTests/Zone/XBlockTests.cpp b/test/ZoneCommonTests/Zone/XBlockTests.cpp new file mode 100644 index 00000000..c3c2debb --- /dev/null +++ b/test/ZoneCommonTests/Zone/XBlockTests.cpp @@ -0,0 +1,27 @@ +#include "Zone/XBlock.h" + +#include +#include +#include + +namespace +{ + TEST_CASE("Zone block buffers provide the maximum asset alignment", "[zone-loading][stream]") + { + static constexpr std::uintptr_t REQUIRED_ALIGNMENT = 4096u; + + XBlock block("test", 0, XBlockType::BLOCK_TYPE_NORMAL); + constexpr size_t sizes[]{1u, 7u, 16u, 4096u, 65537u}; + + for (const auto size : sizes) + { + block.Alloc(size); + REQUIRE(reinterpret_cast(block.m_buffer.get()) % REQUIRED_ALIGNMENT == 0u); + REQUIRE(block.m_buffer_size == size); + } + + block.Alloc(0u); + REQUIRE(block.m_buffer.get() == nullptr); + REQUIRE(block.m_buffer_size == 0u); + } +} // namespace