Skip to content

Commit a8453cb

Browse files
authored
Merge pull request #76406 from dsnopek/gdextension-interface
Rework GDExtension interface from a struct to loading function pointers
2 parents 755c61b + 9b9482d commit a8453cb

File tree

5 files changed

+2238
-438
lines changed

5 files changed

+2238
-438
lines changed

core/extension/gdextension.cpp

Lines changed: 84 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@
3434
#include "core/object/class_db.h"
3535
#include "core/object/method_bind.h"
3636
#include "core/os/os.h"
37+
#include "core/version.h"
38+
39+
extern void gdextension_setup_interface();
40+
extern void *gdextension_get_legacy_interface();
41+
extern GDExtensionInterfaceFunctionPtr gdextension_get_proc_address(const char *p_name);
42+
43+
typedef GDExtensionBool (*GDExtensionLegacyInitializationFunction)(void *p_interface, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization);
3744

3845
String GDExtension::get_extension_list_config_file() {
3946
return ProjectSettings::get_singleton()->get_project_data_path().path_join("extension_list.cfg");
@@ -275,8 +282,6 @@ class GDExtensionMethodBind : public MethodBind {
275282
}
276283
};
277284

278-
static GDExtensionInterface gdextension_interface;
279-
280285
void GDExtension::_register_extension_class(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo *p_extension_funcs) {
281286
GDExtension *self = reinterpret_cast<GDExtension *>(p_library);
282287

@@ -431,7 +436,20 @@ void GDExtension::_get_library_path(GDExtensionClassLibraryPtr p_library, GDExte
431436
memnew_placement(r_path, String(self->library_path));
432437
}
433438

434-
Error GDExtension::open_library(const String &p_path, const String &p_entry_symbol) {
439+
HashMap<StringName, GDExtensionInterfaceFunctionPtr> gdextension_interface_functions;
440+
441+
void GDExtension::register_interface_function(StringName p_function_name, GDExtensionInterfaceFunctionPtr p_function_pointer) {
442+
ERR_FAIL_COND_MSG(gdextension_interface_functions.has(p_function_name), "Attempt to register interface function '" + p_function_name + "', which appears to be already registered.");
443+
gdextension_interface_functions.insert(p_function_name, p_function_pointer);
444+
}
445+
446+
GDExtensionInterfaceFunctionPtr GDExtension::get_interface_function(StringName p_function_name) {
447+
GDExtensionInterfaceFunctionPtr *function = gdextension_interface_functions.getptr(p_function_name);
448+
ERR_FAIL_COND_V_MSG(function == nullptr, nullptr, "Attempt to get non-existent interface function: " + p_function_name);
449+
return *function;
450+
}
451+
452+
Error GDExtension::open_library(const String &p_path, const String &p_entry_symbol, bool p_use_legacy_interface) {
435453
Error err = OS::get_singleton()->open_dynamic_library(p_path, library, true, &library_path);
436454
if (err != OK) {
437455
ERR_PRINT("GDExtension dynamic library not found: " + p_path);
@@ -448,9 +466,17 @@ Error GDExtension::open_library(const String &p_path, const String &p_entry_symb
448466
return err;
449467
}
450468

451-
GDExtensionInitializationFunction initialization_function = (GDExtensionInitializationFunction)entry_funcptr;
469+
GDExtensionBool ret = 0;
470+
if (p_use_legacy_interface) {
471+
GDExtensionLegacyInitializationFunction initialization_function = (GDExtensionLegacyInitializationFunction)entry_funcptr;
472+
ret = initialization_function(gdextension_get_legacy_interface(), this, &initialization);
473+
474+
} else {
475+
GDExtensionInitializationFunction initialization_function = (GDExtensionInitializationFunction)entry_funcptr;
476+
ret = initialization_function(&gdextension_get_proc_address, this, &initialization);
477+
}
452478

453-
if (initialization_function(&gdextension_interface, this, &initialization)) {
479+
if (ret) {
454480
level_initialized = -1;
455481
return OK;
456482
} else {
@@ -459,6 +485,10 @@ Error GDExtension::open_library(const String &p_path, const String &p_entry_symb
459485
}
460486
}
461487

488+
Error GDExtension::open_library_compat_76406(const String &p_path, const String &p_entry_symbol) {
489+
return open_library(p_path, p_entry_symbol, true);
490+
}
491+
462492
void GDExtension::close_library() {
463493
ERR_FAIL_COND(library == nullptr);
464494
OS::get_singleton()->close_dynamic_library(library);
@@ -494,7 +524,8 @@ void GDExtension::deinitialize_library(InitializationLevel p_level) {
494524
}
495525

496526
void GDExtension::_bind_methods() {
497-
ClassDB::bind_method(D_METHOD("open_library", "path", "entry_symbol"), &GDExtension::open_library);
527+
ClassDB::bind_method(D_METHOD("open_library", "path", "entry_symbol", "use_legacy_interface"), &GDExtension::open_library);
528+
ClassDB::bind_compatibility_method(D_METHOD("open_library", "path", "entry_symbol"), &GDExtension::open_library_compat_76406);
498529
ClassDB::bind_method(D_METHOD("close_library"), &GDExtension::close_library);
499530
ClassDB::bind_method(D_METHOD("is_library_open"), &GDExtension::is_library_open);
500531

@@ -516,20 +547,18 @@ GDExtension::~GDExtension() {
516547
}
517548
}
518549

519-
extern void gdextension_setup_interface(GDExtensionInterface *p_interface);
520-
521550
void GDExtension::initialize_gdextensions() {
522-
gdextension_setup_interface(&gdextension_interface);
523-
524-
gdextension_interface.classdb_register_extension_class = _register_extension_class;
525-
gdextension_interface.classdb_register_extension_class_method = _register_extension_class_method;
526-
gdextension_interface.classdb_register_extension_class_integer_constant = _register_extension_class_integer_constant;
527-
gdextension_interface.classdb_register_extension_class_property = _register_extension_class_property;
528-
gdextension_interface.classdb_register_extension_class_property_group = _register_extension_class_property_group;
529-
gdextension_interface.classdb_register_extension_class_property_subgroup = _register_extension_class_property_subgroup;
530-
gdextension_interface.classdb_register_extension_class_signal = _register_extension_class_signal;
531-
gdextension_interface.classdb_unregister_extension_class = _unregister_extension_class;
532-
gdextension_interface.get_library_path = _get_library_path;
551+
gdextension_setup_interface();
552+
553+
register_interface_function("classdb_register_extension_class", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class);
554+
register_interface_function("classdb_register_extension_class_method", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_method);
555+
register_interface_function("classdb_register_extension_class_integer_constant", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_integer_constant);
556+
register_interface_function("classdb_register_extension_class_property", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_property);
557+
register_interface_function("classdb_register_extension_class_property_group", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_property_group);
558+
register_interface_function("classdb_register_extension_class_property_subgroup", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_property_subgroup);
559+
register_interface_function("classdb_register_extension_class_signal", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_signal);
560+
register_interface_function("classdb_unregister_extension_class", (GDExtensionInterfaceFunctionPtr)&GDExtension::_unregister_extension_class);
561+
register_interface_function("get_library_path", (GDExtensionInterfaceFunctionPtr)&GDExtension::_get_library_path);
533562
}
534563

535564
Ref<Resource> GDExtensionResourceLoader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
@@ -557,6 +586,39 @@ Ref<Resource> GDExtensionResourceLoader::load(const String &p_path, const String
557586

558587
String entry_symbol = config->get_value("configuration", "entry_symbol");
559588

589+
uint32_t compatibility_minimum[3] = { 0, 0, 0 };
590+
if (config->has_section_key("configuration", "compatibility_minimum")) {
591+
String compat_string = config->get_value("configuration", "compatibility_minimum");
592+
Vector<int> parts = compat_string.split_ints(".");
593+
for (int i = 0; i < parts.size(); i++) {
594+
if (i >= 3) {
595+
break;
596+
}
597+
if (parts[i] >= 0) {
598+
compatibility_minimum[i] = parts[i];
599+
}
600+
}
601+
}
602+
if (compatibility_minimum[0] < 4) {
603+
compatibility_minimum[0] = 4;
604+
}
605+
606+
bool compatible = true;
607+
if (VERSION_MAJOR < compatibility_minimum[0]) {
608+
compatible = false;
609+
} else if (VERSION_MINOR < compatibility_minimum[1]) {
610+
compatible = false;
611+
} else if (VERSION_PATCH < compatibility_minimum[2]) {
612+
compatible = false;
613+
}
614+
if (!compatible) {
615+
if (r_error) {
616+
*r_error = ERR_INVALID_DATA;
617+
}
618+
ERR_PRINT(vformat("GDExtension only compatible with Godot version %d.%d.%d or later: %s", compatibility_minimum[0], compatibility_minimum[1], compatibility_minimum[2], p_path));
619+
return Ref<Resource>();
620+
}
621+
560622
String library_path = GDExtension::find_extension_library(p_path, config, [](String p_feature) { return OS::get_singleton()->has_feature(p_feature); });
561623

562624
if (library_path.is_empty()) {
@@ -572,10 +634,12 @@ Ref<Resource> GDExtensionResourceLoader::load(const String &p_path, const String
572634
library_path = p_path.get_base_dir().path_join(library_path);
573635
}
574636

637+
bool use_legacy_interface = compatibility_minimum[0] == 4 && compatibility_minimum[1] == 0;
638+
575639
Ref<GDExtension> lib;
576640
lib.instantiate();
577641
String abs_path = ProjectSettings::get_singleton()->globalize_path(library_path);
578-
err = lib->open_library(abs_path, entry_symbol);
642+
err = lib->open_library(abs_path, entry_symbol, use_legacy_interface);
579643

580644
if (r_error) {
581645
*r_error = err;

core/extension/gdextension.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ class GDExtension : public Resource {
7272
static String get_extension_list_config_file();
7373
static String find_extension_library(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature, PackedStringArray *r_tags = nullptr);
7474

75-
Error open_library(const String &p_path, const String &p_entry_symbol);
75+
Error open_library(const String &p_path, const String &p_entry_symbol, bool p_use_legacy_interface = false);
76+
Error open_library_compat_76406(const String &p_path, const String &p_entry_symbol);
7677
void close_library();
7778

7879
enum InitializationLevel {
@@ -88,7 +89,10 @@ class GDExtension : public Resource {
8889
void initialize_library(InitializationLevel p_level);
8990
void deinitialize_library(InitializationLevel p_level);
9091

92+
static void register_interface_function(StringName p_function_name, GDExtensionInterfaceFunctionPtr p_function_pointer);
93+
static GDExtensionInterfaceFunctionPtr get_interface_function(StringName p_function_name);
9194
static void initialize_gdextensions();
95+
9296
GDExtension();
9397
~GDExtension();
9498
};

0 commit comments

Comments
 (0)