From ff25e839f30720394d912046e64821b1c1015c7b Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Mon, 14 Mar 2022 07:26:24 +0100 Subject: [PATCH 1/5] Make sure DefaultAllocator and SingleFrameAllocator returned 16-bytes aligned memory --- CHANGELOG.md | 3 + CMakeLists.txt | 4 +- include/reactphysics3d/configuration.h | 3 + .../reactphysics3d/memory/DefaultAllocator.h | 30 ++++- .../reactphysics3d/memory/MemoryAllocator.h | 2 +- include/reactphysics3d/memory/MemoryManager.h | 14 ++- include/reactphysics3d/memory/PoolAllocator.h | 7 +- .../memory/SingleFrameAllocator.h | 11 -- src/memory/HeapAllocator.cpp | 10 +- src/memory/PoolAllocator.cpp | 24 +++- src/memory/SingleFrameAllocator.cpp | 106 ++++++++---------- 11 files changed, 122 insertions(+), 92 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31510eaf..900a83b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ ### Changed + - The library must now be compiled with C++ 17 compiler + - If the user sets its custom allocator, the return allocated memory must now be 16 bytes aligned + ### Removed ### Fixed diff --git a/CMakeLists.txt b/CMakeLists.txt index c18a8c65..6bb2eaac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ # Minimum cmake version required -cmake_minimum_required(VERSION 3.8) +cmake_minimum_required(VERSION 3.10) # Project configuration project(ReactPhysics3D VERSION 0.9.0 LANGUAGES CXX) @@ -242,7 +242,7 @@ add_library(reactphysics3d ${REACTPHYSICS3D_HEADERS} ${REACTPHYSICS3D_SOURCES}) add_library(ReactPhysics3D::reactphysics3d ALIAS reactphysics3d) # C++11 compiler features -target_compile_features(reactphysics3d PUBLIC cxx_std_11) +target_compile_features(reactphysics3d PUBLIC cxx_std_17) set_target_properties(reactphysics3d PROPERTIES CXX_EXTENSIONS OFF) # Library headers diff --git a/include/reactphysics3d/configuration.h b/include/reactphysics3d/configuration.h index 6f2de958..7e6efdd5 100644 --- a/include/reactphysics3d/configuration.h +++ b/include/reactphysics3d/configuration.h @@ -129,6 +129,9 @@ constexpr uint16 NB_MAX_CONTACT_POINTS_IN_POTENTIAL_MANIFOLD = 256; /// Distance threshold to consider that two contact points in a manifold are the same constexpr decimal SAME_CONTACT_POINT_DISTANCE_THRESHOLD = decimal(0.01); +/// Global alignment (in bytes) that all allocators must enforce +constexpr uint8 GLOBAL_ALIGNMENT = 16; + /// Current version of ReactPhysics3D const std::string RP3D_VERSION = std::string("0.9.0"); diff --git a/include/reactphysics3d/memory/DefaultAllocator.h b/include/reactphysics3d/memory/DefaultAllocator.h index ec2ef0ae..d928741c 100644 --- a/include/reactphysics3d/memory/DefaultAllocator.h +++ b/include/reactphysics3d/memory/DefaultAllocator.h @@ -28,15 +28,19 @@ // Libraries #include +#include #include #include +#include /// ReactPhysics3D namespace namespace reactphysics3d { // Class DefaultAllocator /** - * This class represents a default memory allocator that uses default malloc/free methods + * This class represents a default memory allocator that uses standard C++ functions + * to allocated 16-bytes aligned memory. + * */ class DefaultAllocator : public MemoryAllocator { @@ -49,15 +53,33 @@ class DefaultAllocator : public MemoryAllocator { DefaultAllocator& operator=(DefaultAllocator& allocator) = default; /// Allocate memory of a given size (in bytes) and return a pointer to the - /// allocated memory. + /// allocated memory. The returned allocated memory must be 16 bytes aligned. virtual void* allocate(size_t size) override { - return std::malloc(size); +// If compiler is Visual Studio +#ifdef _MSC_VER + + // Visual Studio doesn't not support standard std:aligned_alloc() method from c++ 17 + return _alligned_malloc(size, GLOBAL_ALIGNMENT); +#else + + // Return 16-bytes aligned memory + return std::aligned_alloc(GLOBAL_ALIGNMENT, size); +#endif } /// Release previously allocated memory. virtual void release(void* pointer, size_t /*size*/) override { - std::free(pointer); + + // If compiler is Visual Studio +#ifdef _MSC_VER + + // Visual Studio doesn't not support standard std:aligned_alloc() method from c++ 17 + return _aligned_free(GLOBAL_ALIGNMENT, pointer); +#else + + return std::free(pointer); +#endif } }; diff --git a/include/reactphysics3d/memory/MemoryAllocator.h b/include/reactphysics3d/memory/MemoryAllocator.h index 9111f3d7..0e732a44 100644 --- a/include/reactphysics3d/memory/MemoryAllocator.h +++ b/include/reactphysics3d/memory/MemoryAllocator.h @@ -50,7 +50,7 @@ class MemoryAllocator { MemoryAllocator& operator=(MemoryAllocator& allocator) = default; /// Allocate memory of a given size (in bytes) and return a pointer to the - /// allocated memory. + /// allocated memory. The return allocated memory must be 16 bytes aligned. virtual void* allocate(size_t size)=0; /// Release previously allocated memory. diff --git a/include/reactphysics3d/memory/MemoryManager.h b/include/reactphysics3d/memory/MemoryManager.h index cf6505bb..e3e7747c 100644 --- a/include/reactphysics3d/memory/MemoryManager.h +++ b/include/reactphysics3d/memory/MemoryManager.h @@ -104,14 +104,18 @@ class MemoryManager { // Allocate memory of a given type RP3D_FORCE_INLINE void* MemoryManager::allocate(AllocationType allocationType, size_t size) { + void* allocatedMemory = nullptr; + switch (allocationType) { - case AllocationType::Base: return mBaseAllocator->allocate(size); - case AllocationType::Pool: return mPoolAllocator.allocate(size); - case AllocationType::Heap: return mHeapAllocator.allocate(size); - case AllocationType::Frame: return mSingleFrameAllocator.allocate(size); + case AllocationType::Base: allocatedMemory = mBaseAllocator->allocate(size); break; + case AllocationType::Pool: allocatedMemory = mPoolAllocator.allocate(size); break; + case AllocationType::Heap: allocatedMemory = mHeapAllocator.allocate(size); break; + case AllocationType::Frame: allocatedMemory = mSingleFrameAllocator.allocate(size); break; } - return nullptr; + assert(allocatedMemory == nullptr || reinterpret_cast(allocatedMemory) % 16 == 0); + + return allocatedMemory; } // Release previously allocated memory. diff --git a/include/reactphysics3d/memory/PoolAllocator.h b/include/reactphysics3d/memory/PoolAllocator.h index 95f56a1f..c2016143 100644 --- a/include/reactphysics3d/memory/PoolAllocator.h +++ b/include/reactphysics3d/memory/PoolAllocator.h @@ -81,13 +81,16 @@ class PoolAllocator : public MemoryAllocator { /// Number of heaps static const int NB_HEAPS = 128; + /// Minimum unit size + static const size_t MIN_UNIT_SIZE = 16; + /// Maximum memory unit size. An allocation request of a size smaller or equal to /// this size will be handled using the small block allocator. However, for an /// allocation request larger than the maximum block size, the standard malloc() /// will be used. - static const size_t MAX_UNIT_SIZE = 1024; + static const size_t MAX_UNIT_SIZE = NB_HEAPS * MIN_UNIT_SIZE; - /// Size a memory chunk + /// Size of a memory chunk static const size_t BLOCK_SIZE = 16 * MAX_UNIT_SIZE; // -------------------- Attributes -------------------- // diff --git a/include/reactphysics3d/memory/SingleFrameAllocator.h b/include/reactphysics3d/memory/SingleFrameAllocator.h index b53b8a4a..c3b006a5 100644 --- a/include/reactphysics3d/memory/SingleFrameAllocator.h +++ b/include/reactphysics3d/memory/SingleFrameAllocator.h @@ -45,10 +45,6 @@ class SingleFrameAllocator : public MemoryAllocator { // -------------------- Constants -------------------- // - /// Number of frames to wait before shrinking the allocated - /// memory if too much is allocated - static const int NB_FRAMES_UNTIL_SHRINK = 120; - /// Initial size (in bytes) of the single frame allocator size_t INIT_SINGLE_FRAME_ALLOCATOR_NB_BYTES = 1048576; // 1Mb @@ -69,13 +65,6 @@ class SingleFrameAllocator : public MemoryAllocator { /// Pointer to the next available memory location in the buffer size_t mCurrentOffset; - /// Current number of frames since we detected too much memory - /// is allocated - size_t mNbFramesTooMuchAllocated; - - /// True if we need to allocate more memory in the next reset() call - bool mNeedToAllocatedMore; - public : // -------------------- Methods -------------------- // diff --git a/src/memory/HeapAllocator.cpp b/src/memory/HeapAllocator.cpp index 85f06337..9dc92682 100644 --- a/src/memory/HeapAllocator.cpp +++ b/src/memory/HeapAllocator.cpp @@ -175,7 +175,12 @@ void* HeapAllocator::allocate(size_t size) { } // Return a pointer to the memory area inside the unit - return static_cast(reinterpret_cast(currentUnit) + sizeof(MemoryUnitHeader)); + void* allocatedMemory = static_cast(reinterpret_cast(currentUnit) + sizeof(MemoryUnitHeader)); + + // Check that allocated memory is 16-bytes aligned + assert(reinterpret_cast(allocatedMemory) % GLOBAL_ALIGNMENT == 0); + + return allocatedMemory; } // Release previously allocated memory. @@ -251,6 +256,9 @@ void HeapAllocator::reserve(size_t sizeToAllocate) { void* memory = mBaseAllocator.allocate(sizeToAllocate + sizeof(MemoryUnitHeader)); assert(memory != nullptr); + // Check that allocated memory is 16-bytes aligned + assert(reinterpret_cast(memory) % GLOBAL_ALIGNMENT == 0); + // Create a new memory unit for the allocated memory MemoryUnitHeader* memoryUnit = new (memory) MemoryUnitHeader(sizeToAllocate, nullptr, mMemoryUnits, false); diff --git a/src/memory/PoolAllocator.cpp b/src/memory/PoolAllocator.cpp index c8fcc680..d8fcfbbe 100644 --- a/src/memory/PoolAllocator.cpp +++ b/src/memory/PoolAllocator.cpp @@ -57,7 +57,7 @@ PoolAllocator::PoolAllocator(MemoryAllocator& baseAllocator) : mBaseAllocator(ba // Initialize the array that contains the sizes of the memory units that will // be allocated in each different heap for (uint i=0; i < NB_HEAPS; i++) { - mUnitSizes[i] = (i+1) * 8; + mUnitSizes[i] = (i+1) * MIN_UNIT_SIZE; } // Initialize the lookup table that maps the size to allocated to the @@ -116,7 +116,12 @@ void* PoolAllocator::allocate(size_t size) { if (size > MAX_UNIT_SIZE) { // Allocate memory using default allocation - return mBaseAllocator.allocate(size); + void* allocatedMemory = mBaseAllocator.allocate(size); + + // Check that allocated memory is 16-bytes aligned + assert(reinterpret_cast(allocatedMemory) % GLOBAL_ALIGNMENT == 0); + + return allocatedMemory; } // Get the index of the heap that will take care of the allocation request @@ -129,7 +134,13 @@ void* PoolAllocator::allocate(size_t size) { // Return a pointer to the memory unit MemoryUnit* unit = mFreeMemoryUnits[indexHeap]; mFreeMemoryUnits[indexHeap] = unit->nextUnit; - return unit; + + void* allocatedMemory = static_cast(unit); + + // Check that allocated memory is 16-bytes aligned + assert(reinterpret_cast(allocatedMemory) % GLOBAL_ALIGNMENT == 0); + + return allocatedMemory; } else { // If there is no more free memory units in the corresponding heap @@ -170,8 +181,13 @@ void* PoolAllocator::allocate(size_t size) { mFreeMemoryUnits[indexHeap] = newBlock->memoryUnits->nextUnit; mNbCurrentMemoryBlocks++; + void* allocatedMemory = newBlock->memoryUnits; + + // Check that allocated memory is 16-bytes aligned + assert(reinterpret_cast(allocatedMemory) % GLOBAL_ALIGNMENT == 0); + // Return the pointer to the first memory unit of the new allocated block - return newBlock->memoryUnits; + return allocatedMemory; } } diff --git a/src/memory/SingleFrameAllocator.cpp b/src/memory/SingleFrameAllocator.cpp index 8cc1970a..6a87ee42 100644 --- a/src/memory/SingleFrameAllocator.cpp +++ b/src/memory/SingleFrameAllocator.cpp @@ -34,7 +34,7 @@ using namespace reactphysics3d; // Constructor SingleFrameAllocator::SingleFrameAllocator(MemoryAllocator& baseAllocator) : mBaseAllocator(baseAllocator), mTotalSizeBytes(INIT_SINGLE_FRAME_ALLOCATOR_NB_BYTES), - mCurrentOffset(0), mNbFramesTooMuchAllocated(0), mNeedToAllocatedMore(false) { + mCurrentOffset(0) { // Allocate a whole block of memory at the beginning mMemoryBufferStart = static_cast(mBaseAllocator.allocate(mTotalSizeBytes)); @@ -48,47 +48,71 @@ SingleFrameAllocator::~SingleFrameAllocator() { mBaseAllocator.release(mMemoryBufferStart, mTotalSizeBytes); } - // Allocate memory of a given size (in bytes) and return a pointer to the -// allocated memory. +// allocated memory. Allocated memory must be 16-bytes aligned. void* SingleFrameAllocator::allocate(size_t size) { // Lock the method with a mutex std::lock_guard lock(mMutex); + // Allocate a little bit more memory to make sure we can return an aligned address + const size_t totalSize = size + GLOBAL_ALIGNMENT; + // Check that there is enough remaining memory in the buffer - if (mCurrentOffset + size > mTotalSizeBytes) { + if (mCurrentOffset + totalSize > mTotalSizeBytes) { - // We need to allocate more memory next time reset() is called - mNeedToAllocatedMore = true; + const size_t previousTotalSizeBytes = mTotalSizeBytes; - // Return default memory allocation - return mBaseAllocator.allocate(size); + // Multiply the total memory to allocate by two + mTotalSizeBytes *= 2; + + // Allocate a whole block of memory + void* allocatedMemory = mBaseAllocator.allocate(mTotalSizeBytes); + assert(allocatedMemory != nullptr); + + // Check that allocated memory is 16-bytes aligned + assert(reinterpret_cast(allocatedMemory) % GLOBAL_ALIGNMENT == 0); + + char* newMemoryBufferStart = static_cast(allocatedMemory); + + // Copy the previous memory bloc to new new location + memcpy(newMemoryBufferStart, mMemoryBufferStart, previousTotalSizeBytes); + + // Release the memory allocated at the beginning + mBaseAllocator.release(mMemoryBufferStart, previousTotalSizeBytes); + + mMemoryBufferStart = newMemoryBufferStart; } // Next available memory location void* nextAvailableMemory = mMemoryBufferStart + mCurrentOffset; + // Take care of alignment to make sure that we always return an address to the + // enforce the global alignment of the library + uintptr_t currentAdress = reinterpret_cast(nextAvailableMemory); + + // Calculate the adjustment by masking off the lower bits of the address, to determine how "misaligned" it is. + size_t mask = GLOBAL_ALIGNMENT - 1; + uintptr_t misalignment = currentAdress & mask; + ptrdiff_t alignmentOffset = GLOBAL_ALIGNMENT - misalignment; + + // Compute the aligned address + uintptr_t alignedAdress = currentAdress + alignmentOffset; + nextAvailableMemory = reinterpret_cast(alignedAdress); + // Increment the offset - mCurrentOffset += size; + mCurrentOffset += totalSize; + + // Check that allocated memory is 16-bytes aligned + assert(reinterpret_cast(nextAvailableMemory) % GLOBAL_ALIGNMENT == 0); // Return the next available memory location return nextAvailableMemory; } // Release previously allocated memory. -void SingleFrameAllocator::release(void* pointer, size_t size) { +void SingleFrameAllocator::release(void* /*pointer*/, size_t /*size*/) { - // Lock the method with a mutex - std::lock_guard lock(mMutex); - - // If allocated memory is not within the single frame allocation range - char* p = static_cast(pointer); - if (p < mMemoryBufferStart || p > mMemoryBufferStart + mTotalSizeBytes) { - - // Use default deallocation - mBaseAllocator.release(pointer, size); - } } // Reset the marker of the current allocated memory @@ -97,48 +121,6 @@ void SingleFrameAllocator::reset() { // Lock the method with a mutex std::lock_guard lock(mMutex); - // If too much memory is allocated - if (mCurrentOffset < mTotalSizeBytes / 2) { - - mNbFramesTooMuchAllocated++; - - if (mNbFramesTooMuchAllocated > NB_FRAMES_UNTIL_SHRINK) { - - // Release the memory allocated at the beginning - mBaseAllocator.release(mMemoryBufferStart, mTotalSizeBytes); - - // Divide the total memory to allocate by two - mTotalSizeBytes /= 2; - if (mTotalSizeBytes == 0) mTotalSizeBytes = 1; - - // Allocate a whole block of memory at the beginning - mMemoryBufferStart = static_cast(mBaseAllocator.allocate(mTotalSizeBytes)); - assert(mMemoryBufferStart != nullptr); - - mNbFramesTooMuchAllocated = 0; - } - } - else { - mNbFramesTooMuchAllocated = 0; - } - - // If we need to allocate more memory - if (mNeedToAllocatedMore) { - - // Release the memory allocated at the beginning - mBaseAllocator.release(mMemoryBufferStart, mTotalSizeBytes); - - // Multiply the total memory to allocate by two - mTotalSizeBytes *= 2; - - // Allocate a whole block of memory at the beginning - mMemoryBufferStart = static_cast(mBaseAllocator.allocate(mTotalSizeBytes)); - assert(mMemoryBufferStart != nullptr); - - mNeedToAllocatedMore = false; - mNbFramesTooMuchAllocated = 0; - } - // Reset the current offset at the beginning of the block mCurrentOffset = 0; } From b05f12850d394c2b1a89ad580ef7b9a275bbb0d6 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Thu, 24 Mar 2022 21:56:54 +0100 Subject: [PATCH 2/5] Modifications of allocators --- include/reactphysics3d/memory/HeapAllocator.h | 40 ++-- .../memory/SingleFrameAllocator.h | 3 + src/memory/HeapAllocator.cpp | 173 +++++++++++++----- src/memory/SingleFrameAllocator.cpp | 73 +++++--- 4 files changed, 201 insertions(+), 88 deletions(-) diff --git a/include/reactphysics3d/memory/HeapAllocator.h b/include/reactphysics3d/memory/HeapAllocator.h index 940853fd..6eedb8c8 100644 --- a/include/reactphysics3d/memory/HeapAllocator.h +++ b/include/reactphysics3d/memory/HeapAllocator.h @@ -57,26 +57,33 @@ class HeapAllocator : public MemoryAllocator { // -------------------- Attributes -------------------- // - /// Size in bytes of the allocated memory unit - size_t size; - - /// True if the memory unit is currently allocated - bool isAllocated; - /// Pointer to the previous memory unit MemoryUnitHeader* previousUnit; /// Pointer to the next memory unit MemoryUnitHeader* nextUnit; + /// Pointer to the previous free (not allocated) memory unit + MemoryUnitHeader* previousFreeUnit; + + /// Pointer to the next free (not allocated) memory unit + MemoryUnitHeader* nextFreeUnit; + + /// Size in bytes of the allocated memory unit + size_t size; + /// True if the next memory unit has been allocated with the same call to malloc() bool isNextContiguousMemory; + /// True if the memory unit is currently allocated + bool isAllocated = false; + // -------------------- Methods -------------------- // - MemoryUnitHeader(size_t size, MemoryUnitHeader* previousUnit, MemoryUnitHeader* nextUnit, bool isNextContiguousMemory) - : size(size), isAllocated(false), previousUnit(previousUnit), - nextUnit(nextUnit), isNextContiguousMemory(isNextContiguousMemory) { + MemoryUnitHeader(size_t size, MemoryUnitHeader* previousUnit, MemoryUnitHeader* nextUnit, + MemoryUnitHeader* previousFreeUnit, MemoryUnitHeader* nextFreeUnit, bool isNextContiguousMemory) + : previousUnit(previousUnit), nextUnit(nextUnit), previousFreeUnit(previousFreeUnit), nextFreeUnit(nextFreeUnit), size(size), + isNextContiguousMemory(isNextContiguousMemory) { assert(size > 0); } @@ -101,8 +108,8 @@ class HeapAllocator : public MemoryAllocator { /// Pointer to the first memory unit of the linked-list MemoryUnitHeader* mMemoryUnits; - /// Pointer to a cached free memory unit - MemoryUnitHeader* mCachedFreeUnit; + /// Pointer to the first item of the linked-list of free units + MemoryUnitHeader* mFreeUnits; #ifndef NDEBUG /// This variable is incremented by one when the allocate() method has been @@ -118,12 +125,21 @@ class HeapAllocator : public MemoryAllocator { /// left over space. The second unit is put into the free memory units void splitMemoryUnit(MemoryUnitHeader* unit, size_t size); - // Merge two contiguous memory units that are not allocated. + /// Add the unit from the linked-list of free units + void addToFreeUnits(MemoryUnitHeader* unit); + + /// Remove the unit from the linked-list of free units + void removeFromFreeUnits(MemoryUnitHeader* unit); + + /// Merge two contiguous memory units that are not allocated. void mergeUnits(MemoryUnitHeader* unit1, MemoryUnitHeader* unit2); /// Reserve more memory for the allocator void reserve(size_t sizeToAllocate); + /// Return the next aligned memory address + void* computeAlignedAddress(void* unalignedAddress); + public : // -------------------- Methods -------------------- // diff --git a/include/reactphysics3d/memory/SingleFrameAllocator.h b/include/reactphysics3d/memory/SingleFrameAllocator.h index c3b006a5..b93f9c9a 100644 --- a/include/reactphysics3d/memory/SingleFrameAllocator.h +++ b/include/reactphysics3d/memory/SingleFrameAllocator.h @@ -65,6 +65,9 @@ class SingleFrameAllocator : public MemoryAllocator { /// Pointer to the next available memory location in the buffer size_t mCurrentOffset; + /// True if we need to allocate more memory in the next reset() call + bool mNeedToAllocatedMore; + public : // -------------------- Methods -------------------- // diff --git a/src/memory/HeapAllocator.cpp b/src/memory/HeapAllocator.cpp index 9dc92682..a7183ca9 100644 --- a/src/memory/HeapAllocator.cpp +++ b/src/memory/HeapAllocator.cpp @@ -36,7 +36,7 @@ size_t HeapAllocator::INIT_ALLOCATED_SIZE = 5 * 1048576; // 5 Mb // Constructor HeapAllocator::HeapAllocator(MemoryAllocator& baseAllocator, size_t initAllocatedMemory) - : mBaseAllocator(baseAllocator), mAllocatedMemory(0), mMemoryUnits(nullptr), mCachedFreeUnit(nullptr) { + : mBaseAllocator(baseAllocator), mAllocatedMemory(0), mMemoryUnits(nullptr), mFreeUnits(nullptr) { #ifndef NDEBUG mNbTimesAllocateMethodCalled = 0; @@ -55,12 +55,12 @@ HeapAllocator::~HeapAllocator() { #endif // Release the memory allocated for memory unit - MemoryUnitHeader* unit = mMemoryUnits; + MemoryUnitHeader* unit = mFreeUnits; while (unit != nullptr) { assert(!unit->isAllocated); - MemoryUnitHeader* nextUnit = unit->nextUnit; + MemoryUnitHeader* nextUnit = unit->nextFreeUnit; const size_t unitSize = unit->size; @@ -76,23 +76,24 @@ HeapAllocator::~HeapAllocator() { /// left over space. The second unit is put into the free memory units void HeapAllocator::splitMemoryUnit(MemoryUnitHeader* unit, size_t size) { - assert(size <= unit->size); assert(!unit->isAllocated); - // Split the free memory unit in two memory units, one with the requested memory size - // and a second one with the left over space + // If the size of the unit is large enough to be slit if (size + sizeof(MemoryUnitHeader) < unit->size) { - assert(unit->size - size > 0); - // Create a new memory unit with left over space unsigned char* newUnitLocation = (reinterpret_cast(unit)) + sizeof(MemoryUnitHeader) + size; - MemoryUnitHeader* newUnit = new (static_cast(newUnitLocation)) MemoryUnitHeader(unit->size - sizeof(MemoryUnitHeader) - size, unit, unit->nextUnit, unit->isNextContiguousMemory); + MemoryUnitHeader* newUnit = new (static_cast(newUnitLocation)) MemoryUnitHeader(unit->size - sizeof(MemoryUnitHeader) - size, unit, unit->nextUnit, unit, unit->nextFreeUnit, unit->isNextContiguousMemory); assert(newUnit->nextUnit != newUnit); unit->nextUnit = newUnit; + unit->nextFreeUnit = newUnit; if (newUnit->nextUnit != nullptr) { newUnit->nextUnit->previousUnit = newUnit; } + if (newUnit->nextFreeUnit != nullptr) { + newUnit->nextFreeUnit->previousFreeUnit = newUnit; + } + assert(unit->nextUnit != unit); unit->isNextContiguousMemory = true; unit->size = size; @@ -100,9 +101,19 @@ void HeapAllocator::splitMemoryUnit(MemoryUnitHeader* unit, size_t size) { assert(unit->previousUnit == nullptr || unit->previousUnit->nextUnit == unit); assert(unit->nextUnit == nullptr || unit->nextUnit->previousUnit == unit); + assert(unit->previousFreeUnit == nullptr || unit->previousFreeUnit->nextFreeUnit == unit); + assert(unit->nextFreeUnit == nullptr || unit->nextFreeUnit->previousFreeUnit == unit); + assert(newUnit->previousUnit == nullptr || newUnit->previousUnit->nextUnit == newUnit); assert(newUnit->nextUnit == nullptr || newUnit->nextUnit->previousUnit == newUnit); - } + + assert(newUnit->previousFreeUnit->nextFreeUnit == newUnit); + assert(newUnit->nextFreeUnit == nullptr || newUnit->nextFreeUnit->previousFreeUnit == newUnit); + + assert(unit->nextFreeUnit == newUnit); + assert(newUnit->previousFreeUnit == unit); + assert(!newUnit->isAllocated); + } } // Allocate memory of a given size (in bytes) and return a pointer to the @@ -117,72 +128,92 @@ void* HeapAllocator::allocate(size_t size) { // We cannot allocate zero bytes if (size == 0) return nullptr; + // Allocate a little bit more memory to make sure we can return an aligned address + const size_t totalSize = size + GLOBAL_ALIGNMENT; + #ifndef NDEBUG mNbTimesAllocateMethodCalled++; #endif - MemoryUnitHeader* currentUnit = mMemoryUnits; - assert(mMemoryUnits->previousUnit == nullptr); + MemoryUnitHeader* currentUnit = mFreeUnits; - // If there is a cached free memory unit - if (mCachedFreeUnit != nullptr) { - assert(!mCachedFreeUnit->isAllocated); - - // If the cached free memory unit matches the request - if (size <= mCachedFreeUnit->size) { - currentUnit = mCachedFreeUnit; - mCachedFreeUnit = nullptr; - } - } - - // For each memory unit + // For each free memory unit while (currentUnit != nullptr) { - // If we have found a free memory unit with size large enough for the allocation request - if (!currentUnit->isAllocated && size <= currentUnit->size) { + assert(!currentUnit->isAllocated); - // Split the free memory unit in two memory units, one with the requested memory size - // and a second one with the left over space - splitMemoryUnit(currentUnit, size); + // If we have found a free memory unit with size large enough for the allocation request + if (totalSize <= currentUnit->size) { break; } - currentUnit = currentUnit->nextUnit; + assert(currentUnit->nextFreeUnit == nullptr || currentUnit->nextFreeUnit->previousFreeUnit == currentUnit); + + currentUnit = currentUnit->nextFreeUnit; } - // If we have not found a large enough memory unit we need to allocate more memory + // If we have not found a large enough free memory unit if (currentUnit == nullptr) { - reserve((mAllocatedMemory + size) * 2); + // We need to allocate more memory + reserve((mAllocatedMemory + totalSize) * 2); - assert(mCachedFreeUnit != nullptr); - assert(!mCachedFreeUnit->isAllocated); + assert(mFreeUnits != nullptr); // The cached free memory unit is large enough at this point - currentUnit = mCachedFreeUnit; - - assert(currentUnit->size >= size); - - splitMemoryUnit(currentUnit, size); + currentUnit = mFreeUnits; } + // Split the free memory unit in two memory units, one with the requested memory size + // and a second one with the left over space + splitMemoryUnit(currentUnit, totalSize); + + assert(currentUnit->size >= totalSize); + assert(!currentUnit->isAllocated); + currentUnit->isAllocated = true; - // Cache the next memory unit if it is not allocated - if (currentUnit->nextUnit != nullptr && !currentUnit->nextUnit->isAllocated) { - mCachedFreeUnit = currentUnit->nextUnit; - } + removeFromFreeUnits(currentUnit); // Return a pointer to the memory area inside the unit void* allocatedMemory = static_cast(reinterpret_cast(currentUnit) + sizeof(MemoryUnitHeader)); + // Offset the allocated address such that it is properly aligned + allocatedMemory = computeAlignedAddress(allocatedMemory); + // Check that allocated memory is 16-bytes aligned assert(reinterpret_cast(allocatedMemory) % GLOBAL_ALIGNMENT == 0); return allocatedMemory; } +// Return the next aligned memory address +void* HeapAllocator::computeAlignedAddress(void* unalignedAddress) { + + // Take care of alignment to make sure that we always return an address to the + // enforce the global alignment of the library + + const uintptr_t currentAdress = reinterpret_cast(unalignedAddress); + + // Calculate the adjustment by masking off the lower bits of the address, to determine how "misaligned" it is. + size_t mask = GLOBAL_ALIGNMENT - 1; + uintptr_t misalignment = currentAdress & mask; + ptrdiff_t alignmentOffset = GLOBAL_ALIGNMENT - misalignment; + + // Compute the aligned address + uintptr_t alignedAddress = currentAdress + alignmentOffset; + + // Store the adjustment in the byte immediately preceding the adjusted address. + // This way we can find again the original allocated memory address returned by malloc + // when this memory unit is released. + assert(alignmentOffset < 256); + uint8* pAlignedMemory = reinterpret_cast(alignedAddress); + pAlignedMemory[-1] = static_cast(alignmentOffset); + + return reinterpret_cast(alignedAddress); +} + // Release previously allocated memory. void HeapAllocator::release(void* pointer, size_t size) { @@ -198,9 +229,19 @@ void HeapAllocator::release(void* pointer, size_t size) { mNbTimesAllocateMethodCalled--; #endif - unsigned char* unitLocation = static_cast(pointer) - sizeof(MemoryUnitHeader); + // Read the alignment offset in order to compute the initial allocated + // raw address (instead of the aligned address) + const uint8* pAlignedMemory = reinterpret_cast(pointer); + const uintptr_t alignedAddress = reinterpret_cast(pAlignedMemory); + const ptrdiff_t alignmentOffset = static_cast(pAlignedMemory[-1]); + const uintptr_t initialAddress = alignedAddress - alignmentOffset; + void* pInitialAddress = reinterpret_cast(initialAddress); + + unsigned char* unitLocation = static_cast(pInitialAddress) - sizeof(MemoryUnitHeader); MemoryUnitHeader* unit = reinterpret_cast(unitLocation); assert(unit->isAllocated); + assert(unit->nextFreeUnit == nullptr); + assert(unit->previousFreeUnit == nullptr); unit->isAllocated = false; MemoryUnitHeader* currentUnit = unit; @@ -208,6 +249,8 @@ void HeapAllocator::release(void* pointer, size_t size) { // If the previous unit is not allocated and memory is contiguous to the current unit if (unit->previousUnit != nullptr && !unit->previousUnit->isAllocated && unit->previousUnit->isNextContiguousMemory) { + removeFromFreeUnits(unit->previousUnit); + currentUnit = unit->previousUnit; // Merge the two contiguous memory units @@ -217,11 +260,40 @@ void HeapAllocator::release(void* pointer, size_t size) { // If the next unit is not allocated and memory is contiguous to the current unit if (currentUnit->nextUnit != nullptr && !currentUnit->nextUnit->isAllocated && currentUnit->isNextContiguousMemory) { + removeFromFreeUnits(unit->nextUnit); + // Merge the two contiguous memory units mergeUnits(currentUnit, currentUnit->nextUnit); } - mCachedFreeUnit = currentUnit; + addToFreeUnits(currentUnit); +} + +// Add the unit from the linked-list of free units +void HeapAllocator::addToFreeUnits(MemoryUnitHeader* unit) { + + if (mFreeUnits != nullptr) { + assert(mFreeUnits->previousFreeUnit == nullptr); + mFreeUnits->previousFreeUnit = unit; + } + unit->nextFreeUnit = mFreeUnits; + mFreeUnits = unit; +} + +// Remove the unit from the linked-list of free units +void HeapAllocator::removeFromFreeUnits(MemoryUnitHeader* unit) { + + if (unit->previousFreeUnit != nullptr) { + unit->previousFreeUnit->nextFreeUnit = unit->nextFreeUnit; + } + if (unit->nextFreeUnit != nullptr) { + unit->nextFreeUnit->previousFreeUnit = unit->previousFreeUnit; + } + if (unit == mFreeUnits) { + mFreeUnits = unit->nextFreeUnit; + } + unit->nextFreeUnit = nullptr; + unit->previousFreeUnit = nullptr; } // Merge two contiguous memory units that are not allocated. @@ -260,7 +332,13 @@ void HeapAllocator::reserve(size_t sizeToAllocate) { assert(reinterpret_cast(memory) % GLOBAL_ALIGNMENT == 0); // Create a new memory unit for the allocated memory - MemoryUnitHeader* memoryUnit = new (memory) MemoryUnitHeader(sizeToAllocate, nullptr, mMemoryUnits, false); + MemoryUnitHeader* memoryUnit = new (memory) MemoryUnitHeader(sizeToAllocate, nullptr, mMemoryUnits, nullptr, mFreeUnits, false); + + if (mFreeUnits != nullptr) { + + assert(mFreeUnits->previousFreeUnit == nullptr); + mFreeUnits->previousFreeUnit = memoryUnit; + } if (mMemoryUnits != nullptr) { mMemoryUnits->previousUnit = memoryUnit; @@ -268,8 +346,7 @@ void HeapAllocator::reserve(size_t sizeToAllocate) { // Add the memory unit at the beginning of the linked-list of memory units mMemoryUnits = memoryUnit; - - mCachedFreeUnit = mMemoryUnits; + mFreeUnits = mMemoryUnits; mAllocatedMemory += sizeToAllocate; } diff --git a/src/memory/SingleFrameAllocator.cpp b/src/memory/SingleFrameAllocator.cpp index 6a87ee42..eb0eb1c8 100644 --- a/src/memory/SingleFrameAllocator.cpp +++ b/src/memory/SingleFrameAllocator.cpp @@ -34,11 +34,17 @@ using namespace reactphysics3d; // Constructor SingleFrameAllocator::SingleFrameAllocator(MemoryAllocator& baseAllocator) : mBaseAllocator(baseAllocator), mTotalSizeBytes(INIT_SINGLE_FRAME_ALLOCATOR_NB_BYTES), - mCurrentOffset(0) { + mCurrentOffset(0), mNeedToAllocatedMore(false) { // Allocate a whole block of memory at the beginning - mMemoryBufferStart = static_cast(mBaseAllocator.allocate(mTotalSizeBytes)); - assert(mMemoryBufferStart != nullptr); + void* allocatedMemory = mBaseAllocator.allocate(mTotalSizeBytes); + + assert(allocatedMemory != nullptr); + + // Check that allocated memory is 16-bytes aligned + assert(reinterpret_cast(allocatedMemory) % GLOBAL_ALIGNMENT == 0); + + mMemoryBufferStart = static_cast(allocatedMemory); } // Destructor @@ -61,27 +67,11 @@ void* SingleFrameAllocator::allocate(size_t size) { // Check that there is enough remaining memory in the buffer if (mCurrentOffset + totalSize > mTotalSizeBytes) { - const size_t previousTotalSizeBytes = mTotalSizeBytes; + // We need to allocate more memory next time reset() is called + mNeedToAllocatedMore = true; - // Multiply the total memory to allocate by two - mTotalSizeBytes *= 2; - - // Allocate a whole block of memory - void* allocatedMemory = mBaseAllocator.allocate(mTotalSizeBytes); - assert(allocatedMemory != nullptr); - - // Check that allocated memory is 16-bytes aligned - assert(reinterpret_cast(allocatedMemory) % GLOBAL_ALIGNMENT == 0); - - char* newMemoryBufferStart = static_cast(allocatedMemory); - - // Copy the previous memory bloc to new new location - memcpy(newMemoryBufferStart, mMemoryBufferStart, previousTotalSizeBytes); - - // Release the memory allocated at the beginning - mBaseAllocator.release(mMemoryBufferStart, previousTotalSizeBytes); - - mMemoryBufferStart = newMemoryBufferStart; + // Return default memory allocation + return mBaseAllocator.allocate(size); } // Next available memory location @@ -92,12 +82,13 @@ void* SingleFrameAllocator::allocate(size_t size) { uintptr_t currentAdress = reinterpret_cast(nextAvailableMemory); // Calculate the adjustment by masking off the lower bits of the address, to determine how "misaligned" it is. - size_t mask = GLOBAL_ALIGNMENT - 1; - uintptr_t misalignment = currentAdress & mask; - ptrdiff_t alignmentOffset = GLOBAL_ALIGNMENT - misalignment; + const size_t mask = GLOBAL_ALIGNMENT - 1; + const uintptr_t misalignment = currentAdress & mask; + const ptrdiff_t alignmentOffset = GLOBAL_ALIGNMENT - misalignment; + assert(alignmentOffset <= GLOBAL_ALIGNMENT); // Compute the aligned address - uintptr_t alignedAdress = currentAdress + alignmentOffset; + const uintptr_t alignedAdress = currentAdress + alignmentOffset; nextAvailableMemory = reinterpret_cast(alignedAdress); // Increment the offset @@ -111,8 +102,18 @@ void* SingleFrameAllocator::allocate(size_t size) { } // Release previously allocated memory. -void SingleFrameAllocator::release(void* /*pointer*/, size_t /*size*/) { +void SingleFrameAllocator::release(void* pointer, size_t size) { + // Lock the method with a mutex + std::lock_guard lock(mMutex); + + // If allocated memory is not within the single frame allocation range + char* p = static_cast(pointer); + if (p < mMemoryBufferStart || p > mMemoryBufferStart + mTotalSizeBytes) { + + // Use default deallocation + mBaseAllocator.release(pointer, size); + } } // Reset the marker of the current allocated memory @@ -121,6 +122,22 @@ void SingleFrameAllocator::reset() { // Lock the method with a mutex std::lock_guard lock(mMutex); + // If we need to allocate more memory + if (mNeedToAllocatedMore) { + + // Release the memory allocated at the beginning + mBaseAllocator.release(mMemoryBufferStart, mTotalSizeBytes); + + // Multiply the total memory to allocate by two + mTotalSizeBytes *= 2; + + // Allocate a whole block of memory at the beginning + mMemoryBufferStart = static_cast(mBaseAllocator.allocate(mTotalSizeBytes)); + assert(mMemoryBufferStart != nullptr); + + mNeedToAllocatedMore = false; + } + // Reset the current offset at the beginning of the block mCurrentOffset = 0; } From 75a64a65b848d04d00e9d176b3b320218f569829 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Fri, 25 Mar 2022 08:47:45 +0100 Subject: [PATCH 3/5] Working on memory allocators --- CMakeLists.txt | 1 + .../reactphysics3d/memory/DefaultAllocator.h | 4 +- .../reactphysics3d/memory/MemoryAllocator.h | 9 +++ src/components/TransformComponents.cpp | 4 +- src/memory/HeapAllocator.cpp | 16 ++--- src/memory/MemoryAllocator.cpp | 71 +++++++++++++++++++ src/memory/SingleFrameAllocator.cpp | 15 +--- 7 files changed, 94 insertions(+), 26 deletions(-) create mode 100644 src/memory/MemoryAllocator.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 6bb2eaac..c2629551 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -229,6 +229,7 @@ set (REACTPHYSICS3D_SOURCES "src/memory/SingleFrameAllocator.cpp" "src/memory/HeapAllocator.cpp" "src/memory/MemoryManager.cpp" + "src/memory/MemoryAllocator.cpp" "src/utils/Profiler.cpp" "src/utils/DefaultLogger.cpp" "src/utils/DebugRenderer.cpp" diff --git a/include/reactphysics3d/memory/DefaultAllocator.h b/include/reactphysics3d/memory/DefaultAllocator.h index d928741c..727b07b2 100644 --- a/include/reactphysics3d/memory/DefaultAllocator.h +++ b/include/reactphysics3d/memory/DefaultAllocator.h @@ -57,7 +57,7 @@ class DefaultAllocator : public MemoryAllocator { virtual void* allocate(size_t size) override { // If compiler is Visual Studio -#ifdef _MSC_VER +#ifdef RP3D_COMPILER_VISUAL_STUDIO // Visual Studio doesn't not support standard std:aligned_alloc() method from c++ 17 return _alligned_malloc(size, GLOBAL_ALIGNMENT); @@ -72,7 +72,7 @@ class DefaultAllocator : public MemoryAllocator { virtual void release(void* pointer, size_t /*size*/) override { // If compiler is Visual Studio -#ifdef _MSC_VER +#ifdef RP3D_COMPILER_VISUAL_STUDIO // Visual Studio doesn't not support standard std:aligned_alloc() method from c++ 17 return _aligned_free(GLOBAL_ALIGNMENT, pointer); diff --git a/include/reactphysics3d/memory/MemoryAllocator.h b/include/reactphysics3d/memory/MemoryAllocator.h index 0e732a44..e523af94 100644 --- a/include/reactphysics3d/memory/MemoryAllocator.h +++ b/include/reactphysics3d/memory/MemoryAllocator.h @@ -28,6 +28,7 @@ // Libraries #include +#include /// ReactPhysics3D namespace namespace reactphysics3d { @@ -55,6 +56,14 @@ class MemoryAllocator { /// Release previously allocated memory. virtual void release(void* pointer, size_t size)=0; + + /// Given a pointer to memory, this method returns the next aligned address + // TODO : We need to use uint8 type instead of uint8_t here + static void* alignAddress(void* pointer, std::uint8_t alignment); + + /// Given a pointer to memory, this method returns the next aligned address and also output the alignment offset + // TODO : We need to use uint8 type instead of uint8_t here + static void* alignAddress(void* pointer, std::uint8_t alignment, ptrdiff_t& alignmentOffset); }; } diff --git a/src/components/TransformComponents.cpp b/src/components/TransformComponents.cpp index 83245022..aa7d5a58 100644 --- a/src/components/TransformComponents.cpp +++ b/src/components/TransformComponents.cpp @@ -35,7 +35,7 @@ using namespace reactphysics3d; // Constructor TransformComponents::TransformComponents(MemoryAllocator& allocator) - :Components(allocator, sizeof(Entity) + sizeof(Transform)) { + :Components(allocator, sizeof(Entity) + sizeof(Transform) + 2 * GLOBAL_ALIGNMENT) { // Allocate memory for the components data allocate(INIT_NB_ALLOCATED_COMPONENTS); @@ -55,7 +55,9 @@ void TransformComponents::allocate(uint32 nbComponentsToAllocate) { // New pointers to components data Entity* newEntities = static_cast(newBuffer); + //assert(reinterpret_cast(newEntities) % GLOBAL_ALIGNMENT == 0); Transform* newTransforms = reinterpret_cast(newEntities + nbComponentsToAllocate); + //assert(reinterpret_cast(newTransforms) % GLOBAL_ALIGNMENT == 0); // If there was already components before if (mNbComponents > 0) { diff --git a/src/memory/HeapAllocator.cpp b/src/memory/HeapAllocator.cpp index a7183ca9..565cceef 100644 --- a/src/memory/HeapAllocator.cpp +++ b/src/memory/HeapAllocator.cpp @@ -194,24 +194,20 @@ void* HeapAllocator::computeAlignedAddress(void* unalignedAddress) { // Take care of alignment to make sure that we always return an address to the // enforce the global alignment of the library - const uintptr_t currentAdress = reinterpret_cast(unalignedAddress); - - // Calculate the adjustment by masking off the lower bits of the address, to determine how "misaligned" it is. - size_t mask = GLOBAL_ALIGNMENT - 1; - uintptr_t misalignment = currentAdress & mask; - ptrdiff_t alignmentOffset = GLOBAL_ALIGNMENT - misalignment; - // Compute the aligned address - uintptr_t alignedAddress = currentAdress + alignmentOffset; + ptrdiff_t alignmentOffset; + void* alignedPointer = alignAddress(unalignedAddress, GLOBAL_ALIGNMENT, alignmentOffset); + + uintptr_t alignedAddress = reinterpret_cast(alignedPointer); // Store the adjustment in the byte immediately preceding the adjusted address. // This way we can find again the original allocated memory address returned by malloc // when this memory unit is released. - assert(alignmentOffset < 256); + assert(alignmentOffset <= GLOBAL_ALIGNMENT); uint8* pAlignedMemory = reinterpret_cast(alignedAddress); pAlignedMemory[-1] = static_cast(alignmentOffset); - return reinterpret_cast(alignedAddress); + return alignedPointer; } // Release previously allocated memory. diff --git a/src/memory/MemoryAllocator.cpp b/src/memory/MemoryAllocator.cpp new file mode 100644 index 00000000..338c55ba --- /dev/null +++ b/src/memory/MemoryAllocator.cpp @@ -0,0 +1,71 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2022 Daniel Chappuis * +********************************************************************************* +* * +* This software is provided 'as-is', without any express or implied warranty. * +* In no event will the authors be held liable for any damages arising from the * +* use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute it * +* freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must not claim * +* that you wrote the original software. If you use this software in a * +* product, an acknowledgment in the product documentation would be * +* appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must not be * +* misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source distribution. * +* * +********************************************************************************/ + +// Libraries +#include +#include + +using namespace reactphysics3d; + +/// Given a pointer to memory, this method returns the next aligned address +/** +* @param pointer Pointer to a memory location +* @param alignment Desired alignment +* @return Pointer to the next aligned memory location +*/ +void* MemoryAllocator::alignAddress(void* pointer, std::uint8_t alignment) { + + ptrdiff_t alignmentOffset; + return alignAddress(pointer, alignment, alignmentOffset); +} + +/// Given a pointer to memory, this method returns the next aligned address and also output the alignment offset +/** +* @param pointer Pointer to a memory location +* @param alignment Desired alignment +* @param outAlignmentOffset Output alignment offset needed to align the initial pointer +* @return Pointer to the next aligned memory location +*/ +void* MemoryAllocator::alignAddress(void* pointer, std::uint8_t alignment, ptrdiff_t& outAlignmentOffset) { + + // Take care of alignment to make sure that we always return an address to the + // enforce the global alignment of the library + const uintptr_t currentAdress = reinterpret_cast(pointer); + + // Calculate the adjustment by masking off the lower bits of the address, to determine how "misaligned" it is. + const size_t mask = alignment - 1; + const uintptr_t misalignment = currentAdress & mask; + outAlignmentOffset = alignment - misalignment; + assert(outAlignmentOffset <= alignment); + + // Compute the aligned address + const uintptr_t alignedAdress = currentAdress + outAlignmentOffset; + void* alignedPointer = reinterpret_cast(alignedAdress); + + // Check that allocated memory is correctly aligned + assert(reinterpret_cast(alignedPointer) % alignment == 0); + + return alignedPointer; +} diff --git a/src/memory/SingleFrameAllocator.cpp b/src/memory/SingleFrameAllocator.cpp index eb0eb1c8..97193e4d 100644 --- a/src/memory/SingleFrameAllocator.cpp +++ b/src/memory/SingleFrameAllocator.cpp @@ -77,19 +77,8 @@ void* SingleFrameAllocator::allocate(size_t size) { // Next available memory location void* nextAvailableMemory = mMemoryBufferStart + mCurrentOffset; - // Take care of alignment to make sure that we always return an address to the - // enforce the global alignment of the library - uintptr_t currentAdress = reinterpret_cast(nextAvailableMemory); - - // Calculate the adjustment by masking off the lower bits of the address, to determine how "misaligned" it is. - const size_t mask = GLOBAL_ALIGNMENT - 1; - const uintptr_t misalignment = currentAdress & mask; - const ptrdiff_t alignmentOffset = GLOBAL_ALIGNMENT - misalignment; - assert(alignmentOffset <= GLOBAL_ALIGNMENT); - - // Compute the aligned address - const uintptr_t alignedAdress = currentAdress + alignmentOffset; - nextAvailableMemory = reinterpret_cast(alignedAdress); + // Compute the next aligned memory address + nextAvailableMemory = alignAddress(nextAvailableMemory, GLOBAL_ALIGNMENT); // Increment the offset mCurrentOffset += totalSize; From 0d1861029880e2273cd7a9cf9a54bba56e9a2018 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sun, 27 Mar 2022 13:26:45 +0200 Subject: [PATCH 4/5] Make sure the allocated memory for components is properly aligned --- .../reactphysics3d/components/Components.h | 8 +- .../BallAndSocketJointComponents.cpp | 61 ++++++--- src/components/ColliderComponents.cpp | 44 +++--- src/components/CollisionBodyComponents.cpp | 21 +-- src/components/Components.cpp | 11 +- src/components/FixedJointComponents.cpp | 50 ++++--- src/components/HingeJointComponents.cpp | 110 +++++++++------ src/components/JointComponents.cpp | 29 ++-- src/components/RigidBodyComponents.cpp | 98 +++++++++----- src/components/SliderJointComponents.cpp | 125 ++++++++++++------ src/components/TransformComponents.cpp | 16 ++- src/engine/PhysicsWorld.cpp | 10 ++ 12 files changed, 384 insertions(+), 199 deletions(-) diff --git a/include/reactphysics3d/components/Components.h b/include/reactphysics3d/components/Components.h index 17dfa001..80fc2e4a 100644 --- a/include/reactphysics3d/components/Components.h +++ b/include/reactphysics3d/components/Components.h @@ -63,6 +63,9 @@ class Components { /// Size (in bytes) of a single component size_t mComponentDataSize; + /// Size (in bytes) to allocate to make sure we can offset the components array to keep alignment + size_t mAlignmentMarginSize; + /// Number of allocated components uint32 mNbAllocatedComponents; @@ -96,11 +99,14 @@ class Components { // -------------------- Methods -------------------- // /// Constructor - Components(MemoryAllocator& allocator, size_t componentDataSize); + Components(MemoryAllocator& allocator, size_t componentDataSize, size_t alignmentMarginSize); /// Destructor virtual ~Components(); + /// Initialize the components: + void init(); + /// Remove a component void removeComponent(Entity entity); diff --git a/src/components/BallAndSocketJointComponents.cpp b/src/components/BallAndSocketJointComponents.cpp index 6f843e78..4a429bb7 100644 --- a/src/components/BallAndSocketJointComponents.cpp +++ b/src/components/BallAndSocketJointComponents.cpp @@ -38,10 +38,9 @@ BallAndSocketJointComponents::BallAndSocketJointComponents(MemoryAllocator& allo sizeof(Vector3) + sizeof(Vector3) + sizeof(Vector3) + sizeof(Matrix3x3) + sizeof(Matrix3x3) + sizeof(Vector3) + sizeof(Matrix3x3) + sizeof(Vector3) + sizeof(bool) + sizeof(decimal) + - sizeof(decimal) + sizeof(decimal) + sizeof(decimal) + sizeof(bool) + sizeof(Vector3)) { + sizeof(decimal) + sizeof(decimal) + sizeof(decimal) + sizeof(bool) + sizeof(Vector3), + 18 * GLOBAL_ALIGNMENT) { - // Allocate memory for the components data - allocate(INIT_NB_ALLOCATED_COMPONENTS); } // Allocate memory for a given number of components @@ -50,31 +49,51 @@ void BallAndSocketJointComponents::allocate(uint32 nbComponentsToAllocate) { assert(nbComponentsToAllocate > mNbAllocatedComponents); // Size for the data of a single component (in bytes) - const size_t totalSizeBytes = nbComponentsToAllocate * mComponentDataSize; + const size_t totalSizeBytes = nbComponentsToAllocate * mComponentDataSize + mAlignmentMarginSize; // Allocate memory void* newBuffer = mMemoryAllocator.allocate(totalSizeBytes); assert(newBuffer != nullptr); + assert(reinterpret_cast(newBuffer) % GLOBAL_ALIGNMENT == 0); // New pointers to components data Entity* newJointEntities = static_cast(newBuffer); - BallAndSocketJoint** newJoints = reinterpret_cast(newJointEntities + nbComponentsToAllocate); - Vector3* newLocalAnchorPointBody1 = reinterpret_cast(newJoints + nbComponentsToAllocate); - Vector3* newLocalAnchorPointBody2 = reinterpret_cast(newLocalAnchorPointBody1 + nbComponentsToAllocate); - Vector3* newR1World = reinterpret_cast(newLocalAnchorPointBody2 + nbComponentsToAllocate); - Vector3* newR2World = reinterpret_cast(newR1World + nbComponentsToAllocate); - Matrix3x3* newI1 = reinterpret_cast(newR2World + nbComponentsToAllocate); - Matrix3x3* newI2 = reinterpret_cast(newI1 + nbComponentsToAllocate); - Vector3* newBiasVector = reinterpret_cast(newI2 + nbComponentsToAllocate); - Matrix3x3* newInverseMassMatrix = reinterpret_cast(newBiasVector + nbComponentsToAllocate); - Vector3* newImpulse = reinterpret_cast(newInverseMassMatrix + nbComponentsToAllocate); - bool* newIsConeLimitEnabled = reinterpret_cast(newImpulse + nbComponentsToAllocate); - decimal* newConeLimitImpulse = reinterpret_cast(newIsConeLimitEnabled + nbComponentsToAllocate); - decimal* newConeLimitHalfAngle = reinterpret_cast(newConeLimitImpulse + nbComponentsToAllocate); - decimal* newInverseMassMatrixConeLimit = reinterpret_cast(newConeLimitHalfAngle + nbComponentsToAllocate); - decimal* newBConeLimit = reinterpret_cast(newInverseMassMatrixConeLimit + nbComponentsToAllocate); - bool* newIsConeLimitViolated = reinterpret_cast(newBConeLimit + nbComponentsToAllocate); - Vector3* newConeLimitACrossB = reinterpret_cast(newIsConeLimitViolated + nbComponentsToAllocate); + assert(reinterpret_cast(newJointEntities) % GLOBAL_ALIGNMENT == 0); + BallAndSocketJoint** newJoints = reinterpret_cast(MemoryAllocator::alignAddress(newJointEntities + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newJoints) % GLOBAL_ALIGNMENT == 0); + Vector3* newLocalAnchorPointBody1 = reinterpret_cast(MemoryAllocator::alignAddress(newJoints + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newLocalAnchorPointBody1) % GLOBAL_ALIGNMENT == 0); + Vector3* newLocalAnchorPointBody2 = reinterpret_cast(MemoryAllocator::alignAddress(newLocalAnchorPointBody1 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newLocalAnchorPointBody2) % GLOBAL_ALIGNMENT == 0); + Vector3* newR1World = reinterpret_cast(MemoryAllocator::alignAddress(newLocalAnchorPointBody2 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newR1World) % GLOBAL_ALIGNMENT == 0); + Vector3* newR2World = reinterpret_cast(MemoryAllocator::alignAddress(newR1World + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newR2World) % GLOBAL_ALIGNMENT == 0); + Matrix3x3* newI1 = reinterpret_cast(MemoryAllocator::alignAddress(newR2World + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newI1) % GLOBAL_ALIGNMENT == 0); + Matrix3x3* newI2 = reinterpret_cast(MemoryAllocator::alignAddress(newI1 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newI2) % GLOBAL_ALIGNMENT == 0); + Vector3* newBiasVector = reinterpret_cast(MemoryAllocator::alignAddress(newI2 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newBiasVector) % GLOBAL_ALIGNMENT == 0); + Matrix3x3* newInverseMassMatrix = reinterpret_cast(MemoryAllocator::alignAddress(newBiasVector + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newInverseMassMatrix) % GLOBAL_ALIGNMENT == 0); + Vector3* newImpulse = reinterpret_cast(MemoryAllocator::alignAddress(newInverseMassMatrix + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newImpulse) % GLOBAL_ALIGNMENT == 0); + bool* newIsConeLimitEnabled = reinterpret_cast(MemoryAllocator::alignAddress(newImpulse + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newIsConeLimitEnabled) % GLOBAL_ALIGNMENT == 0); + decimal* newConeLimitImpulse = reinterpret_cast(MemoryAllocator::alignAddress(newIsConeLimitEnabled + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newConeLimitImpulse) % GLOBAL_ALIGNMENT == 0); + decimal* newConeLimitHalfAngle = reinterpret_cast(MemoryAllocator::alignAddress(newConeLimitImpulse + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newConeLimitHalfAngle) % GLOBAL_ALIGNMENT == 0); + decimal* newInverseMassMatrixConeLimit = reinterpret_cast(MemoryAllocator::alignAddress(newConeLimitHalfAngle + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newInverseMassMatrixConeLimit) % GLOBAL_ALIGNMENT == 0); + decimal* newBConeLimit = reinterpret_cast(MemoryAllocator::alignAddress(newInverseMassMatrixConeLimit + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newBConeLimit) % GLOBAL_ALIGNMENT == 0); + bool* newIsConeLimitViolated = reinterpret_cast(MemoryAllocator::alignAddress(newBConeLimit + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newIsConeLimitViolated) % GLOBAL_ALIGNMENT == 0); + Vector3* newConeLimitACrossB = reinterpret_cast(MemoryAllocator::alignAddress(newIsConeLimitViolated + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newConeLimitACrossB) % GLOBAL_ALIGNMENT == 0); + assert(reinterpret_cast(newConeLimitACrossB + nbComponentsToAllocate) <= reinterpret_cast(newBuffer) + totalSizeBytes); // If there was already components before if (mNbComponents > 0) { diff --git a/src/components/ColliderComponents.cpp b/src/components/ColliderComponents.cpp index 51e1b8dc..dbc16e64 100644 --- a/src/components/ColliderComponents.cpp +++ b/src/components/ColliderComponents.cpp @@ -38,10 +38,8 @@ ColliderComponents::ColliderComponents(MemoryAllocator& allocator) :Components(allocator, sizeof(Entity) + sizeof(Entity) + sizeof(Collider*) + sizeof(int32) + sizeof(Transform) + sizeof(CollisionShape*) + sizeof(unsigned short) + sizeof(unsigned short) + sizeof(Transform) + sizeof(Array) + sizeof(bool) + - sizeof(bool) + sizeof(Material)) { + sizeof(bool) + sizeof(Material), 13 * GLOBAL_ALIGNMENT) { - // Allocate memory for the components data - allocate(INIT_NB_ALLOCATED_COMPONENTS); } // Allocate memory for a given number of components @@ -50,26 +48,40 @@ void ColliderComponents::allocate(uint32 nbComponentsToAllocate) { assert(nbComponentsToAllocate > mNbAllocatedComponents); // Size for the data of a single component (in bytes) - const size_t totalSizeBytes = nbComponentsToAllocate * mComponentDataSize; + const size_t totalSizeBytes = nbComponentsToAllocate * mComponentDataSize + mAlignmentMarginSize; // Allocate memory void* newBuffer = mMemoryAllocator.allocate(totalSizeBytes); assert(newBuffer != nullptr); + assert(reinterpret_cast(newBuffer) % GLOBAL_ALIGNMENT == 0); // New pointers to components data Entity* newCollidersEntities = static_cast(newBuffer); - Entity* newBodiesEntities = reinterpret_cast(newCollidersEntities + nbComponentsToAllocate); - Collider** newColliders = reinterpret_cast(newBodiesEntities + nbComponentsToAllocate); - int32* newBroadPhaseIds = reinterpret_cast(newColliders + nbComponentsToAllocate); - Transform* newLocalToBodyTransforms = reinterpret_cast(newBroadPhaseIds + nbComponentsToAllocate); - CollisionShape** newCollisionShapes = reinterpret_cast(newLocalToBodyTransforms + nbComponentsToAllocate); - unsigned short* newCollisionCategoryBits = reinterpret_cast(newCollisionShapes + nbComponentsToAllocate); - unsigned short* newCollideWithMaskBits = reinterpret_cast(newCollisionCategoryBits + nbComponentsToAllocate); - Transform* newLocalToWorldTransforms = reinterpret_cast(newCollideWithMaskBits + nbComponentsToAllocate); - Array* newOverlappingPairs = reinterpret_cast*>(newLocalToWorldTransforms + nbComponentsToAllocate); - bool* hasCollisionShapeChangedSize = reinterpret_cast(newOverlappingPairs + nbComponentsToAllocate); - bool* isTrigger = reinterpret_cast(hasCollisionShapeChangedSize + nbComponentsToAllocate); - Material* materials = reinterpret_cast(isTrigger + nbComponentsToAllocate); + Entity* newBodiesEntities = reinterpret_cast(MemoryAllocator::alignAddress(newCollidersEntities + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newBodiesEntities) % GLOBAL_ALIGNMENT == 0); + Collider** newColliders = reinterpret_cast(MemoryAllocator::alignAddress(newBodiesEntities + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newColliders) % GLOBAL_ALIGNMENT == 0); + int32* newBroadPhaseIds = reinterpret_cast(MemoryAllocator::alignAddress(newColliders + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newBroadPhaseIds) % GLOBAL_ALIGNMENT == 0); + Transform* newLocalToBodyTransforms = reinterpret_cast(MemoryAllocator::alignAddress(newBroadPhaseIds + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newLocalToBodyTransforms) % GLOBAL_ALIGNMENT == 0); + CollisionShape** newCollisionShapes = reinterpret_cast(MemoryAllocator::alignAddress(newLocalToBodyTransforms + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newCollisionShapes) % GLOBAL_ALIGNMENT == 0); + unsigned short* newCollisionCategoryBits = reinterpret_cast(MemoryAllocator::alignAddress(newCollisionShapes + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newCollisionCategoryBits) % GLOBAL_ALIGNMENT == 0); + unsigned short* newCollideWithMaskBits = reinterpret_cast(MemoryAllocator::alignAddress(newCollisionCategoryBits + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newCollideWithMaskBits) % GLOBAL_ALIGNMENT == 0); + Transform* newLocalToWorldTransforms = reinterpret_cast(MemoryAllocator::alignAddress(newCollideWithMaskBits + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newLocalToWorldTransforms) % GLOBAL_ALIGNMENT == 0); + Array* newOverlappingPairs = reinterpret_cast*>(MemoryAllocator::alignAddress(newLocalToWorldTransforms + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newOverlappingPairs) % GLOBAL_ALIGNMENT == 0); + bool* hasCollisionShapeChangedSize = reinterpret_cast(MemoryAllocator::alignAddress(newOverlappingPairs + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(hasCollisionShapeChangedSize) % GLOBAL_ALIGNMENT == 0); + bool* isTrigger = reinterpret_cast(MemoryAllocator::alignAddress(hasCollisionShapeChangedSize + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(isTrigger) % GLOBAL_ALIGNMENT == 0); + Material* materials = reinterpret_cast(MemoryAllocator::alignAddress(isTrigger + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(materials) % GLOBAL_ALIGNMENT == 0); + assert(reinterpret_cast(materials + nbComponentsToAllocate) <= reinterpret_cast(newBuffer) + totalSizeBytes); // If there was already components before if (mNbComponents > 0) { diff --git a/src/components/CollisionBodyComponents.cpp b/src/components/CollisionBodyComponents.cpp index 9606cfaa..0c4cd567 100644 --- a/src/components/CollisionBodyComponents.cpp +++ b/src/components/CollisionBodyComponents.cpp @@ -35,10 +35,8 @@ using namespace reactphysics3d; // Constructor CollisionBodyComponents::CollisionBodyComponents(MemoryAllocator& allocator) :Components(allocator, sizeof(Entity) + sizeof(CollisionBody*) + sizeof(Array) + - sizeof(bool) + sizeof(void*)) { + sizeof(bool) + sizeof(void*), 5 * GLOBAL_ALIGNMENT) { - // Allocate memory for the components data - allocate(INIT_NB_ALLOCATED_COMPONENTS); } // Allocate memory for a given number of components @@ -47,18 +45,25 @@ void CollisionBodyComponents::allocate(uint32 nbComponentsToAllocate) { assert(nbComponentsToAllocate > mNbAllocatedComponents); // Size for the data of a single component (in bytes) - const size_t totalSizeBytes = nbComponentsToAllocate * mComponentDataSize; + const size_t totalSizeBytes = nbComponentsToAllocate * mComponentDataSize + mAlignmentMarginSize; // Allocate memory void* newBuffer = mMemoryAllocator.allocate(totalSizeBytes); assert(newBuffer != nullptr); + assert(reinterpret_cast(newBuffer) % GLOBAL_ALIGNMENT == 0); // New pointers to components data Entity* newBodiesEntities = static_cast(newBuffer); - CollisionBody** newBodies = reinterpret_cast(newBodiesEntities + nbComponentsToAllocate); - Array* newColliders = reinterpret_cast*>(newBodies + nbComponentsToAllocate); - bool* newIsActive = reinterpret_cast(newColliders + nbComponentsToAllocate); - void** newUserData = reinterpret_cast(newIsActive + nbComponentsToAllocate); + assert(reinterpret_cast(newBodiesEntities) % GLOBAL_ALIGNMENT == 0); + CollisionBody** newBodies = reinterpret_cast(MemoryAllocator::alignAddress(newBodiesEntities + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newBodies) % GLOBAL_ALIGNMENT == 0); + Array* newColliders = reinterpret_cast*>(MemoryAllocator::alignAddress(newBodies + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newColliders) % GLOBAL_ALIGNMENT == 0); + bool* newIsActive = reinterpret_cast(MemoryAllocator::alignAddress(newColliders + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newIsActive) % GLOBAL_ALIGNMENT == 0); + void** newUserData = reinterpret_cast(MemoryAllocator::alignAddress(newIsActive + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newUserData) % GLOBAL_ALIGNMENT == 0); + assert(reinterpret_cast(newUserData + nbComponentsToAllocate) <= reinterpret_cast(newBuffer) + totalSizeBytes); // If there was already components before if (mNbComponents > 0) { diff --git a/src/components/Components.cpp b/src/components/Components.cpp index f09d4fe2..0b5de9c1 100644 --- a/src/components/Components.cpp +++ b/src/components/Components.cpp @@ -31,9 +31,9 @@ using namespace reactphysics3d; // Constructor -Components::Components(MemoryAllocator& allocator, size_t componentDataSize) +Components::Components(MemoryAllocator& allocator, size_t componentDataSize, size_t alignmentMarginSize) : mMemoryAllocator(allocator), mNbComponents(0), mComponentDataSize(componentDataSize), - mNbAllocatedComponents(0), mBuffer(nullptr), mMapEntityToComponentIndex(allocator), + mAlignmentMarginSize(alignmentMarginSize), mNbAllocatedComponents(0), mBuffer(nullptr), mMapEntityToComponentIndex(allocator), mDisabledStartIndex(0) { } @@ -57,6 +57,13 @@ Components::~Components() { } } +// Initialize the components: +void Components::init() { + + // Allocate memory for the components data + allocate(INIT_NB_ALLOCATED_COMPONENTS); +} + // Compute the index where we need to insert the new component uint32 Components::prepareAddComponent(bool isSleeping) { diff --git a/src/components/FixedJointComponents.cpp b/src/components/FixedJointComponents.cpp index 0794c058..96ff3c4f 100644 --- a/src/components/FixedJointComponents.cpp +++ b/src/components/FixedJointComponents.cpp @@ -38,10 +38,8 @@ FixedJointComponents::FixedJointComponents(MemoryAllocator& allocator) sizeof(Vector3) + sizeof(Vector3) + sizeof(Vector3) + sizeof(Matrix3x3) + sizeof(Matrix3x3) + sizeof(Vector3) + sizeof(Vector3) + sizeof(Matrix3x3) + sizeof(Matrix3x3) + - sizeof(Vector3) + sizeof(Vector3) + sizeof(Quaternion)) { + sizeof(Vector3) + sizeof(Vector3) + sizeof(Quaternion), 15 * GLOBAL_ALIGNMENT) { - // Allocate memory for the components data - allocate(INIT_NB_ALLOCATED_COMPONENTS); } // Allocate memory for a given number of components @@ -50,28 +48,44 @@ void FixedJointComponents::allocate(uint32 nbComponentsToAllocate) { assert(nbComponentsToAllocate > mNbAllocatedComponents); // Size for the data of a single component (in bytes) - const size_t totalSizeBytes = nbComponentsToAllocate * mComponentDataSize; + const size_t totalSizeBytes = nbComponentsToAllocate * mComponentDataSize + mAlignmentMarginSize; // Allocate memory void* newBuffer = mMemoryAllocator.allocate(totalSizeBytes); assert(newBuffer != nullptr); + assert(reinterpret_cast(newBuffer) % GLOBAL_ALIGNMENT == 0); // New pointers to components data Entity* newJointEntities = static_cast(newBuffer); - FixedJoint** newJoints = reinterpret_cast(newJointEntities + nbComponentsToAllocate); - Vector3* newLocalAnchorPointBody1 = reinterpret_cast(newJoints + nbComponentsToAllocate); - Vector3* newLocalAnchorPointBody2 = reinterpret_cast(newLocalAnchorPointBody1 + nbComponentsToAllocate); - Vector3* newR1World = reinterpret_cast(newLocalAnchorPointBody2 + nbComponentsToAllocate); - Vector3* newR2World = reinterpret_cast(newR1World + nbComponentsToAllocate); - Matrix3x3* newI1 = reinterpret_cast(newR2World + nbComponentsToAllocate); - Matrix3x3* newI2 = reinterpret_cast(newI1 + nbComponentsToAllocate); - Vector3* newImpulseTranslation = reinterpret_cast(newI2 + nbComponentsToAllocate); - Vector3* newImpulseRotation = reinterpret_cast(newImpulseTranslation + nbComponentsToAllocate); - Matrix3x3* newInverseMassMatrixTranslation = reinterpret_cast(newImpulseRotation + nbComponentsToAllocate); - Matrix3x3* newInverseMassMatrixRotation = reinterpret_cast(newInverseMassMatrixTranslation + nbComponentsToAllocate); - Vector3* newBiasTranslation = reinterpret_cast(newInverseMassMatrixRotation + nbComponentsToAllocate); - Vector3* newBiasRotation = reinterpret_cast(newBiasTranslation + nbComponentsToAllocate); - Quaternion* newInitOrientationDifferenceInv = reinterpret_cast(newBiasRotation + nbComponentsToAllocate); + FixedJoint** newJoints = reinterpret_cast(MemoryAllocator::alignAddress(newJointEntities + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newJoints) % GLOBAL_ALIGNMENT == 0); + Vector3* newLocalAnchorPointBody1 = reinterpret_cast(MemoryAllocator::alignAddress(newJoints + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newLocalAnchorPointBody1) % GLOBAL_ALIGNMENT == 0); + Vector3* newLocalAnchorPointBody2 = reinterpret_cast(MemoryAllocator::alignAddress(newLocalAnchorPointBody1 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newLocalAnchorPointBody2) % GLOBAL_ALIGNMENT == 0); + Vector3* newR1World = reinterpret_cast(MemoryAllocator::alignAddress(newLocalAnchorPointBody2 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newR1World) % GLOBAL_ALIGNMENT == 0); + Vector3* newR2World = reinterpret_cast(MemoryAllocator::alignAddress(newR1World + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newR2World) % GLOBAL_ALIGNMENT == 0); + Matrix3x3* newI1 = reinterpret_cast(MemoryAllocator::alignAddress(newR2World + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newI1) % GLOBAL_ALIGNMENT == 0); + Matrix3x3* newI2 = reinterpret_cast(MemoryAllocator::alignAddress(newI1 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newI1) % GLOBAL_ALIGNMENT == 0); + Vector3* newImpulseTranslation = reinterpret_cast(MemoryAllocator::alignAddress(newI2 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newImpulseTranslation) % GLOBAL_ALIGNMENT == 0); + Vector3* newImpulseRotation = reinterpret_cast(MemoryAllocator::alignAddress(newImpulseTranslation + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newImpulseRotation) % GLOBAL_ALIGNMENT == 0); + Matrix3x3* newInverseMassMatrixTranslation = reinterpret_cast(MemoryAllocator::alignAddress(newImpulseRotation + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newInverseMassMatrixTranslation) % GLOBAL_ALIGNMENT == 0); + Matrix3x3* newInverseMassMatrixRotation = reinterpret_cast(MemoryAllocator::alignAddress(newInverseMassMatrixTranslation + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newInverseMassMatrixRotation) % GLOBAL_ALIGNMENT == 0); + Vector3* newBiasTranslation = reinterpret_cast(MemoryAllocator::alignAddress(newInverseMassMatrixRotation + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newBiasTranslation) % GLOBAL_ALIGNMENT == 0); + Vector3* newBiasRotation = reinterpret_cast(MemoryAllocator::alignAddress(newBiasTranslation + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newBiasRotation) % GLOBAL_ALIGNMENT == 0); + Quaternion* newInitOrientationDifferenceInv = reinterpret_cast(MemoryAllocator::alignAddress(newBiasRotation + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newInitOrientationDifferenceInv) % GLOBAL_ALIGNMENT == 0); + assert(reinterpret_cast(newInitOrientationDifferenceInv + nbComponentsToAllocate) <= reinterpret_cast(newBuffer) + totalSizeBytes); // If there was already components before if (mNbComponents > 0) { diff --git a/src/components/HingeJointComponents.cpp b/src/components/HingeJointComponents.cpp index e55a9d2d..22e945c7 100644 --- a/src/components/HingeJointComponents.cpp +++ b/src/components/HingeJointComponents.cpp @@ -43,10 +43,8 @@ HingeJointComponents::HingeJointComponents(MemoryAllocator& allocator) sizeof(Vector3) + sizeof(decimal) + sizeof(decimal) + sizeof(decimal) + sizeof(decimal) + sizeof(decimal) + sizeof(decimal) + sizeof(decimal) + sizeof(bool) + sizeof(bool) + sizeof(decimal) + sizeof(decimal) + - sizeof(bool) + sizeof(bool) + sizeof(decimal) + sizeof(decimal)) { + sizeof(bool) + sizeof(bool) + sizeof(decimal) + sizeof(decimal), 35 * GLOBAL_ALIGNMENT ) { - // Allocate memory for the components data - allocate(INIT_NB_ALLOCATED_COMPONENTS); } // Allocate memory for a given number of components @@ -55,48 +53,84 @@ void HingeJointComponents::allocate(uint32 nbComponentsToAllocate) { assert(nbComponentsToAllocate > mNbAllocatedComponents); // Size for the data of a single component (in bytes) - const size_t totalSizeBytes = nbComponentsToAllocate * mComponentDataSize; + const size_t totalSizeBytes = nbComponentsToAllocate * mComponentDataSize + mAlignmentMarginSize; // Allocate memory void* newBuffer = mMemoryAllocator.allocate(totalSizeBytes); assert(newBuffer != nullptr); + assert(reinterpret_cast(newBuffer) % GLOBAL_ALIGNMENT == 0); // New pointers to components data Entity* newJointEntities = static_cast(newBuffer); - HingeJoint** newJoints = reinterpret_cast(newJointEntities + nbComponentsToAllocate); - Vector3* newLocalAnchorPointBody1 = reinterpret_cast(newJoints + nbComponentsToAllocate); - Vector3* newLocalAnchorPointBody2 = reinterpret_cast(newLocalAnchorPointBody1 + nbComponentsToAllocate); - Vector3* newR1World = reinterpret_cast(newLocalAnchorPointBody2 + nbComponentsToAllocate); - Vector3* newR2World = reinterpret_cast(newR1World + nbComponentsToAllocate); - Matrix3x3* newI1 = reinterpret_cast(newR2World + nbComponentsToAllocate); - Matrix3x3* newI2 = reinterpret_cast(newI1 + nbComponentsToAllocate); - Vector3* newImpulseTranslation = reinterpret_cast(newI2 + nbComponentsToAllocate); - Vector2* newImpulseRotation = reinterpret_cast(newImpulseTranslation + nbComponentsToAllocate); - Matrix3x3* newInverseMassMatrixTranslation = reinterpret_cast(newImpulseRotation + nbComponentsToAllocate); - Matrix2x2* newInverseMassMatrixRotation = reinterpret_cast(newInverseMassMatrixTranslation + nbComponentsToAllocate); - Vector3* newBiasTranslation = reinterpret_cast(newInverseMassMatrixRotation + nbComponentsToAllocate); - Vector2* newBiasRotation = reinterpret_cast(newBiasTranslation + nbComponentsToAllocate); - Quaternion* newInitOrientationDifferenceInv = reinterpret_cast(newBiasRotation + nbComponentsToAllocate); - Vector3* newHingeLocalAxisBody1 = reinterpret_cast(newInitOrientationDifferenceInv + nbComponentsToAllocate); - Vector3* newHingeLocalAxisBody2 = reinterpret_cast(newHingeLocalAxisBody1 + nbComponentsToAllocate); - Vector3* newA1 = reinterpret_cast(newHingeLocalAxisBody2 + nbComponentsToAllocate); - Vector3* newB2CrossA1 = reinterpret_cast(newA1 + nbComponentsToAllocate); - Vector3* newC2CrossA1 = reinterpret_cast(newB2CrossA1 + nbComponentsToAllocate); - decimal* newImpulseLowerLimit = reinterpret_cast(newC2CrossA1 + nbComponentsToAllocate); - decimal* newImpulseUpperLimit = reinterpret_cast(newImpulseLowerLimit + nbComponentsToAllocate); - decimal* newImpulseMotor = reinterpret_cast(newImpulseUpperLimit + nbComponentsToAllocate); - decimal* newInverseMassMatrixLimitMotor = reinterpret_cast(newImpulseMotor + nbComponentsToAllocate); - decimal* newInverseMassMatrixMotor = reinterpret_cast(newInverseMassMatrixLimitMotor + nbComponentsToAllocate); - decimal* newBLowerLimit = reinterpret_cast(newInverseMassMatrixMotor + nbComponentsToAllocate); - decimal* newBUpperLimit = reinterpret_cast(newBLowerLimit + nbComponentsToAllocate); - bool* newIsLimitEnabled = reinterpret_cast(newBUpperLimit + nbComponentsToAllocate); - bool* newIsMotorEnabled = reinterpret_cast(newIsLimitEnabled + nbComponentsToAllocate); - decimal* newLowerLimit = reinterpret_cast(newIsMotorEnabled + nbComponentsToAllocate); - decimal* newUpperLimit = reinterpret_cast(newLowerLimit + nbComponentsToAllocate); - bool* newIsLowerLimitViolated = reinterpret_cast(newUpperLimit + nbComponentsToAllocate); - bool* newIsUpperLimitViolated = reinterpret_cast(newIsLowerLimitViolated + nbComponentsToAllocate); - decimal* newMotorSpeed = reinterpret_cast(newIsUpperLimitViolated + nbComponentsToAllocate); - decimal* newMaxMotorTorque = reinterpret_cast(newMotorSpeed + nbComponentsToAllocate); + HingeJoint** newJoints = reinterpret_cast(MemoryAllocator::alignAddress(newJointEntities + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newJoints) % GLOBAL_ALIGNMENT == 0); + Vector3* newLocalAnchorPointBody1 = reinterpret_cast(MemoryAllocator::alignAddress(newJoints + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newLocalAnchorPointBody1) % GLOBAL_ALIGNMENT == 0); + Vector3* newLocalAnchorPointBody2 = reinterpret_cast(MemoryAllocator::alignAddress(newLocalAnchorPointBody1 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newLocalAnchorPointBody2) % GLOBAL_ALIGNMENT == 0); + Vector3* newR1World = reinterpret_cast(MemoryAllocator::alignAddress(newLocalAnchorPointBody2 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newR1World) % GLOBAL_ALIGNMENT == 0); + Vector3* newR2World = reinterpret_cast(MemoryAllocator::alignAddress(newR1World + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newR2World) % GLOBAL_ALIGNMENT == 0); + Matrix3x3* newI1 = reinterpret_cast(MemoryAllocator::alignAddress(newR2World + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newI1) % GLOBAL_ALIGNMENT == 0); + Matrix3x3* newI2 = reinterpret_cast(MemoryAllocator::alignAddress(newI1 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newI2) % GLOBAL_ALIGNMENT == 0); + Vector3* newImpulseTranslation = reinterpret_cast(MemoryAllocator::alignAddress(newI2 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newImpulseTranslation) % GLOBAL_ALIGNMENT == 0); + Vector2* newImpulseRotation = reinterpret_cast(MemoryAllocator::alignAddress(newImpulseTranslation + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newImpulseRotation) % GLOBAL_ALIGNMENT == 0); + Matrix3x3* newInverseMassMatrixTranslation = reinterpret_cast(MemoryAllocator::alignAddress(newImpulseRotation + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newInverseMassMatrixTranslation) % GLOBAL_ALIGNMENT == 0); + Matrix2x2* newInverseMassMatrixRotation = reinterpret_cast(MemoryAllocator::alignAddress(newInverseMassMatrixTranslation + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newInverseMassMatrixRotation) % GLOBAL_ALIGNMENT == 0); + Vector3* newBiasTranslation = reinterpret_cast(MemoryAllocator::alignAddress(newInverseMassMatrixRotation + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newBiasTranslation) % GLOBAL_ALIGNMENT == 0); + Vector2* newBiasRotation = reinterpret_cast(MemoryAllocator::alignAddress(newBiasTranslation + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newBiasRotation) % GLOBAL_ALIGNMENT == 0); + Quaternion* newInitOrientationDifferenceInv = reinterpret_cast(MemoryAllocator::alignAddress(newBiasRotation + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newInitOrientationDifferenceInv) % GLOBAL_ALIGNMENT == 0); + Vector3* newHingeLocalAxisBody1 = reinterpret_cast(MemoryAllocator::alignAddress(newInitOrientationDifferenceInv + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newHingeLocalAxisBody1) % GLOBAL_ALIGNMENT == 0); + Vector3* newHingeLocalAxisBody2 = reinterpret_cast(MemoryAllocator::alignAddress(newHingeLocalAxisBody1 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newHingeLocalAxisBody2) % GLOBAL_ALIGNMENT == 0); + Vector3* newA1 = reinterpret_cast(MemoryAllocator::alignAddress(newHingeLocalAxisBody2 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newA1) % GLOBAL_ALIGNMENT == 0); + Vector3* newB2CrossA1 = reinterpret_cast(MemoryAllocator::alignAddress(newA1 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newB2CrossA1) % GLOBAL_ALIGNMENT == 0); + Vector3* newC2CrossA1 = reinterpret_cast(MemoryAllocator::alignAddress(newB2CrossA1 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newC2CrossA1) % GLOBAL_ALIGNMENT == 0); + decimal* newImpulseLowerLimit = reinterpret_cast(MemoryAllocator::alignAddress(newC2CrossA1 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newImpulseLowerLimit) % GLOBAL_ALIGNMENT == 0); + decimal* newImpulseUpperLimit = reinterpret_cast(MemoryAllocator::alignAddress(newImpulseLowerLimit + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newImpulseUpperLimit) % GLOBAL_ALIGNMENT == 0); + decimal* newImpulseMotor = reinterpret_cast(MemoryAllocator::alignAddress(newImpulseUpperLimit + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newImpulseMotor) % GLOBAL_ALIGNMENT == 0); + decimal* newInverseMassMatrixLimitMotor = reinterpret_cast(MemoryAllocator::alignAddress(newImpulseMotor + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newInverseMassMatrixLimitMotor) % GLOBAL_ALIGNMENT == 0); + decimal* newInverseMassMatrixMotor = reinterpret_cast(MemoryAllocator::alignAddress(newInverseMassMatrixLimitMotor + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newInverseMassMatrixMotor) % GLOBAL_ALIGNMENT == 0); + decimal* newBLowerLimit = reinterpret_cast(MemoryAllocator::alignAddress(newInverseMassMatrixMotor + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newBLowerLimit) % GLOBAL_ALIGNMENT == 0); + decimal* newBUpperLimit = reinterpret_cast(MemoryAllocator::alignAddress(newBLowerLimit + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newBUpperLimit) % GLOBAL_ALIGNMENT == 0); + bool* newIsLimitEnabled = reinterpret_cast(MemoryAllocator::alignAddress(newBUpperLimit + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newIsLimitEnabled) % GLOBAL_ALIGNMENT == 0); + bool* newIsMotorEnabled = reinterpret_cast(MemoryAllocator::alignAddress(newIsLimitEnabled + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newIsMotorEnabled) % GLOBAL_ALIGNMENT == 0); + decimal* newLowerLimit = reinterpret_cast(MemoryAllocator::alignAddress(newIsMotorEnabled + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newLowerLimit) % GLOBAL_ALIGNMENT == 0); + decimal* newUpperLimit = reinterpret_cast(MemoryAllocator::alignAddress(newLowerLimit + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newUpperLimit) % GLOBAL_ALIGNMENT == 0); + bool* newIsLowerLimitViolated = reinterpret_cast(MemoryAllocator::alignAddress(newUpperLimit + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newIsLowerLimitViolated) % GLOBAL_ALIGNMENT == 0); + bool* newIsUpperLimitViolated = reinterpret_cast(MemoryAllocator::alignAddress(newIsLowerLimitViolated + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newIsUpperLimitViolated) % GLOBAL_ALIGNMENT == 0); + decimal* newMotorSpeed = reinterpret_cast(MemoryAllocator::alignAddress(newIsUpperLimitViolated + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newMotorSpeed) % GLOBAL_ALIGNMENT == 0); + decimal* newMaxMotorTorque = reinterpret_cast(MemoryAllocator::alignAddress(newMotorSpeed + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newMaxMotorTorque) % GLOBAL_ALIGNMENT == 0); + assert(reinterpret_cast(newMaxMotorTorque + nbComponentsToAllocate) <= reinterpret_cast(newBuffer) + totalSizeBytes); // If there was already components before if (mNbComponents > 0) { diff --git a/src/components/JointComponents.cpp b/src/components/JointComponents.cpp index 12123c51..947b4ee0 100644 --- a/src/components/JointComponents.cpp +++ b/src/components/JointComponents.cpp @@ -35,10 +35,8 @@ using namespace reactphysics3d; JointComponents::JointComponents(MemoryAllocator& allocator) :Components(allocator, sizeof(Entity) + sizeof(Entity) + sizeof(Entity) + sizeof(Joint*) + sizeof(JointType) + sizeof(JointsPositionCorrectionTechnique) + sizeof(bool) + - sizeof(bool)) { + sizeof(bool), 8 * GLOBAL_ALIGNMENT) { - // Allocate memory for the components data - allocate(INIT_NB_ALLOCATED_COMPONENTS); } // Allocate memory for a given number of components @@ -47,21 +45,30 @@ void JointComponents::allocate(uint32 nbComponentsToAllocate) { assert(nbComponentsToAllocate > mNbAllocatedComponents); // Size for the data of a single component (in bytes) - const size_t totalSizeBytes = nbComponentsToAllocate * mComponentDataSize; + const size_t totalSizeBytes = nbComponentsToAllocate * mComponentDataSize + mAlignmentMarginSize; // Allocate memory void* newBuffer = mMemoryAllocator.allocate(totalSizeBytes); assert(newBuffer != nullptr); + assert(reinterpret_cast(newBuffer) % GLOBAL_ALIGNMENT == 0); // New pointers to components data Entity* newJointsEntities = static_cast(newBuffer); - Entity* newBody1Entities = reinterpret_cast(newJointsEntities + nbComponentsToAllocate); - Entity* newBody2Entities = reinterpret_cast(newBody1Entities + nbComponentsToAllocate); - Joint** newJoints = reinterpret_cast(newBody2Entities + nbComponentsToAllocate); - JointType* newTypes = reinterpret_cast(newJoints + nbComponentsToAllocate); - JointsPositionCorrectionTechnique* newPositionCorrectionTechniques = reinterpret_cast(newTypes + nbComponentsToAllocate); - bool* newIsCollisionEnabled = reinterpret_cast(newPositionCorrectionTechniques + nbComponentsToAllocate); - bool* newIsAlreadyInIsland = reinterpret_cast(newIsCollisionEnabled + nbComponentsToAllocate); + Entity* newBody1Entities = reinterpret_cast(MemoryAllocator::alignAddress(newJointsEntities + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newBody1Entities) % GLOBAL_ALIGNMENT == 0); + Entity* newBody2Entities = reinterpret_cast(MemoryAllocator::alignAddress(newBody1Entities + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newBody2Entities) % GLOBAL_ALIGNMENT == 0); + Joint** newJoints = reinterpret_cast(MemoryAllocator::alignAddress(newBody2Entities + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newJoints) % GLOBAL_ALIGNMENT == 0); + JointType* newTypes = reinterpret_cast(MemoryAllocator::alignAddress(newJoints + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newTypes) % GLOBAL_ALIGNMENT == 0); + JointsPositionCorrectionTechnique* newPositionCorrectionTechniques = reinterpret_cast(MemoryAllocator::alignAddress(newTypes + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newPositionCorrectionTechniques) % GLOBAL_ALIGNMENT == 0); + bool* newIsCollisionEnabled = reinterpret_cast(MemoryAllocator::alignAddress(newPositionCorrectionTechniques + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newIsCollisionEnabled) % GLOBAL_ALIGNMENT == 0); + bool* newIsAlreadyInIsland = reinterpret_cast(MemoryAllocator::alignAddress(newIsCollisionEnabled + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newIsAlreadyInIsland) % GLOBAL_ALIGNMENT == 0); + assert(reinterpret_cast(newIsAlreadyInIsland + nbComponentsToAllocate) <= reinterpret_cast(newBuffer) + totalSizeBytes); // If there was already components before if (mNbComponents > 0) { diff --git a/src/components/RigidBodyComponents.cpp b/src/components/RigidBodyComponents.cpp index 3edcefe9..adc0e4df 100644 --- a/src/components/RigidBodyComponents.cpp +++ b/src/components/RigidBodyComponents.cpp @@ -44,10 +44,8 @@ RigidBodyComponents::RigidBodyComponents(MemoryAllocator& allocator) sizeof(Vector3) + sizeof(Vector3) + sizeof(Vector3) + sizeof(Quaternion) + sizeof(Vector3) + sizeof(Vector3) + sizeof(bool) + sizeof(bool) + sizeof(Array) + sizeof(Array) + - sizeof(Vector3) + sizeof(Vector3)) { + sizeof(Vector3) + sizeof(Vector3), 31 * GLOBAL_ALIGNMENT) { - // Allocate memory for the components data - allocate(INIT_NB_ALLOCATED_COMPONENTS); } // Allocate memory for a given number of components @@ -56,44 +54,76 @@ void RigidBodyComponents::allocate(uint32 nbComponentsToAllocate) { assert(nbComponentsToAllocate > mNbAllocatedComponents); // Size for the data of a single component (in bytes) - const size_t totalSizeBytes = nbComponentsToAllocate * mComponentDataSize; + const size_t totalSizeBytes = nbComponentsToAllocate * mComponentDataSize + mAlignmentMarginSize; // Allocate memory void* newBuffer = mMemoryAllocator.allocate(totalSizeBytes); assert(newBuffer != nullptr); + assert(reinterpret_cast(newBuffer) % GLOBAL_ALIGNMENT == 0); // New pointers to components data Entity* newBodiesEntities = static_cast(newBuffer); - RigidBody** newBodies = reinterpret_cast(newBodiesEntities + nbComponentsToAllocate); - bool* newIsAllowedToSleep = reinterpret_cast(newBodies + nbComponentsToAllocate); - bool* newIsSleeping = reinterpret_cast(newIsAllowedToSleep + nbComponentsToAllocate); - decimal* newSleepTimes = reinterpret_cast(newIsSleeping + nbComponentsToAllocate); - BodyType* newBodyTypes = reinterpret_cast(newSleepTimes + nbComponentsToAllocate); - Vector3* newLinearVelocities = reinterpret_cast(newBodyTypes + nbComponentsToAllocate); - Vector3* newAngularVelocities = reinterpret_cast(newLinearVelocities + nbComponentsToAllocate); - Vector3* newExternalForces = reinterpret_cast(newAngularVelocities + nbComponentsToAllocate); - Vector3* newExternalTorques = reinterpret_cast(newExternalForces + nbComponentsToAllocate); - decimal* newLinearDampings = reinterpret_cast(newExternalTorques + nbComponentsToAllocate); - decimal* newAngularDampings = reinterpret_cast(newLinearDampings + nbComponentsToAllocate); - decimal* newMasses = reinterpret_cast(newAngularDampings + nbComponentsToAllocate); - decimal* newInverseMasses = reinterpret_cast(newMasses + nbComponentsToAllocate); - Vector3* newInertiaTensorLocal = reinterpret_cast(newInverseMasses + nbComponentsToAllocate); - Vector3* newInertiaTensorLocalInverses = reinterpret_cast(newInertiaTensorLocal + nbComponentsToAllocate); - Matrix3x3* newInertiaTensorWorldInverses = reinterpret_cast(newInertiaTensorLocalInverses + nbComponentsToAllocate); - Vector3* newConstrainedLinearVelocities = reinterpret_cast(newInertiaTensorWorldInverses + nbComponentsToAllocate); - Vector3* newConstrainedAngularVelocities = reinterpret_cast(newConstrainedLinearVelocities + nbComponentsToAllocate); - Vector3* newSplitLinearVelocities = reinterpret_cast(newConstrainedAngularVelocities + nbComponentsToAllocate); - Vector3* newSplitAngularVelocities = reinterpret_cast(newSplitLinearVelocities + nbComponentsToAllocate); - Vector3* newConstrainedPositions = reinterpret_cast(newSplitAngularVelocities + nbComponentsToAllocate); - Quaternion* newConstrainedOrientations = reinterpret_cast(newConstrainedPositions + nbComponentsToAllocate); - Vector3* newCentersOfMassLocal = reinterpret_cast(newConstrainedOrientations + nbComponentsToAllocate); - Vector3* newCentersOfMassWorld = reinterpret_cast(newCentersOfMassLocal + nbComponentsToAllocate); - bool* newIsGravityEnabled = reinterpret_cast(newCentersOfMassWorld + nbComponentsToAllocate); - bool* newIsAlreadyInIsland = reinterpret_cast(newIsGravityEnabled + nbComponentsToAllocate); - Array* newJoints = reinterpret_cast*>(newIsAlreadyInIsland + nbComponentsToAllocate); - Array* newContactPairs = reinterpret_cast*>(newJoints + nbComponentsToAllocate); - Vector3* newLinearLockAxisFactors = reinterpret_cast(newContactPairs + nbComponentsToAllocate); - Vector3* newAngularLockAxisFactors = reinterpret_cast(newLinearLockAxisFactors + nbComponentsToAllocate); + RigidBody** newBodies = reinterpret_cast(MemoryAllocator::alignAddress(newBodiesEntities + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newBodies) % GLOBAL_ALIGNMENT == 0); + bool* newIsAllowedToSleep = reinterpret_cast(MemoryAllocator::alignAddress(newBodies + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newIsAllowedToSleep) % GLOBAL_ALIGNMENT == 0); + bool* newIsSleeping = reinterpret_cast(MemoryAllocator::alignAddress(newIsAllowedToSleep + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newIsSleeping) % GLOBAL_ALIGNMENT == 0); + decimal* newSleepTimes = reinterpret_cast(MemoryAllocator::alignAddress(newIsSleeping + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newSleepTimes) % GLOBAL_ALIGNMENT == 0); + BodyType* newBodyTypes = reinterpret_cast(MemoryAllocator::alignAddress(newSleepTimes + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newBodyTypes) % GLOBAL_ALIGNMENT == 0); + Vector3* newLinearVelocities = reinterpret_cast(MemoryAllocator::alignAddress(newBodyTypes + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newLinearVelocities) % GLOBAL_ALIGNMENT == 0); + Vector3* newAngularVelocities = reinterpret_cast(MemoryAllocator::alignAddress(newLinearVelocities + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newAngularVelocities) % GLOBAL_ALIGNMENT == 0); + Vector3* newExternalForces = reinterpret_cast(MemoryAllocator::alignAddress(newAngularVelocities + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newExternalForces) % GLOBAL_ALIGNMENT == 0); + Vector3* newExternalTorques = reinterpret_cast(MemoryAllocator::alignAddress(newExternalForces + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newExternalTorques) % GLOBAL_ALIGNMENT == 0); + decimal* newLinearDampings = reinterpret_cast(MemoryAllocator::alignAddress(newExternalTorques + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newLinearDampings) % GLOBAL_ALIGNMENT == 0); + decimal* newAngularDampings = reinterpret_cast(MemoryAllocator::alignAddress(newLinearDampings + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newAngularDampings) % GLOBAL_ALIGNMENT == 0); + decimal* newMasses = reinterpret_cast(MemoryAllocator::alignAddress(newAngularDampings + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newMasses) % GLOBAL_ALIGNMENT == 0); + decimal* newInverseMasses = reinterpret_cast(MemoryAllocator::alignAddress(newMasses + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newInverseMasses) % GLOBAL_ALIGNMENT == 0); + Vector3* newInertiaTensorLocal = reinterpret_cast(MemoryAllocator::alignAddress(newInverseMasses + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newInertiaTensorLocal) % GLOBAL_ALIGNMENT == 0); + Vector3* newInertiaTensorLocalInverses = reinterpret_cast(MemoryAllocator::alignAddress(newInertiaTensorLocal + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newInertiaTensorLocal) % GLOBAL_ALIGNMENT == 0); + Matrix3x3* newInertiaTensorWorldInverses = reinterpret_cast(MemoryAllocator::alignAddress(newInertiaTensorLocalInverses + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newInertiaTensorWorldInverses) % GLOBAL_ALIGNMENT == 0); + Vector3* newConstrainedLinearVelocities = reinterpret_cast(MemoryAllocator::alignAddress(newInertiaTensorWorldInverses + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newConstrainedLinearVelocities) % GLOBAL_ALIGNMENT == 0); + Vector3* newConstrainedAngularVelocities = reinterpret_cast(MemoryAllocator::alignAddress(newConstrainedLinearVelocities + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newConstrainedAngularVelocities) % GLOBAL_ALIGNMENT == 0); + Vector3* newSplitLinearVelocities = reinterpret_cast(MemoryAllocator::alignAddress(newConstrainedAngularVelocities + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newSplitLinearVelocities) % GLOBAL_ALIGNMENT == 0); + Vector3* newSplitAngularVelocities = reinterpret_cast(MemoryAllocator::alignAddress(newSplitLinearVelocities + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newSplitAngularVelocities) % GLOBAL_ALIGNMENT == 0); + Vector3* newConstrainedPositions = reinterpret_cast(MemoryAllocator::alignAddress(newSplitAngularVelocities + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newConstrainedPositions) % GLOBAL_ALIGNMENT == 0); + Quaternion* newConstrainedOrientations = reinterpret_cast(MemoryAllocator::alignAddress(newConstrainedPositions + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newConstrainedOrientations) % GLOBAL_ALIGNMENT == 0); + Vector3* newCentersOfMassLocal = reinterpret_cast(MemoryAllocator::alignAddress(newConstrainedOrientations + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newCentersOfMassLocal) % GLOBAL_ALIGNMENT == 0); + Vector3* newCentersOfMassWorld = reinterpret_cast(MemoryAllocator::alignAddress(newCentersOfMassLocal + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newCentersOfMassWorld) % GLOBAL_ALIGNMENT == 0); + bool* newIsGravityEnabled = reinterpret_cast(MemoryAllocator::alignAddress(newCentersOfMassWorld + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newIsGravityEnabled) % GLOBAL_ALIGNMENT == 0); + bool* newIsAlreadyInIsland = reinterpret_cast(MemoryAllocator::alignAddress(newIsGravityEnabled + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newIsAlreadyInIsland) % GLOBAL_ALIGNMENT == 0); + Array* newJoints = reinterpret_cast*>(MemoryAllocator::alignAddress(newIsAlreadyInIsland + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newJoints) % GLOBAL_ALIGNMENT == 0); + Array* newContactPairs = reinterpret_cast*>(MemoryAllocator::alignAddress(newJoints + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newContactPairs) % GLOBAL_ALIGNMENT == 0); + Vector3* newLinearLockAxisFactors = reinterpret_cast(MemoryAllocator::alignAddress(newContactPairs + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newLinearLockAxisFactors) % GLOBAL_ALIGNMENT == 0); + Vector3* newAngularLockAxisFactors = reinterpret_cast(MemoryAllocator::alignAddress(newLinearLockAxisFactors + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newAngularLockAxisFactors) % GLOBAL_ALIGNMENT == 0); + assert(reinterpret_cast(newAngularLockAxisFactors + nbComponentsToAllocate) <= reinterpret_cast(newBuffer) + totalSizeBytes); // If there was already components before if (mNbComponents > 0) { diff --git a/src/components/SliderJointComponents.cpp b/src/components/SliderJointComponents.cpp index 4a6da7a0..97eeab24 100644 --- a/src/components/SliderJointComponents.cpp +++ b/src/components/SliderJointComponents.cpp @@ -45,10 +45,8 @@ SliderJointComponents::SliderJointComponents(MemoryAllocator& allocator) sizeof(bool) + sizeof(bool) + sizeof(decimal) + sizeof(decimal) + sizeof(bool) + sizeof(bool) + sizeof(decimal) + sizeof(decimal) + sizeof(Vector3) + sizeof(Vector3) + sizeof(Vector3) + sizeof(Vector3) + - sizeof(Vector3) + sizeof(Vector3)) { + sizeof(Vector3) + sizeof(Vector3), 40 * GLOBAL_ALIGNMENT) { - // Allocate memory for the components data - allocate(INIT_NB_ALLOCATED_COMPONENTS); } // Allocate memory for a given number of components @@ -57,53 +55,94 @@ void SliderJointComponents::allocate(uint32 nbComponentsToAllocate) { assert(nbComponentsToAllocate > mNbAllocatedComponents); // Size for the data of a single component (in bytes) - const size_t totalSizeBytes = nbComponentsToAllocate * mComponentDataSize; + const size_t totalSizeBytes = nbComponentsToAllocate * mComponentDataSize + mAlignmentMarginSize; // Allocate memory void* newBuffer = mMemoryAllocator.allocate(totalSizeBytes); assert(newBuffer != nullptr); + assert(reinterpret_cast(newBuffer) % GLOBAL_ALIGNMENT == 0); // New pointers to components data Entity* newJointEntities = static_cast(newBuffer); - SliderJoint** newJoints = reinterpret_cast(newJointEntities + nbComponentsToAllocate); - Vector3* newLocalAnchorPointBody1 = reinterpret_cast(newJoints + nbComponentsToAllocate); - Vector3* newLocalAnchorPointBody2 = reinterpret_cast(newLocalAnchorPointBody1 + nbComponentsToAllocate); - Matrix3x3* newI1 = reinterpret_cast(newLocalAnchorPointBody2 + nbComponentsToAllocate); - Matrix3x3* newI2 = reinterpret_cast(newI1 + nbComponentsToAllocate); - Vector2* newImpulseTranslation = reinterpret_cast(newI2 + nbComponentsToAllocate); - Vector3* newImpulseRotation = reinterpret_cast(newImpulseTranslation + nbComponentsToAllocate); - Matrix2x2* newInverseMassMatrixTranslation = reinterpret_cast(newImpulseRotation + nbComponentsToAllocate); - Matrix3x3* newInverseMassMatrixRotation = reinterpret_cast(newInverseMassMatrixTranslation + nbComponentsToAllocate); - Vector2* newBiasTranslation = reinterpret_cast(newInverseMassMatrixRotation + nbComponentsToAllocate); - Vector3* newBiasRotation = reinterpret_cast(newBiasTranslation + nbComponentsToAllocate); - Quaternion* newInitOrientationDifferenceInv = reinterpret_cast(newBiasRotation + nbComponentsToAllocate); - Vector3* newSliderAxisBody1 = reinterpret_cast(newInitOrientationDifferenceInv + nbComponentsToAllocate); - Vector3* newSliderAxisWorld = reinterpret_cast(newSliderAxisBody1 + nbComponentsToAllocate); - Vector3* newR1 = reinterpret_cast(newSliderAxisWorld + nbComponentsToAllocate); - Vector3* newR2 = reinterpret_cast(newR1 + nbComponentsToAllocate); - Vector3* newN1 = reinterpret_cast(newR2 + nbComponentsToAllocate); - Vector3* newN2 = reinterpret_cast(newN1 + nbComponentsToAllocate); - decimal* newImpulseLowerLimit = reinterpret_cast(newN2 + nbComponentsToAllocate); - decimal* newImpulseUpperLimit = reinterpret_cast(newImpulseLowerLimit + nbComponentsToAllocate); - decimal* newImpulseMotor = reinterpret_cast(newImpulseUpperLimit + nbComponentsToAllocate); - decimal* newInverseMassMatrixLimit = reinterpret_cast(newImpulseMotor + nbComponentsToAllocate); - decimal* newInverseMassMatrixMotor = reinterpret_cast(newInverseMassMatrixLimit + nbComponentsToAllocate); - decimal* newBLowerLimit = reinterpret_cast(newInverseMassMatrixMotor + nbComponentsToAllocate); - decimal* newBUpperLimit = reinterpret_cast(newBLowerLimit + nbComponentsToAllocate); - bool* newIsLimitEnabled = reinterpret_cast(newBUpperLimit + nbComponentsToAllocate); - bool* newIsMotorEnabled = reinterpret_cast(newIsLimitEnabled + nbComponentsToAllocate); - decimal* newLowerLimit = reinterpret_cast(newIsMotorEnabled + nbComponentsToAllocate); - decimal* newUpperLimit = reinterpret_cast(newLowerLimit + nbComponentsToAllocate); - bool* newIsLowerLimitViolated = reinterpret_cast(newUpperLimit + nbComponentsToAllocate); - bool* newIsUpperLimitViolated = reinterpret_cast(newIsLowerLimitViolated + nbComponentsToAllocate); - decimal* newMotorSpeed = reinterpret_cast(newIsUpperLimitViolated + nbComponentsToAllocate); - decimal* newMaxMotorForce = reinterpret_cast(newMotorSpeed + nbComponentsToAllocate); - Vector3* newR2CrossN1 = reinterpret_cast(newMaxMotorForce + nbComponentsToAllocate); - Vector3* newR2CrossN2 = reinterpret_cast(newR2CrossN1 + nbComponentsToAllocate); - Vector3* newR2CrossSliderAxis = reinterpret_cast(newR2CrossN2 + nbComponentsToAllocate); - Vector3* newR1PlusUCrossN1 = reinterpret_cast(newR2CrossSliderAxis + nbComponentsToAllocate); - Vector3* newR1PlusUCrossN2 = reinterpret_cast(newR1PlusUCrossN1 + nbComponentsToAllocate); - Vector3* newR1PlusUCrossSliderAxis = reinterpret_cast(newR1PlusUCrossN2 + nbComponentsToAllocate); + SliderJoint** newJoints = reinterpret_cast(MemoryAllocator::alignAddress(newJointEntities + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newJoints) % GLOBAL_ALIGNMENT == 0); + Vector3* newLocalAnchorPointBody1 = reinterpret_cast(MemoryAllocator::alignAddress(newJoints + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newLocalAnchorPointBody1) % GLOBAL_ALIGNMENT == 0); + Vector3* newLocalAnchorPointBody2 = reinterpret_cast(MemoryAllocator::alignAddress(newLocalAnchorPointBody1 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newLocalAnchorPointBody2) % GLOBAL_ALIGNMENT == 0); + Matrix3x3* newI1 = reinterpret_cast(MemoryAllocator::alignAddress(newLocalAnchorPointBody2 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newI1) % GLOBAL_ALIGNMENT == 0); + Matrix3x3* newI2 = reinterpret_cast(MemoryAllocator::alignAddress(newI1 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newI2) % GLOBAL_ALIGNMENT == 0); + Vector2* newImpulseTranslation = reinterpret_cast(MemoryAllocator::alignAddress(newI2 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newImpulseTranslation) % GLOBAL_ALIGNMENT == 0); + Vector3* newImpulseRotation = reinterpret_cast(MemoryAllocator::alignAddress(newImpulseTranslation + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newImpulseRotation) % GLOBAL_ALIGNMENT == 0); + Matrix2x2* newInverseMassMatrixTranslation = reinterpret_cast(MemoryAllocator::alignAddress(newImpulseRotation + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newInverseMassMatrixTranslation) % GLOBAL_ALIGNMENT == 0); + Matrix3x3* newInverseMassMatrixRotation = reinterpret_cast(MemoryAllocator::alignAddress(newInverseMassMatrixTranslation + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newInverseMassMatrixRotation) % GLOBAL_ALIGNMENT == 0); + Vector2* newBiasTranslation = reinterpret_cast(MemoryAllocator::alignAddress(newInverseMassMatrixRotation + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newBiasTranslation) % GLOBAL_ALIGNMENT == 0); + Vector3* newBiasRotation = reinterpret_cast(MemoryAllocator::alignAddress(newBiasTranslation + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newBiasRotation) % GLOBAL_ALIGNMENT == 0); + Quaternion* newInitOrientationDifferenceInv = reinterpret_cast(MemoryAllocator::alignAddress(newBiasRotation + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newInitOrientationDifferenceInv) % GLOBAL_ALIGNMENT == 0); + Vector3* newSliderAxisBody1 = reinterpret_cast(MemoryAllocator::alignAddress(newInitOrientationDifferenceInv + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newSliderAxisBody1) % GLOBAL_ALIGNMENT == 0); + Vector3* newSliderAxisWorld = reinterpret_cast(MemoryAllocator::alignAddress(newSliderAxisBody1 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newSliderAxisWorld) % GLOBAL_ALIGNMENT == 0); + Vector3* newR1 = reinterpret_cast(MemoryAllocator::alignAddress(newSliderAxisWorld + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newR1) % GLOBAL_ALIGNMENT == 0); + Vector3* newR2 = reinterpret_cast(MemoryAllocator::alignAddress(newR1 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newR2) % GLOBAL_ALIGNMENT == 0); + Vector3* newN1 = reinterpret_cast(MemoryAllocator::alignAddress(newR2 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newN1) % GLOBAL_ALIGNMENT == 0); + Vector3* newN2 = reinterpret_cast(MemoryAllocator::alignAddress(newN1 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newN2) % GLOBAL_ALIGNMENT == 0); + decimal* newImpulseLowerLimit = reinterpret_cast(MemoryAllocator::alignAddress(newN2 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newImpulseLowerLimit) % GLOBAL_ALIGNMENT == 0); + decimal* newImpulseUpperLimit = reinterpret_cast(MemoryAllocator::alignAddress(newImpulseLowerLimit + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newImpulseUpperLimit) % GLOBAL_ALIGNMENT == 0); + decimal* newImpulseMotor = reinterpret_cast(MemoryAllocator::alignAddress(newImpulseUpperLimit + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newImpulseMotor) % GLOBAL_ALIGNMENT == 0); + decimal* newInverseMassMatrixLimit = reinterpret_cast(MemoryAllocator::alignAddress(newImpulseMotor + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newInverseMassMatrixLimit) % GLOBAL_ALIGNMENT == 0); + decimal* newInverseMassMatrixMotor = reinterpret_cast(MemoryAllocator::alignAddress(newInverseMassMatrixLimit + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newInverseMassMatrixMotor) % GLOBAL_ALIGNMENT == 0); + decimal* newBLowerLimit = reinterpret_cast(MemoryAllocator::alignAddress(newInverseMassMatrixMotor + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newBLowerLimit) % GLOBAL_ALIGNMENT == 0); + decimal* newBUpperLimit = reinterpret_cast(MemoryAllocator::alignAddress(newBLowerLimit + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newBUpperLimit) % GLOBAL_ALIGNMENT == 0); + bool* newIsLimitEnabled = reinterpret_cast(MemoryAllocator::alignAddress(newBUpperLimit + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newIsLimitEnabled) % GLOBAL_ALIGNMENT == 0); + bool* newIsMotorEnabled = reinterpret_cast(MemoryAllocator::alignAddress(newIsLimitEnabled + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newIsMotorEnabled) % GLOBAL_ALIGNMENT == 0); + decimal* newLowerLimit = reinterpret_cast(MemoryAllocator::alignAddress(newIsMotorEnabled + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newLowerLimit) % GLOBAL_ALIGNMENT == 0); + decimal* newUpperLimit = reinterpret_cast(MemoryAllocator::alignAddress(newLowerLimit + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newUpperLimit) % GLOBAL_ALIGNMENT == 0); + bool* newIsLowerLimitViolated = reinterpret_cast(MemoryAllocator::alignAddress(newUpperLimit + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newIsLowerLimitViolated) % GLOBAL_ALIGNMENT == 0); + bool* newIsUpperLimitViolated = reinterpret_cast(MemoryAllocator::alignAddress(newIsLowerLimitViolated + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newIsUpperLimitViolated) % GLOBAL_ALIGNMENT == 0); + decimal* newMotorSpeed = reinterpret_cast(MemoryAllocator::alignAddress(newIsUpperLimitViolated + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newMotorSpeed) % GLOBAL_ALIGNMENT == 0); + decimal* newMaxMotorForce = reinterpret_cast(MemoryAllocator::alignAddress(newMotorSpeed + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newMaxMotorForce) % GLOBAL_ALIGNMENT == 0); + Vector3* newR2CrossN1 = reinterpret_cast(MemoryAllocator::alignAddress(newMaxMotorForce + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newR2CrossN1) % GLOBAL_ALIGNMENT == 0); + Vector3* newR2CrossN2 = reinterpret_cast(MemoryAllocator::alignAddress(newR2CrossN1 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newR2CrossN2) % GLOBAL_ALIGNMENT == 0); + Vector3* newR2CrossSliderAxis = reinterpret_cast(MemoryAllocator::alignAddress(newR2CrossN2 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newR2CrossSliderAxis) % GLOBAL_ALIGNMENT == 0); + Vector3* newR1PlusUCrossN1 = reinterpret_cast(MemoryAllocator::alignAddress(newR2CrossSliderAxis + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newR1PlusUCrossN1) % GLOBAL_ALIGNMENT == 0); + Vector3* newR1PlusUCrossN2 = reinterpret_cast(MemoryAllocator::alignAddress(newR1PlusUCrossN1 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newR1PlusUCrossN2) % GLOBAL_ALIGNMENT == 0); + Vector3* newR1PlusUCrossSliderAxis = reinterpret_cast(MemoryAllocator::alignAddress(newR1PlusUCrossN2 + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newR1PlusUCrossSliderAxis) % GLOBAL_ALIGNMENT == 0); + assert(reinterpret_cast(newR1PlusUCrossSliderAxis + nbComponentsToAllocate) <= reinterpret_cast(newBuffer) + totalSizeBytes); // If there was already components before if (mNbComponents > 0) { diff --git a/src/components/TransformComponents.cpp b/src/components/TransformComponents.cpp index aa7d5a58..2970e36e 100644 --- a/src/components/TransformComponents.cpp +++ b/src/components/TransformComponents.cpp @@ -26,6 +26,7 @@ // Libraries #include #include +#include #include #include @@ -35,10 +36,9 @@ using namespace reactphysics3d; // Constructor TransformComponents::TransformComponents(MemoryAllocator& allocator) - :Components(allocator, sizeof(Entity) + sizeof(Transform) + 2 * GLOBAL_ALIGNMENT) { + :Components(allocator, sizeof(Entity) + sizeof(Transform), 2 * GLOBAL_ALIGNMENT) { + - // Allocate memory for the components data - allocate(INIT_NB_ALLOCATED_COMPONENTS); } // Allocate memory for a given number of components @@ -47,17 +47,19 @@ void TransformComponents::allocate(uint32 nbComponentsToAllocate) { assert(nbComponentsToAllocate > mNbAllocatedComponents); // Size for the data of a single component (in bytes) - const size_t totalSizeBytes = nbComponentsToAllocate * mComponentDataSize; + const size_t totalSizeBytes = nbComponentsToAllocate * mComponentDataSize + mAlignmentMarginSize; // Allocate memory void* newBuffer = mMemoryAllocator.allocate(totalSizeBytes); assert(newBuffer != nullptr); + assert(reinterpret_cast(newBuffer) % GLOBAL_ALIGNMENT == 0); // New pointers to components data Entity* newEntities = static_cast(newBuffer); - //assert(reinterpret_cast(newEntities) % GLOBAL_ALIGNMENT == 0); - Transform* newTransforms = reinterpret_cast(newEntities + nbComponentsToAllocate); - //assert(reinterpret_cast(newTransforms) % GLOBAL_ALIGNMENT == 0); + assert(reinterpret_cast(newEntities) % GLOBAL_ALIGNMENT == 0); + Transform* newTransforms = reinterpret_cast(MemoryAllocator::alignAddress(newEntities + nbComponentsToAllocate, GLOBAL_ALIGNMENT)); + assert(reinterpret_cast(newTransforms) % GLOBAL_ALIGNMENT == 0); + assert(reinterpret_cast(newTransforms + nbComponentsToAllocate) <= reinterpret_cast(newBuffer) + totalSizeBytes); // If there was already components before if (mNbComponents > 0) { diff --git a/src/engine/PhysicsWorld.cpp b/src/engine/PhysicsWorld.cpp index b6058e6d..d3529be1 100644 --- a/src/engine/PhysicsWorld.cpp +++ b/src/engine/PhysicsWorld.cpp @@ -106,6 +106,16 @@ PhysicsWorld::PhysicsWorld(MemoryManager& memoryManager, PhysicsCommon& physicsC mNbWorlds++; + mTransformComponents.init(); + mCollidersComponents.init(); + mCollisionBodyComponents.init(); + mRigidBodyComponents.init(); + mJointsComponents.init(); + mBallAndSocketJointsComponents.init(); + mFixedJointsComponents.init(); + mSliderJointsComponents.init(); + mHingeJointsComponents.init(); + RP3D_LOG(mConfig.worldName, Logger::Level::Information, Logger::Category::World, "Physics World: Physics world " + mName + " has been created", __FILE__, __LINE__); RP3D_LOG(mConfig.worldName, Logger::Level::Information, Logger::Category::World, From 8b18ee22f3ea82ccaecd319fd667e55e32c4eb81 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Mon, 28 Mar 2022 21:48:18 +0200 Subject: [PATCH 5/5] Fix compilation issue with Visual Studio --- CHANGELOG.md | 3 ++- include/reactphysics3d/memory/DefaultAllocator.h | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 900a83b8..90f24e09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,8 @@ ### Changed - The library must now be compiled with C++ 17 compiler - - If the user sets its custom allocator, the return allocated memory must now be 16 bytes aligned + - If the user sets its own custom allocator, the return allocated memory must now be 16 bytes aligned + - The internal allocators now allocates memory that is 16-bytes aligned ### Removed diff --git a/include/reactphysics3d/memory/DefaultAllocator.h b/include/reactphysics3d/memory/DefaultAllocator.h index 727b07b2..521e684a 100644 --- a/include/reactphysics3d/memory/DefaultAllocator.h +++ b/include/reactphysics3d/memory/DefaultAllocator.h @@ -59,8 +59,8 @@ class DefaultAllocator : public MemoryAllocator { // If compiler is Visual Studio #ifdef RP3D_COMPILER_VISUAL_STUDIO - // Visual Studio doesn't not support standard std:aligned_alloc() method from c++ 17 - return _alligned_malloc(size, GLOBAL_ALIGNMENT); + // Visual Studio doesn't not support standard std:aligned_alloc() method from C++ 17 + return _aligned_malloc(size, GLOBAL_ALIGNMENT); #else // Return 16-bytes aligned memory @@ -75,7 +75,7 @@ class DefaultAllocator : public MemoryAllocator { #ifdef RP3D_COMPILER_VISUAL_STUDIO // Visual Studio doesn't not support standard std:aligned_alloc() method from c++ 17 - return _aligned_free(GLOBAL_ALIGNMENT, pointer); + return _aligned_free(pointer); #else return std::free(pointer);