Skip to content

Commit

Permalink
Add ValidatedCall to MethodBind
Browse files Browse the repository at this point in the history
* This should optimize GDScript function calling _enormously_.
* It also should simplify the GDScript VM considerably.

NOTE: GDExtension calling performance has most likely been affected until going via ptrcall is fixed.
  • Loading branch information
reduz committed Apr 26, 2023
1 parent 14c582b commit 3050be1
Show file tree
Hide file tree
Showing 32 changed files with 310 additions and 84 deletions.
5 changes: 3 additions & 2 deletions core/core_bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -965,10 +965,11 @@ Vector<Vector3> Geometry3D::segment_intersects_cylinder(const Vector3 &p_from, c
return r;
}

Vector<Vector3> Geometry3D::segment_intersects_convex(const Vector3 &p_from, const Vector3 &p_to, const Vector<Plane> &p_planes) {
Vector<Vector3> Geometry3D::segment_intersects_convex(const Vector3 &p_from, const Vector3 &p_to, const TypedArray<Plane> &p_planes) {
Vector<Vector3> r;
Vector3 res, norm;
if (!::Geometry3D::segment_intersects_convex(p_from, p_to, p_planes.ptr(), p_planes.size(), &res, &norm)) {
Vector<Plane> planes = Variant(p_planes);
if (!::Geometry3D::segment_intersects_convex(p_from, p_to, planes.ptr(), planes.size(), &res, &norm)) {
return r;
}

Expand Down
2 changes: 1 addition & 1 deletion core/core_bind.h
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ class Geometry3D : public Object {

Vector<Vector3> segment_intersects_sphere(const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_sphere_pos, real_t p_sphere_radius);
Vector<Vector3> segment_intersects_cylinder(const Vector3 &p_from, const Vector3 &p_to, float p_height, float p_radius);
Vector<Vector3> segment_intersects_convex(const Vector3 &p_from, const Vector3 &p_to, const Vector<Plane> &p_planes);
Vector<Vector3> segment_intersects_convex(const Vector3 &p_from, const Vector3 &p_to, const TypedArray<Plane> &p_planes);

Vector<Vector3> clip_polygon(const Vector<Vector3> &p_points, const Plane &p_plane);

Expand Down
39 changes: 38 additions & 1 deletion core/extension/gdextension.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,11 @@ String GDExtension::find_extension_library(const String &p_path, Ref<ConfigFile>

class GDExtensionMethodBind : public MethodBind {
GDExtensionClassMethodCall call_func;
GDExtensionClassMethodValidatedCall validated_call_func;
GDExtensionClassMethodPtrCall ptrcall_func;
void *method_userdata;
bool vararg;
uint32_t argument_count;
PropertyInfo return_value_info;
GodotTypeInfo::Metadata return_value_metadata;
List<PropertyInfo> arguments_info;
Expand Down Expand Up @@ -191,6 +193,40 @@ class GDExtensionMethodBind : public MethodBind {
r_error.expected = ce.expected;
return ret;
}
virtual void validated_call(Object *p_object, const Variant **p_args, Variant *r_ret) const override {
ERR_FAIL_COND_MSG(vararg, "Validated methods don't have ptrcall support. This is most likely an engine bug.");
GDExtensionClassInstancePtr extension_instance = is_static() ? nullptr : p_object->_get_extension_instance();

if (validated_call_func) {
// This is added here, but it's unlikely to be provided by most extensions.
validated_call_func(method_userdata, extension_instance, reinterpret_cast<GDExtensionConstVariantPtr *>(p_args), (GDExtensionVariantPtr)r_ret);
} else {
#if 1
// Slow code-path, but works for the time being.
Callable::CallError ce;
call(p_object, p_args, argument_count, ce);
#else
// This is broken, because it needs more information to do the calling properly

// If not provided, go via ptrcall, which is faster than resorting to regular call.
const void **argptrs = (const void **)alloca(argument_count * sizeof(void *));
for (uint32_t i = 0; i < argument_count; i++) {
argptrs[i] = VariantInternal::get_opaque_pointer(p_args[i]);
}

bool returns = true;
void *ret_opaque;
if (returns) {
ret_opaque = VariantInternal::get_opaque_pointer(r_ret);
} else {
ret_opaque = nullptr; // May be unnecessary as this is ignored, but just in case.
}

ptrcall(p_object, argptrs, ret_opaque);
#endif
}
}

virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) const override {
ERR_FAIL_COND_MSG(vararg, "Vararg methods don't have ptrcall support. This is most likely an engine bug.");
GDExtensionClassInstancePtr extension_instance = p_object->_get_extension_instance();
Expand All @@ -204,6 +240,7 @@ class GDExtensionMethodBind : public MethodBind {
explicit GDExtensionMethodBind(const GDExtensionClassMethodInfo *p_method_info) {
method_userdata = p_method_info->method_userdata;
call_func = p_method_info->call_func;
validated_call_func = nullptr;
ptrcall_func = p_method_info->ptrcall_func;
set_name(*reinterpret_cast<StringName *>(p_method_info->name));

Expand All @@ -218,7 +255,7 @@ class GDExtensionMethodBind : public MethodBind {
}

set_hint_flags(p_method_info->method_flags);

argument_count = p_method_info->argument_count;
vararg = p_method_info->method_flags & GDEXTENSION_METHOD_FLAG_VARARG;
_set_returns(p_method_info->has_return_value);
_set_const(p_method_info->method_flags & GDEXTENSION_METHOD_FLAG_CONST);
Expand Down
1 change: 1 addition & 0 deletions core/extension/gdextension_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ typedef enum {
} GDExtensionClassMethodArgumentMetadata;

typedef void (*GDExtensionClassMethodCall)(void *method_userdata, GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error);
typedef void (*GDExtensionClassMethodValidatedCall)(void *method_userdata, GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionVariantPtr r_return);
typedef void (*GDExtensionClassMethodPtrCall)(void *method_userdata, GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret);

typedef struct {
Expand Down
49 changes: 48 additions & 1 deletion core/object/method_bind.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ class MethodBind {
_FORCE_INLINE_ int get_argument_count() const { return argument_count; };

virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) const = 0;
virtual void validated_call(Object *p_object, const Variant **p_args, Variant *r_ret) const = 0;

virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) const = 0;

StringName get_name() const;
Expand Down Expand Up @@ -162,8 +164,12 @@ class MethodBindVarArgBase : public MethodBind {
}
#endif

virtual void validated_call(Object *p_object, const Variant **p_args, Variant *r_ret) const override {
ERR_FAIL_MSG("Validated call can't be used with vararg methods. This is a bug.");
}

virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) const override {
ERR_FAIL(); // Can't call.
ERR_FAIL_MSG("ptrcall can't be used with vararg methods. This is a bug.");
}

virtual bool is_const() const { return false; }
Expand Down Expand Up @@ -253,6 +259,7 @@ class MethodBindVarArgTR : public MethodBindVarArgBase<MethodBindVarArgTR<T, R>,
virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) const override {
return (static_cast<T *>(p_object)->*MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>::method)(p_args, p_arg_count, r_error);
}

#if defined(SANITIZERS_ENABLED) && defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
Expand Down Expand Up @@ -326,6 +333,14 @@ class MethodBindT : public MethodBind {
return Variant();
}

virtual void validated_call(Object *p_object, const Variant **p_args, Variant *r_ret) const override {
#ifdef TYPED_METHOD_BIND
call_with_validated_object_instance_args(static_cast<T *>(p_object), method, p_args);
#else
call_with_validated_object_instance_args(reinterpret_cast<MB_T *>(p_object), method, p_args);
#endif
}

virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) const override {
#ifdef TYPED_METHOD_BIND
call_with_ptr_args<T, P...>(static_cast<T *>(p_object), method, p_args);
Expand Down Expand Up @@ -393,6 +408,14 @@ class MethodBindTC : public MethodBind {
return Variant();
}

virtual void validated_call(Object *p_object, const Variant **p_args, Variant *r_ret) const override {
#ifdef TYPED_METHOD_BIND
call_with_validated_object_instance_argsc(static_cast<T *>(p_object), method, p_args);
#else
call_with_validated_object_instance_argsc(reinterpret_cast<MB_T *>(p_object), method, p_args);
#endif
}

virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) const override {
#ifdef TYPED_METHOD_BIND
call_with_ptr_argsc<T, P...>(static_cast<T *>(p_object), method, p_args);
Expand Down Expand Up @@ -471,6 +494,14 @@ class MethodBindTR : public MethodBind {
return ret;
}

virtual void validated_call(Object *p_object, const Variant **p_args, Variant *r_ret) const override {
#ifdef TYPED_METHOD_BIND
call_with_validated_object_instance_args_ret(static_cast<T *>(p_object), method, p_args, r_ret);
#else
call_with_validated_object_instance_args_ret(reinterpret_cast<MB_T *>(p_object), method, p_args, r_ret);
#endif
}

virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) const override {
#ifdef TYPED_METHOD_BIND
call_with_ptr_args_ret<T, R, P...>(static_cast<T *>(p_object), method, p_args, r_ret);
Expand Down Expand Up @@ -550,6 +581,14 @@ class MethodBindTRC : public MethodBind {
return ret;
}

virtual void validated_call(Object *p_object, const Variant **p_args, Variant *r_ret) const override {
#ifdef TYPED_METHOD_BIND
call_with_validated_object_instance_args_retc(static_cast<T *>(p_object), method, p_args, r_ret);
#else
call_with_validated_object_instance_args_retc(reinterpret_cast<MB_T *>(p_object), method, p_args, r_ret);
#endif
}

virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) const override {
#ifdef TYPED_METHOD_BIND
call_with_ptr_args_retc<T, R, P...>(static_cast<T *>(p_object), method, p_args, r_ret);
Expand Down Expand Up @@ -614,6 +653,10 @@ class MethodBindTS : public MethodBind {
return Variant();
}

virtual void validated_call(Object *p_object, const Variant **p_args, Variant *r_ret) const override {
call_with_validated_variant_args_static_method(function, p_args);
}

virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) const override {
(void)p_object;
(void)r_ret;
Expand Down Expand Up @@ -677,6 +720,10 @@ class MethodBindTRS : public MethodBind {
return ret;
}

virtual void validated_call(Object *p_object, const Variant **p_args, Variant *r_ret) const override {
call_with_validated_variant_args_static_method_ret(function, p_args, r_ret);
}

virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) const override {
(void)p_object;
call_with_ptr_args_static_method_ret(function, p_args, r_ret);
Expand Down
4 changes: 2 additions & 2 deletions core/object/object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -935,8 +935,8 @@ TypedArray<Dictionary> Object::_get_method_list_bind() const {
return ret;
}

Vector<StringName> Object::_get_meta_list_bind() const {
Vector<StringName> _metaret;
TypedArray<StringName> Object::_get_meta_list_bind() const {
TypedArray<StringName> _metaret;

for (const KeyValue<StringName, Variant> &K : metadata) {
_metaret.push_back(K.key);
Expand Down
2 changes: 1 addition & 1 deletion core/object/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,7 @@ class Object {
return &_class_name_static;
}

Vector<StringName> _get_meta_list_bind() const;
TypedArray<StringName> _get_meta_list_bind() const;
TypedArray<Dictionary> _get_property_list_bind() const;
TypedArray<Dictionary> _get_method_list_bind() const;

Expand Down
12 changes: 12 additions & 0 deletions core/object/ref_counted.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,4 +295,16 @@ struct GetTypeInfo<const Ref<T> &> {
}
};

template <class T>
struct VariantInternalAccessor<Ref<T>> {
static _FORCE_INLINE_ Ref<T> get(const Variant *v) { return Ref<T>(*VariantInternal::get_object(v)); }
static _FORCE_INLINE_ void set(Variant *v, const Ref<T> &p_ref) { VariantInternal::refcounted_object_assign(v, p_ref.ptr()); }
};

template <class T>
struct VariantInternalAccessor<const Ref<T> &> {
static _FORCE_INLINE_ Ref<T> get(const Variant *v) { return Ref<T>(*VariantInternal::get_object(v)); }
static _FORCE_INLINE_ void set(Variant *v, const Ref<T> &p_ref) { VariantInternal::refcounted_object_assign(v, p_ref.ptr()); }
};

#endif // REF_COUNTED_H
Loading

0 comments on commit 3050be1

Please sign in to comment.