summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRémi Verschelde <rverschelde@gmail.com>2023-11-24 09:23:42 +0100
committerGitHub <noreply@github.com>2023-11-24 09:23:42 +0100
commit2f16eddf153fd392cad0d2a1ed261da54702404b (patch)
tree4f4a7355a5037662c8570e90663d8c7d347657fe
parent32409472b785fd6f9062300664fa55b46bfd07e7 (diff)
parentadc9def046b1f871d58163adc959e78db131324a (diff)
downloadredot-cpp-2f16eddf153fd392cad0d2a1ed261da54702404b.tar.gz
Merge pull request #1316 from bruvzg/static_multiple_init
[iOS] Fix initialisation/termination of multiple statically linked extensions.
-rw-r--r--include/godot_cpp/godot.hpp32
-rw-r--r--src/godot.cpp90
2 files changed, 95 insertions, 27 deletions
diff --git a/include/godot_cpp/godot.hpp b/include/godot_cpp/godot.hpp
index d2184a4..c9e9022 100644
--- a/include/godot_cpp/godot.hpp
+++ b/include/godot_cpp/godot.hpp
@@ -194,26 +194,44 @@ enum ModuleInitializationLevel {
MODULE_INITIALIZATION_LEVEL_CORE = GDEXTENSION_INITIALIZATION_CORE,
MODULE_INITIALIZATION_LEVEL_SERVERS = GDEXTENSION_INITIALIZATION_SERVERS,
MODULE_INITIALIZATION_LEVEL_SCENE = GDEXTENSION_INITIALIZATION_SCENE,
- MODULE_INITIALIZATION_LEVEL_EDITOR = GDEXTENSION_INITIALIZATION_EDITOR
+ MODULE_INITIALIZATION_LEVEL_EDITOR = GDEXTENSION_INITIALIZATION_EDITOR,
+ MODULE_INITIALIZATION_LEVEL_MAX
};
class GDExtensionBinding {
public:
using Callback = void (*)(ModuleInitializationLevel p_level);
- static Callback init_callback;
- static Callback terminate_callback;
- static GDExtensionInitializationLevel minimum_initialization_level;
- static GDExtensionBool init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization);
+ struct InitData {
+ GDExtensionInitializationLevel minimum_initialization_level = GDEXTENSION_INITIALIZATION_CORE;
+ Callback init_callback = nullptr;
+ Callback terminate_callback = nullptr;
+ };
+
+ class InitDataList {
+ int data_count = 0;
+ int data_capacity = 0;
+ InitData **data = nullptr;
+
+ public:
+ void add(InitData *p_cb);
+ ~InitDataList();
+ };
+
+ static bool api_initialized;
+ static int level_initialized[MODULE_INITIALIZATION_LEVEL_MAX];
+ static InitDataList initdata;
+ static GDExtensionBool init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, InitData *p_init_data, GDExtensionInitialization *r_initialization);
public:
- static void initialize_level(void *userdata, GDExtensionInitializationLevel p_level);
- static void deinitialize_level(void *userdata, GDExtensionInitializationLevel p_level);
+ static void initialize_level(void *p_userdata, GDExtensionInitializationLevel p_level);
+ static void deinitialize_level(void *p_userdata, GDExtensionInitializationLevel p_level);
class InitObject {
GDExtensionInterfaceGetProcAddress get_proc_address;
GDExtensionClassLibraryPtr library;
GDExtensionInitialization *initialization;
+ mutable InitData *init_data = nullptr;
public:
InitObject(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization);
diff --git a/src/godot.cpp b/src/godot.cpp
index 70c5978..ee4156b 100644
--- a/src/godot.cpp
+++ b/src/godot.cpp
@@ -196,9 +196,9 @@ GDExtensionInterfaceEditorRemovePlugin gdextension_interface_editor_remove_plugi
} // namespace internal
-GDExtensionBinding::Callback GDExtensionBinding::init_callback = nullptr;
-GDExtensionBinding::Callback GDExtensionBinding::terminate_callback = nullptr;
-GDExtensionInitializationLevel GDExtensionBinding::minimum_initialization_level = GDEXTENSION_INITIALIZATION_CORE;
+bool GDExtensionBinding::api_initialized = false;
+int GDExtensionBinding::level_initialized[MODULE_INITIALIZATION_LEVEL_MAX] = { 0 };
+GDExtensionBinding::InitDataList GDExtensionBinding::initdata;
#define ERR_PRINT_EARLY(m_msg) \
internal::gdextension_interface_print_error(m_msg, FUNCTION_STR, __FILE__, __LINE__, false)
@@ -225,7 +225,20 @@ typedef struct {
GDExtensionInterfacePrintErrorWithMessage print_error_with_message;
} LegacyGDExtensionInterface;
-GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
+GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, InitData *p_init_data, GDExtensionInitialization *r_initialization) {
+ if (!p_init_data || !p_init_data->init_callback) {
+ ERR_FAIL_V_MSG(false, "Initialization callback must be defined.");
+ }
+
+ if (api_initialized) {
+ r_initialization->initialize = initialize_level;
+ r_initialization->deinitialize = deinitialize_level;
+ r_initialization->userdata = p_init_data;
+ r_initialization->minimum_initialization_level = p_init_data->minimum_initialization_level;
+
+ return true;
+ }
+
// Make sure we weren't passed the legacy struct.
uint32_t *raw_interface = (uint32_t *)(void *)p_get_proc_address;
if (raw_interface[0] == 4 && raw_interface[1] == 0) {
@@ -415,59 +428,96 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
r_initialization->initialize = initialize_level;
r_initialization->deinitialize = deinitialize_level;
- r_initialization->minimum_initialization_level = minimum_initialization_level;
-
- ERR_FAIL_NULL_V_MSG(init_callback, false, "Initialization callback must be defined.");
+ r_initialization->userdata = p_init_data;
+ r_initialization->minimum_initialization_level = p_init_data->minimum_initialization_level;
Variant::init_bindings();
godot::internal::register_engine_classes();
+ api_initialized = true;
return true;
}
#undef LOAD_PROC_ADDRESS
#undef ERR_PRINT_EARLY
-void GDExtensionBinding::initialize_level(void *userdata, GDExtensionInitializationLevel p_level) {
+void GDExtensionBinding::initialize_level(void *p_userdata, GDExtensionInitializationLevel p_level) {
+ ERR_FAIL_COND(static_cast<ModuleInitializationLevel>(p_level) >= MODULE_INITIALIZATION_LEVEL_MAX);
ClassDB::current_level = p_level;
- if (init_callback) {
- init_callback(static_cast<ModuleInitializationLevel>(p_level));
+ InitData *init_data = static_cast<InitData *>(p_userdata);
+ if (init_data && init_data->init_callback) {
+ init_data->init_callback(static_cast<ModuleInitializationLevel>(p_level));
}
- ClassDB::initialize(p_level);
+ if (level_initialized[p_level] == 0) {
+ ClassDB::initialize(p_level);
+ }
+ level_initialized[p_level]++;
}
-void GDExtensionBinding::deinitialize_level(void *userdata, GDExtensionInitializationLevel p_level) {
+void GDExtensionBinding::deinitialize_level(void *p_userdata, GDExtensionInitializationLevel p_level) {
+ ERR_FAIL_COND(static_cast<ModuleInitializationLevel>(p_level) >= MODULE_INITIALIZATION_LEVEL_MAX);
ClassDB::current_level = p_level;
- if (terminate_callback) {
- terminate_callback(static_cast<ModuleInitializationLevel>(p_level));
+ InitData *init_data = static_cast<InitData *>(p_userdata);
+ if (init_data && init_data->terminate_callback) {
+ init_data->terminate_callback(static_cast<ModuleInitializationLevel>(p_level));
+ }
+
+ level_initialized[p_level]--;
+ if (level_initialized[p_level] == 0) {
+ EditorPlugins::deinitialize(p_level);
+ ClassDB::deinitialize(p_level);
+ }
+}
+
+void GDExtensionBinding::InitDataList::add(InitData *p_data) {
+ if (data_count == data_capacity) {
+ void *new_ptr = realloc(data, sizeof(InitData *) * (data_capacity + 32));
+ if (new_ptr) {
+ data = (InitData **)(new_ptr);
+ data_capacity += 32;
+ } else {
+ ERR_FAIL_MSG("Unable to allocate memory for extension callbacks.");
+ }
}
+ data[data_count++] = p_data;
+}
- EditorPlugins::deinitialize(p_level);
- ClassDB::deinitialize(p_level);
+GDExtensionBinding::InitDataList::~InitDataList() {
+ for (int i = 0; i < data_count; i++) {
+ if (data[i]) {
+ delete data[i];
+ }
+ }
+ if (data) {
+ free(data);
+ }
}
+
GDExtensionBinding::InitObject::InitObject(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
get_proc_address = p_get_proc_address;
library = p_library;
initialization = r_initialization;
+ init_data = new InitData();
+ GDExtensionBinding::initdata.add(init_data);
}
void GDExtensionBinding::InitObject::register_initializer(Callback p_init) const {
- GDExtensionBinding::init_callback = p_init;
+ init_data->init_callback = p_init;
}
void GDExtensionBinding::InitObject::register_terminator(Callback p_terminate) const {
- GDExtensionBinding::terminate_callback = p_terminate;
+ init_data->terminate_callback = p_terminate;
}
void GDExtensionBinding::InitObject::set_minimum_library_initialization_level(ModuleInitializationLevel p_level) const {
- GDExtensionBinding::minimum_initialization_level = static_cast<GDExtensionInitializationLevel>(p_level);
+ init_data->minimum_initialization_level = static_cast<GDExtensionInitializationLevel>(p_level);
}
GDExtensionBool GDExtensionBinding::InitObject::init() const {
- return GDExtensionBinding::init(get_proc_address, library, initialization);
+ return GDExtensionBinding::init(get_proc_address, library, init_data, initialization);
}
} // namespace godot