[iOS] Fix initialisation/termination of multiple statically linked extensions.

(cherry picked from commit adc9def046)
pull/1373/head
bruvzg 2023-11-22 14:14:41 +02:00 committed by David Snopek
parent 92449b46e1
commit b622b11df3
2 changed files with 95 additions and 27 deletions

View File

@ -187,26 +187,44 @@ enum ModuleInitializationLevel {
MODULE_INITIALIZATION_LEVEL_CORE = GDEXTENSION_INITIALIZATION_CORE, MODULE_INITIALIZATION_LEVEL_CORE = GDEXTENSION_INITIALIZATION_CORE,
MODULE_INITIALIZATION_LEVEL_SERVERS = GDEXTENSION_INITIALIZATION_SERVERS, MODULE_INITIALIZATION_LEVEL_SERVERS = GDEXTENSION_INITIALIZATION_SERVERS,
MODULE_INITIALIZATION_LEVEL_SCENE = GDEXTENSION_INITIALIZATION_SCENE, 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 { class GDExtensionBinding {
public: public:
using Callback = void (*)(ModuleInitializationLevel p_level); using Callback = void (*)(ModuleInitializationLevel p_level);
static Callback init_callback; struct InitData {
static Callback terminate_callback; GDExtensionInitializationLevel minimum_initialization_level = GDEXTENSION_INITIALIZATION_CORE;
static GDExtensionInitializationLevel minimum_initialization_level; Callback init_callback = nullptr;
static GDExtensionBool init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization); 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: public:
static void initialize_level(void *userdata, GDExtensionInitializationLevel p_level); static void initialize_level(void *p_userdata, GDExtensionInitializationLevel p_level);
static void deinitialize_level(void *userdata, GDExtensionInitializationLevel p_level); static void deinitialize_level(void *p_userdata, GDExtensionInitializationLevel p_level);
class InitObject { class InitObject {
GDExtensionInterfaceGetProcAddress get_proc_address; GDExtensionInterfaceGetProcAddress get_proc_address;
GDExtensionClassLibraryPtr library; GDExtensionClassLibraryPtr library;
GDExtensionInitialization *initialization; GDExtensionInitialization *initialization;
mutable InitData *init_data = nullptr;
public: public:
InitObject(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization); InitObject(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization);

View File

@ -189,9 +189,9 @@ GDExtensionInterfaceEditorRemovePlugin gdextension_interface_editor_remove_plugi
} // namespace internal } // namespace internal
GDExtensionBinding::Callback GDExtensionBinding::init_callback = nullptr; bool GDExtensionBinding::api_initialized = false;
GDExtensionBinding::Callback GDExtensionBinding::terminate_callback = nullptr; int GDExtensionBinding::level_initialized[MODULE_INITIALIZATION_LEVEL_MAX] = { 0 };
GDExtensionInitializationLevel GDExtensionBinding::minimum_initialization_level = GDEXTENSION_INITIALIZATION_CORE; GDExtensionBinding::InitDataList GDExtensionBinding::initdata;
#define ERR_PRINT_EARLY(m_msg) \ #define ERR_PRINT_EARLY(m_msg) \
internal::gdextension_interface_print_error(m_msg, FUNCTION_STR, __FILE__, __LINE__, false) internal::gdextension_interface_print_error(m_msg, FUNCTION_STR, __FILE__, __LINE__, false)
@ -218,7 +218,20 @@ typedef struct {
GDExtensionInterfacePrintErrorWithMessage print_error_with_message; GDExtensionInterfacePrintErrorWithMessage print_error_with_message;
} LegacyGDExtensionInterface; } 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. // Make sure we weren't passed the legacy struct.
uint32_t *raw_interface = (uint32_t *)(void *)p_get_proc_address; uint32_t *raw_interface = (uint32_t *)(void *)p_get_proc_address;
if (raw_interface[0] == 4 && raw_interface[1] == 0) { if (raw_interface[0] == 4 && raw_interface[1] == 0) {
@ -401,59 +414,96 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
r_initialization->initialize = initialize_level; r_initialization->initialize = initialize_level;
r_initialization->deinitialize = deinitialize_level; r_initialization->deinitialize = deinitialize_level;
r_initialization->minimum_initialization_level = minimum_initialization_level; r_initialization->userdata = p_init_data;
r_initialization->minimum_initialization_level = p_init_data->minimum_initialization_level;
ERR_FAIL_NULL_V_MSG(init_callback, false, "Initialization callback must be defined.");
Variant::init_bindings(); Variant::init_bindings();
godot::internal::register_engine_classes(); godot::internal::register_engine_classes();
api_initialized = true;
return true; return true;
} }
#undef LOAD_PROC_ADDRESS #undef LOAD_PROC_ADDRESS
#undef ERR_PRINT_EARLY #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; ClassDB::current_level = p_level;
if (init_callback) { InitData *init_data = static_cast<InitData *>(p_userdata);
init_callback(static_cast<ModuleInitializationLevel>(p_level)); 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; ClassDB::current_level = p_level;
if (terminate_callback) { InitData *init_data = static_cast<InitData *>(p_userdata);
terminate_callback(static_cast<ModuleInitializationLevel>(p_level)); if (init_data && init_data->terminate_callback) {
init_data->terminate_callback(static_cast<ModuleInitializationLevel>(p_level));
} }
EditorPlugins::deinitialize(p_level); level_initialized[p_level]--;
ClassDB::deinitialize(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;
}
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) { GDExtensionBinding::InitObject::InitObject(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
get_proc_address = p_get_proc_address; get_proc_address = p_get_proc_address;
library = p_library; library = p_library;
initialization = r_initialization; initialization = r_initialization;
init_data = new InitData();
GDExtensionBinding::initdata.add(init_data);
} }
void GDExtensionBinding::InitObject::register_initializer(Callback p_init) const { 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 { 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 { 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 { 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 } // namespace godot