Skip to content

Commit

Permalink
Merge pull request #76406 from dsnopek/gdextension-interface
Browse files Browse the repository at this point in the history
Rework GDExtension interface from a struct to loading function pointers
  • Loading branch information
akien-mga authored May 16, 2023
2 parents 755c61b + 9b9482d commit a8453cb
Show file tree
Hide file tree
Showing 5 changed files with 2,238 additions and 438 deletions.
104 changes: 84 additions & 20 deletions core/extension/gdextension.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@
#include "core/object/class_db.h"
#include "core/object/method_bind.h"
#include "core/os/os.h"
#include "core/version.h"

extern void gdextension_setup_interface();
extern void *gdextension_get_legacy_interface();
extern GDExtensionInterfaceFunctionPtr gdextension_get_proc_address(const char *p_name);

typedef GDExtensionBool (*GDExtensionLegacyInitializationFunction)(void *p_interface, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization);

String GDExtension::get_extension_list_config_file() {
return ProjectSettings::get_singleton()->get_project_data_path().path_join("extension_list.cfg");
Expand Down Expand Up @@ -275,8 +282,6 @@ class GDExtensionMethodBind : public MethodBind {
}
};

static GDExtensionInterface gdextension_interface;

void GDExtension::_register_extension_class(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo *p_extension_funcs) {
GDExtension *self = reinterpret_cast<GDExtension *>(p_library);

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

Error GDExtension::open_library(const String &p_path, const String &p_entry_symbol) {
HashMap<StringName, GDExtensionInterfaceFunctionPtr> gdextension_interface_functions;

void GDExtension::register_interface_function(StringName p_function_name, GDExtensionInterfaceFunctionPtr p_function_pointer) {
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.");
gdextension_interface_functions.insert(p_function_name, p_function_pointer);
}

GDExtensionInterfaceFunctionPtr GDExtension::get_interface_function(StringName p_function_name) {
GDExtensionInterfaceFunctionPtr *function = gdextension_interface_functions.getptr(p_function_name);
ERR_FAIL_COND_V_MSG(function == nullptr, nullptr, "Attempt to get non-existent interface function: " + p_function_name);
return *function;
}

Error GDExtension::open_library(const String &p_path, const String &p_entry_symbol, bool p_use_legacy_interface) {
Error err = OS::get_singleton()->open_dynamic_library(p_path, library, true, &library_path);
if (err != OK) {
ERR_PRINT("GDExtension dynamic library not found: " + p_path);
Expand All @@ -448,9 +466,17 @@ Error GDExtension::open_library(const String &p_path, const String &p_entry_symb
return err;
}

GDExtensionInitializationFunction initialization_function = (GDExtensionInitializationFunction)entry_funcptr;
GDExtensionBool ret = 0;
if (p_use_legacy_interface) {
GDExtensionLegacyInitializationFunction initialization_function = (GDExtensionLegacyInitializationFunction)entry_funcptr;
ret = initialization_function(gdextension_get_legacy_interface(), this, &initialization);

} else {
GDExtensionInitializationFunction initialization_function = (GDExtensionInitializationFunction)entry_funcptr;
ret = initialization_function(&gdextension_get_proc_address, this, &initialization);
}

if (initialization_function(&gdextension_interface, this, &initialization)) {
if (ret) {
level_initialized = -1;
return OK;
} else {
Expand All @@ -459,6 +485,10 @@ Error GDExtension::open_library(const String &p_path, const String &p_entry_symb
}
}

Error GDExtension::open_library_compat_76406(const String &p_path, const String &p_entry_symbol) {
return open_library(p_path, p_entry_symbol, true);
}

void GDExtension::close_library() {
ERR_FAIL_COND(library == nullptr);
OS::get_singleton()->close_dynamic_library(library);
Expand Down Expand Up @@ -494,7 +524,8 @@ void GDExtension::deinitialize_library(InitializationLevel p_level) {
}

void GDExtension::_bind_methods() {
ClassDB::bind_method(D_METHOD("open_library", "path", "entry_symbol"), &GDExtension::open_library);
ClassDB::bind_method(D_METHOD("open_library", "path", "entry_symbol", "use_legacy_interface"), &GDExtension::open_library);
ClassDB::bind_compatibility_method(D_METHOD("open_library", "path", "entry_symbol"), &GDExtension::open_library_compat_76406);
ClassDB::bind_method(D_METHOD("close_library"), &GDExtension::close_library);
ClassDB::bind_method(D_METHOD("is_library_open"), &GDExtension::is_library_open);

Expand All @@ -516,20 +547,18 @@ GDExtension::~GDExtension() {
}
}

extern void gdextension_setup_interface(GDExtensionInterface *p_interface);

void GDExtension::initialize_gdextensions() {
gdextension_setup_interface(&gdextension_interface);

gdextension_interface.classdb_register_extension_class = _register_extension_class;
gdextension_interface.classdb_register_extension_class_method = _register_extension_class_method;
gdextension_interface.classdb_register_extension_class_integer_constant = _register_extension_class_integer_constant;
gdextension_interface.classdb_register_extension_class_property = _register_extension_class_property;
gdextension_interface.classdb_register_extension_class_property_group = _register_extension_class_property_group;
gdextension_interface.classdb_register_extension_class_property_subgroup = _register_extension_class_property_subgroup;
gdextension_interface.classdb_register_extension_class_signal = _register_extension_class_signal;
gdextension_interface.classdb_unregister_extension_class = _unregister_extension_class;
gdextension_interface.get_library_path = _get_library_path;
gdextension_setup_interface();

register_interface_function("classdb_register_extension_class", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class);
register_interface_function("classdb_register_extension_class_method", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_method);
register_interface_function("classdb_register_extension_class_integer_constant", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_integer_constant);
register_interface_function("classdb_register_extension_class_property", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_property);
register_interface_function("classdb_register_extension_class_property_group", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_property_group);
register_interface_function("classdb_register_extension_class_property_subgroup", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_property_subgroup);
register_interface_function("classdb_register_extension_class_signal", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_signal);
register_interface_function("classdb_unregister_extension_class", (GDExtensionInterfaceFunctionPtr)&GDExtension::_unregister_extension_class);
register_interface_function("get_library_path", (GDExtensionInterfaceFunctionPtr)&GDExtension::_get_library_path);
}

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) {
Expand Down Expand Up @@ -557,6 +586,39 @@ Ref<Resource> GDExtensionResourceLoader::load(const String &p_path, const String

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

uint32_t compatibility_minimum[3] = { 0, 0, 0 };
if (config->has_section_key("configuration", "compatibility_minimum")) {
String compat_string = config->get_value("configuration", "compatibility_minimum");
Vector<int> parts = compat_string.split_ints(".");
for (int i = 0; i < parts.size(); i++) {
if (i >= 3) {
break;
}
if (parts[i] >= 0) {
compatibility_minimum[i] = parts[i];
}
}
}
if (compatibility_minimum[0] < 4) {
compatibility_minimum[0] = 4;
}

bool compatible = true;
if (VERSION_MAJOR < compatibility_minimum[0]) {
compatible = false;
} else if (VERSION_MINOR < compatibility_minimum[1]) {
compatible = false;
} else if (VERSION_PATCH < compatibility_minimum[2]) {
compatible = false;
}
if (!compatible) {
if (r_error) {
*r_error = ERR_INVALID_DATA;
}
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));
return Ref<Resource>();
}

String library_path = GDExtension::find_extension_library(p_path, config, [](String p_feature) { return OS::get_singleton()->has_feature(p_feature); });

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

bool use_legacy_interface = compatibility_minimum[0] == 4 && compatibility_minimum[1] == 0;

Ref<GDExtension> lib;
lib.instantiate();
String abs_path = ProjectSettings::get_singleton()->globalize_path(library_path);
err = lib->open_library(abs_path, entry_symbol);
err = lib->open_library(abs_path, entry_symbol, use_legacy_interface);

if (r_error) {
*r_error = err;
Expand Down
6 changes: 5 additions & 1 deletion core/extension/gdextension.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ class GDExtension : public Resource {
static String get_extension_list_config_file();
static String find_extension_library(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature, PackedStringArray *r_tags = nullptr);

Error open_library(const String &p_path, const String &p_entry_symbol);
Error open_library(const String &p_path, const String &p_entry_symbol, bool p_use_legacy_interface = false);
Error open_library_compat_76406(const String &p_path, const String &p_entry_symbol);
void close_library();

enum InitializationLevel {
Expand All @@ -88,7 +89,10 @@ class GDExtension : public Resource {
void initialize_library(InitializationLevel p_level);
void deinitialize_library(InitializationLevel p_level);

static void register_interface_function(StringName p_function_name, GDExtensionInterfaceFunctionPtr p_function_pointer);
static GDExtensionInterfaceFunctionPtr get_interface_function(StringName p_function_name);
static void initialize_gdextensions();

GDExtension();
~GDExtension();
};
Expand Down
Loading

0 comments on commit a8453cb

Please sign in to comment.