[iOS] Fix initialisation/termination of multiple statically linked extensions.
(cherry picked from commit adc9def046
)
pull/1373/head
parent
92449b46e1
commit
b622b11df3
|
@ -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);
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (level_initialized[p_level] == 0) {
|
||||||
ClassDB::initialize(p_level);
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
level_initialized[p_level]--;
|
||||||
|
if (level_initialized[p_level] == 0) {
|
||||||
EditorPlugins::deinitialize(p_level);
|
EditorPlugins::deinitialize(p_level);
|
||||||
ClassDB::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
|
||||||
|
|
Loading…
Reference in New Issue