Skip to content

Added aligned memory management methods #1778

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions gdextension/gdextension_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

/**
Expand Down
8 changes: 8 additions & 0 deletions include/godot_cpp/core/memory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename T, std::enable_if_t<!std::is_base_of<::godot::Wrapped, T>::value, bool> = true>
Expand All @@ -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<std::remove_pointer_t<decltype(new ("", "") m_class)>>(), ::godot::_post_initialize(new ("", "") m_class))

#define memnew_allocator(m_class, m_allocator) (::godot::_pre_initialize<std::remove_pointer_t<decltype(new ("", "") m_class)>>(), ::godot::_post_initialize(new ("", m_allocator::alloc) m_class))
Expand Down
4 changes: 4 additions & 0 deletions include/godot_cpp/godot.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
54 changes: 54 additions & 0 deletions src/core/memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions src/godot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down