From fe67f995cacec51cc07dc6760405f14558f13595 Mon Sep 17 00:00:00 2001 From: iiMidknightii <89699177+iiMidknightii@users.noreply.github.com> Date: Wed, 30 Apr 2025 08:06:47 -0700 Subject: [PATCH] Added aligned memory management methods --- gdextension/gdextension_interface.h | 39 +++++++++++++++++++++ include/godot_cpp/core/memory.hpp | 8 +++++ include/godot_cpp/godot.hpp | 4 +++ src/core/memory.cpp | 54 +++++++++++++++++++++++++++++ src/godot.cpp | 4 +++ 5 files changed, 109 insertions(+) diff --git a/gdextension/gdextension_interface.h b/gdextension/gdextension_interface.h index 107086fc9..bc905f52b 100644 --- a/gdextension/gdextension_interface.h +++ b/gdextension/gdextension_interface.h @@ -839,6 +839,45 @@ typedef void *(*GDExtensionInterfaceMemRealloc)(void *p_ptr, size_t p_bytes); */ typedef void (*GDExtensionInterfaceMemFree)(void *p_ptr); +// TODO: Uncomment if the approach is to add to the interface instead of a local implementation +// /** +// * @name mem_aligned_alloc +// * @since 4.5 +// * +// * Allocates memory aligned to user input +// * +// * @param p_bytes The amount of memory to allocate in bytes +// * @param p_align The alignment of the memory block to allocate to the nearest byte +// * +// * @return A pointer to the allocated aligned memory, or NULL if unsucessful +// */ +// typedef void *(*GDExtensionInterfaceMemAlignedAlloc)(size_t p_bytes, size_t p_align); + +// /** +// * @name mem_aligned_realloc +// * @since 4.5 +// * +// * Reallocates memory aligned to user input. +// * +// * @param p_ptr A pointer to the previously allocated aligned memory. +// * @param p_bytes The number of bytes to resize the memory block to. +// * @param p_prev_bytes The previous size of the memory block in bytes. +// * @param p_align The alignment of the memory block to allocate to the nearest byte. +// * +// * @return A pointer to the allocated aligned memory, or NULL if unsuccessful. +// */ +// typedef void *(*GDExtensionInterfaceMemAlignedRealloc)(void *p_ptr, size_t p_bytes, size_t p_prev_bytes, size_t p_align); + +// /** +// * @name mem_aligned_free +// * @since 4.5 +// * +// * Frees memory allocated with `mem_aligned_alloc`. +// * +// * @param p_ptr A pointer to the previously allocated aligned memory. +// */ +// typedef void (*GDExtensionInterfaceMemAlignedFree)(void *p_ptr); + /* INTERFACE: Godot Core */ /** diff --git a/include/godot_cpp/core/memory.hpp b/include/godot_cpp/core/memory.hpp index 917ccdede..cdac9e588 100644 --- a/include/godot_cpp/core/memory.hpp +++ b/include/godot_cpp/core/memory.hpp @@ -79,6 +79,10 @@ class Memory { static void *alloc_static(size_t p_bytes, bool p_pad_align = false); static void *realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align = false); static void free_static(void *p_ptr, bool p_pad_align = false); + + static void *alloc_aligned_static(size_t p_bytes, size_t p_alignment); + static void *realloc_aligned_static(void *p_memory, size_t p_bytes, size_t p_prev_bytes, size_t p_alignment); + static void free_aligned_static(void *p_ptr); }; template ::value, bool> = true> @@ -96,6 +100,10 @@ _ALWAYS_INLINE_ T *_post_initialize(T *p_obj) { #define memrealloc(m_mem, m_size) ::godot::Memory::realloc_static(m_mem, m_size) #define memfree(m_mem) ::godot::Memory::free_static(m_mem) +#define memalloc_aligned(m_size, m_alignment) ::godot::Memory::alloc_aligned_static(m_size, m_alignment) +#define memrealloc_aligned(m_mem, m_size, m_prev_size, m_alignment) ::godot::Memory::realloc_aligned_static(m_mem, m_size, m_prev_size, m_alignment) +#define memfree_aligned(m_mem) ::godot::Memory::free_aligned_static(m_mem) + #define memnew(m_class) (::godot::_pre_initialize>(), ::godot::_post_initialize(new ("", "") m_class)) #define memnew_allocator(m_class, m_allocator) (::godot::_pre_initialize>(), ::godot::_post_initialize(new ("", m_allocator::alloc) m_class)) diff --git a/include/godot_cpp/godot.hpp b/include/godot_cpp/godot.hpp index c0bf8aeee..a931d8b66 100644 --- a/include/godot_cpp/godot.hpp +++ b/include/godot_cpp/godot.hpp @@ -47,6 +47,10 @@ extern "C" GDExtensionInterfaceGetGodotVersion gdextension_interface_get_godot_v extern "C" GDExtensionInterfaceMemAlloc gdextension_interface_mem_alloc; extern "C" GDExtensionInterfaceMemRealloc gdextension_interface_mem_realloc; extern "C" GDExtensionInterfaceMemFree gdextension_interface_mem_free; +// TODO: Uncomment if the engine is updated to use this extended interface +// extern "C" GDExtensionInterfaceMemAlignedAlloc gdextension_interface_mem_aligned_alloc; +// extern "C" GDExtensionInterfaceMemAlignedRealloc gdextension_interface_mem_aligned_realloc; +// extern "C" GDExtensionInterfaceMemAlignedFree gdextension_interface_mem_aligned_free; extern "C" GDExtensionInterfacePrintError gdextension_interface_print_error; extern "C" GDExtensionInterfacePrintErrorWithMessage gdextension_interface_print_error_with_message; extern "C" GDExtensionInterfacePrintWarning gdextension_interface_print_warning; diff --git a/src/core/memory.cpp b/src/core/memory.cpp index fca794d21..706ba6a58 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -93,6 +93,60 @@ void Memory::free_static(void *p_ptr, bool p_pad_align) { internal::gdextension_interface_mem_free(mem); } +void *Memory::alloc_aligned_static(size_t p_bytes, size_t p_alignment) { + DEV_ASSERT(is_power_of_2(p_alignment)); + + void *p1, *p2; + if ((p1 = (void *)alloc_static(p_bytes + p_alignment - 1 + sizeof(uint32_t))) == nullptr) { + return nullptr; + } + + p2 = (void *)(((uintptr_t)p1 + sizeof(uint32_t) + p_alignment - 1) & ~((p_alignment)-1)); + *((uint32_t *)p2 - 1) = (uint32_t)((uintptr_t)p2 - (uintptr_t)p1); + return p2; + + // TODO: Alternate implementation if engine accepts this interface + // void *mem = internal::gdextension_interface_mem_aligned_alloc(p_bytes, p_alignment); + // ERR_FAIL_NULL_V(mem, nullptr); + // return mem; +} + +void *Memory::realloc_aligned_static(void *p_memory, size_t p_bytes, size_t p_prev_bytes, size_t p_alignment) { + DEV_ASSERT(is_power_of_2(p_alignment)); + + if (p_memory == nullptr) { + return alloc_aligned_static(p_bytes, p_alignment); + } + + void *ret = alloc_aligned_static(p_bytes, p_alignment); + if (ret) { + memcpy(ret, p_memory, p_prev_bytes); + } + free_aligned_static(p_memory); + return ret; + + // TODO: Alternate implementation if engine accepts this interface + // if (p_memory == nullptr) { + // return alloc_aligned_static(p_bytes, p_alignment); + // } else if (p_bytes == 0) { + // free_aligned_static(p_memory); + // return nullptr; + // } + + // void *mem = internal::gdextension_interface_mem_aligned_realloc(p_memory, p_bytes, p_prev_bytes, p_alignment); + // ERR_FAIL_NULL_V(mem, nullptr); + // return mem; +} + +void Memory::free_aligned_static(void *p_ptr) { + uint32_t offset = *((uint32_t *)p_ptr - 1); + void *p = (void *)((uint8_t *)p_ptr - offset); + free_static(p); + + // TODO: Alternate implementation if engine accepts this interface + // internal::gdextension_interface_mem_aligned_free(p_ptr); +} + _GlobalNil::_GlobalNil() { left = this; right = this; diff --git a/src/godot.cpp b/src/godot.cpp index add05e14d..339921d65 100644 --- a/src/godot.cpp +++ b/src/godot.cpp @@ -54,6 +54,10 @@ GDExtensionInterfaceGetGodotVersion gdextension_interface_get_godot_version = nu GDExtensionInterfaceMemAlloc gdextension_interface_mem_alloc = nullptr; GDExtensionInterfaceMemRealloc gdextension_interface_mem_realloc = nullptr; GDExtensionInterfaceMemFree gdextension_interface_mem_free = nullptr; +// TODO: Uncomment if the engine is updated to use this extended interface +// GDExtensionInterfaceMemAlignedAlloc gdextension_interface_mem_aligned_alloc = nullptr; +// GDExtensionInterfaceMemAlignedRealloc gdextension_interface_mem_aligned_realloc = nullptr; +// GDExtensionInterfaceMemAlignedFree gdextension_interface_mem_aligned_free = nullptr; GDExtensionInterfacePrintError gdextension_interface_print_error = nullptr; GDExtensionInterfacePrintErrorWithMessage gdextension_interface_print_error_with_message = nullptr; GDExtensionInterfacePrintWarning gdextension_interface_print_warning = nullptr;