Sfoglia il codice sorgente

Add ValidatedCall to MethodBind

* 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.
Juan Linietsky 2 anni fa
parent
commit
1c93606e47

+ 3 - 2
core/core_bind.cpp

@@ -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;
 	}
 

+ 1 - 1
core/core_bind.h

@@ -323,7 +323,7 @@ public:
 
 	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);
 

+ 38 - 1
core/extension/gdextension.cpp

@@ -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;
@@ -191,6 +193,40 @@ public:
 		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();
@@ -204,6 +240,7 @@ public:
 	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));
 
@@ -218,7 +255,7 @@ public:
 		}
 
 		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);

+ 1 - 0
core/extension/gdextension_interface.h

@@ -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 {

+ 48 - 1
core/object/method_bind.h

@@ -112,6 +112,8 @@ public:
 	_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;
@@ -162,8 +164,12 @@ public:
 	}
 #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; }
@@ -253,6 +259,7 @@ public:
 	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
@@ -326,6 +333,14 @@ public:
 		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);
@@ -393,6 +408,14 @@ public:
 		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);
@@ -471,6 +494,14 @@ public:
 		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);
@@ -550,6 +581,14 @@ public:
 		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);
@@ -614,6 +653,10 @@ public:
 		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;
@@ -677,6 +720,10 @@ public:
 		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);

+ 2 - 2
core/object/object.cpp

@@ -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);

+ 1 - 1
core/object/object.h

@@ -717,7 +717,7 @@ protected:
 		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;
 

+ 12 - 0
core/object/ref_counted.h

@@ -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

+ 86 - 42
core/variant/binder_common.h

@@ -83,50 +83,60 @@ struct VariantCaster<const T &> {
 	}
 };
 
-#define VARIANT_ENUM_CAST(m_enum)                                            \
-	MAKE_ENUM_TYPE_INFO(m_enum)                                              \
-	template <>                                                              \
-	struct VariantCaster<m_enum> {                                           \
-		static _FORCE_INLINE_ m_enum cast(const Variant &p_variant) {        \
-			return (m_enum)p_variant.operator int64_t();                     \
-		}                                                                    \
-	};                                                                       \
-	template <>                                                              \
-	struct PtrToArg<m_enum> {                                                \
-		_FORCE_INLINE_ static m_enum convert(const void *p_ptr) {            \
-			return m_enum(*reinterpret_cast<const int64_t *>(p_ptr));        \
-		}                                                                    \
-		typedef int64_t EncodeT;                                             \
-		_FORCE_INLINE_ static void encode(m_enum p_val, const void *p_ptr) { \
-			*(int64_t *)p_ptr = (int64_t)p_val;                              \
-		}                                                                    \
-	};                                                                       \
-	template <>                                                              \
-	struct ZeroInitializer<m_enum> {                                         \
-		static void initialize(m_enum &value) { value = (m_enum)0; }         \
+#define VARIANT_ENUM_CAST(m_enum)                                                                                       \
+	MAKE_ENUM_TYPE_INFO(m_enum)                                                                                         \
+	template <>                                                                                                         \
+	struct VariantCaster<m_enum> {                                                                                      \
+		static _FORCE_INLINE_ m_enum cast(const Variant &p_variant) {                                                   \
+			return (m_enum)p_variant.operator int64_t();                                                                \
+		}                                                                                                               \
+	};                                                                                                                  \
+	template <>                                                                                                         \
+	struct PtrToArg<m_enum> {                                                                                           \
+		_FORCE_INLINE_ static m_enum convert(const void *p_ptr) {                                                       \
+			return m_enum(*reinterpret_cast<const int64_t *>(p_ptr));                                                   \
+		}                                                                                                               \
+		typedef int64_t EncodeT;                                                                                        \
+		_FORCE_INLINE_ static void encode(m_enum p_val, const void *p_ptr) {                                            \
+			*(int64_t *)p_ptr = (int64_t)p_val;                                                                         \
+		}                                                                                                               \
+	};                                                                                                                  \
+	template <>                                                                                                         \
+	struct ZeroInitializer<m_enum> {                                                                                    \
+		static void initialize(m_enum &value) { value = (m_enum)0; }                                                    \
+	};                                                                                                                  \
+	template <>                                                                                                         \
+	struct VariantInternalAccessor<m_enum> {                                                                            \
+		static _FORCE_INLINE_ m_enum get(const Variant *v) { return m_enum(*VariantInternal::get_int(v)); }             \
+		static _FORCE_INLINE_ void set(Variant *v, m_enum p_value) { *VariantInternal::get_int(v) = (int64_t)p_value; } \
 	};
 
-#define VARIANT_BITFIELD_CAST(m_enum)                                                  \
-	MAKE_BITFIELD_TYPE_INFO(m_enum)                                                    \
-	template <>                                                                        \
-	struct VariantCaster<BitField<m_enum>> {                                           \
-		static _FORCE_INLINE_ BitField<m_enum> cast(const Variant &p_variant) {        \
-			return BitField<m_enum>(p_variant.operator int64_t());                     \
-		}                                                                              \
-	};                                                                                 \
-	template <>                                                                        \
-	struct PtrToArg<BitField<m_enum>> {                                                \
-		_FORCE_INLINE_ static BitField<m_enum> convert(const void *p_ptr) {            \
-			return BitField<m_enum>(*reinterpret_cast<const int64_t *>(p_ptr));        \
-		}                                                                              \
-		typedef int64_t EncodeT;                                                       \
-		_FORCE_INLINE_ static void encode(BitField<m_enum> p_val, const void *p_ptr) { \
-			*(int64_t *)p_ptr = p_val;                                                 \
-		}                                                                              \
-	};                                                                                 \
-	template <>                                                                        \
-	struct ZeroInitializer<BitField<m_enum>> {                                         \
-		static void initialize(BitField<m_enum> &value) { value = 0; }                 \
+#define VARIANT_BITFIELD_CAST(m_enum)                                                                                                       \
+	MAKE_BITFIELD_TYPE_INFO(m_enum)                                                                                                         \
+	template <>                                                                                                                             \
+	struct VariantCaster<BitField<m_enum>> {                                                                                                \
+		static _FORCE_INLINE_ BitField<m_enum> cast(const Variant &p_variant) {                                                             \
+			return BitField<m_enum>(p_variant.operator int64_t());                                                                          \
+		}                                                                                                                                   \
+	};                                                                                                                                      \
+	template <>                                                                                                                             \
+	struct PtrToArg<BitField<m_enum>> {                                                                                                     \
+		_FORCE_INLINE_ static BitField<m_enum> convert(const void *p_ptr) {                                                                 \
+			return BitField<m_enum>(*reinterpret_cast<const int64_t *>(p_ptr));                                                             \
+		}                                                                                                                                   \
+		typedef int64_t EncodeT;                                                                                                            \
+		_FORCE_INLINE_ static void encode(BitField<m_enum> p_val, const void *p_ptr) {                                                      \
+			*(int64_t *)p_ptr = p_val;                                                                                                      \
+		}                                                                                                                                   \
+	};                                                                                                                                      \
+	template <>                                                                                                                             \
+	struct ZeroInitializer<BitField<m_enum>> {                                                                                              \
+		static void initialize(BitField<m_enum> &value) { value = 0; }                                                                      \
+	};                                                                                                                                      \
+	template <>                                                                                                                             \
+	struct VariantInternalAccessor<BitField<m_enum>> {                                                                                      \
+		static _FORCE_INLINE_ BitField<m_enum> get(const Variant *v) { return BitField<m_enum>(*VariantInternal::get_int(v)); }             \
+		static _FORCE_INLINE_ void set(Variant *v, BitField<m_enum> p_value) { *VariantInternal::get_int(v) = p_value.operator int64_t(); } \
 	};
 
 // Object enum casts must go here
@@ -597,6 +607,8 @@ void call_with_ptr_args_static_method(void (*p_method)(P...), const void **p_arg
 	call_with_ptr_args_static_method_helper<P...>(p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
 }
 
+// Validated
+
 template <class T, class... P>
 void call_with_validated_variant_args(Variant *base, void (T::*p_method)(P...), const Variant **p_args) {
 	call_with_validated_variant_args_helper<T, P...>(VariantGetInternalPtr<T>::get_ptr(base), p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
@@ -632,6 +644,38 @@ void call_with_validated_variant_args_static_method_ret(R (*p_method)(P...), con
 	call_with_validated_variant_args_static_method_ret_helper<R, P...>(p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
 }
 
+// Validated Object
+
+template <class T, class... P>
+void call_with_validated_object_instance_args(T *base, void (T::*p_method)(P...), const Variant **p_args) {
+	call_with_validated_variant_args_helper<T, P...>(base, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class... P>
+void call_with_validated_object_instance_argsc(T *base, void (T::*p_method)(P...) const, const Variant **p_args) {
+	call_with_validated_variant_argsc_helper<T, P...>(base, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class R, class... P>
+void call_with_validated_object_instance_args_ret(T *base, R (T::*p_method)(P...), const Variant **p_args, Variant *r_ret) {
+	call_with_validated_variant_args_ret_helper<T, R, P...>(base, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class R, class... P>
+void call_with_validated_object_instance_args_retc(T *base, R (T::*p_method)(P...) const, const Variant **p_args, Variant *r_ret) {
+	call_with_validated_variant_args_retc_helper<T, R, P...>(base, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class... P>
+void call_with_validated_object_instance_args_static(T *base, void (*p_method)(T *, P...), const Variant **p_args) {
+	call_with_validated_variant_args_static_helper<T, P...>(base, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class R, class... P>
+void call_with_validated_object_instance_args_static_retc(T *base, R (*p_method)(T *, P...), const Variant **p_args, Variant *r_ret) {
+	call_with_validated_variant_args_static_retc_helper<T, R, P...>(base, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
+}
+
 // GCC raises "parameter 'p_args' set but not used" when P = {},
 // it's not clever enough to treat other P values as making this branch valid.
 #if defined(__GNUC__) && !defined(__clang__)

+ 14 - 0
core/variant/typed_array.h

@@ -33,6 +33,7 @@
 
 #include "core/object/object.h"
 #include "core/variant/array.h"
+#include "core/variant/binder_common.h"
 #include "core/variant/method_ptrcall.h"
 #include "core/variant/type_info.h"
 #include "core/variant/variant.h"
@@ -55,6 +56,17 @@ public:
 	}
 };
 
+template <class T>
+struct VariantInternalAccessor<TypedArray<T>> {
+	static _FORCE_INLINE_ TypedArray<T> get(const Variant *v) { return *VariantInternal::get_array(v); }
+	static _FORCE_INLINE_ void set(Variant *v, const TypedArray<T> &p_array) { *VariantInternal::get_array(v) = p_array; }
+};
+template <class T>
+struct VariantInternalAccessor<const TypedArray<T> &> {
+	static _FORCE_INLINE_ TypedArray<T> get(const Variant *v) { return *VariantInternal::get_array(v); }
+	static _FORCE_INLINE_ void set(Variant *v, const TypedArray<T> &p_array) { *VariantInternal::get_array(v) = p_array; }
+};
+
 //specialization for the rest of variant types
 
 #define MAKE_TYPED_ARRAY(m_type, m_variant_type)                                                                 \
@@ -117,6 +129,7 @@ MAKE_TYPED_ARRAY(Vector<String>, Variant::PACKED_STRING_ARRAY)
 MAKE_TYPED_ARRAY(Vector<Vector2>, Variant::PACKED_VECTOR2_ARRAY)
 MAKE_TYPED_ARRAY(Vector<Vector3>, Variant::PACKED_VECTOR3_ARRAY)
 MAKE_TYPED_ARRAY(Vector<Color>, Variant::PACKED_COLOR_ARRAY)
+MAKE_TYPED_ARRAY(IPAddress, Variant::STRING)
 
 template <class T>
 struct PtrToArg<TypedArray<T>> {
@@ -215,5 +228,6 @@ MAKE_TYPED_ARRAY_INFO(Vector<String>, Variant::PACKED_STRING_ARRAY)
 MAKE_TYPED_ARRAY_INFO(Vector<Vector2>, Variant::PACKED_VECTOR2_ARRAY)
 MAKE_TYPED_ARRAY_INFO(Vector<Vector3>, Variant::PACKED_VECTOR3_ARRAY)
 MAKE_TYPED_ARRAY_INFO(Vector<Color>, Variant::PACKED_COLOR_ARRAY)
+MAKE_TYPED_ARRAY_INFO(IPAddress, Variant::STRING)
 
 #endif // TYPED_ARRAY_H

+ 11 - 0
core/variant/variant_construct.cpp

@@ -317,6 +317,17 @@ String Variant::get_constructor_argument_name(Variant::Type p_type, int p_constr
 	return construct_data[p_type][p_constructor].arg_names[p_argument];
 }
 
+void VariantInternal::refcounted_object_assign(Variant *v, const RefCounted *rc) {
+	if (!rc || !const_cast<RefCounted *>(rc)->init_ref()) {
+		v->_get_obj().obj = nullptr;
+		v->_get_obj().id = ObjectID();
+		return;
+	}
+
+	v->_get_obj().obj = const_cast<RefCounted *>(rc);
+	v->_get_obj().id = rc->get_instance_id();
+}
+
 void VariantInternal::object_assign(Variant *v, const Object *o) {
 	if (o) {
 		if (o->is_ref_counted()) {

+ 21 - 17
core/variant/variant_internal.h

@@ -35,6 +35,9 @@
 
 // For use when you want to access the internal pointer of a Variant directly.
 // Use with caution. You need to be sure that the type is correct.
+
+class RefCounted;
+
 class VariantInternal {
 	friend class Variant;
 
@@ -320,6 +323,7 @@ public:
 	}
 
 	static void object_assign(Variant *v, const Object *o); // Needs RefCounted, so it's implemented elsewhere.
+	static void refcounted_object_assign(Variant *v, const RefCounted *rc);
 
 	_FORCE_INLINE_ static void object_assign(Variant *v, const Variant *o) {
 		object_assign(v, o->_get_obj().obj);
@@ -820,28 +824,28 @@ VARIANT_ACCESSOR_NUMBER(int64_t)
 VARIANT_ACCESSOR_NUMBER(uint64_t)
 VARIANT_ACCESSOR_NUMBER(char32_t)
 
-// Bind enums to allow using them as return types.
-VARIANT_ACCESSOR_NUMBER(Error)
-VARIANT_ACCESSOR_NUMBER(Side)
-VARIANT_ACCESSOR_NUMBER(Vector2::Axis)
-VARIANT_ACCESSOR_NUMBER(Vector2i::Axis)
-VARIANT_ACCESSOR_NUMBER(Vector3::Axis)
-VARIANT_ACCESSOR_NUMBER(Vector3i::Axis)
-VARIANT_ACCESSOR_NUMBER(Vector4::Axis)
-VARIANT_ACCESSOR_NUMBER(Vector4i::Axis)
+template <>
+struct VariantInternalAccessor<ObjectID> {
+	static _FORCE_INLINE_ ObjectID get(const Variant *v) { return ObjectID(*VariantInternal::get_int(v)); }
+	static _FORCE_INLINE_ void set(Variant *v, ObjectID p_value) { *VariantInternal::get_int(v) = p_value; }
+};
 
-VARIANT_ACCESSOR_NUMBER(Projection::Planes)
+template <class T>
+struct VariantInternalAccessor<T *> {
+	static _FORCE_INLINE_ T *get(const Variant *v) { return const_cast<T *>(static_cast<const T *>(*VariantInternal::get_object(v))); }
+	static _FORCE_INLINE_ void set(Variant *v, const T *p_value) { VariantInternal::object_assign(v, p_value); }
+};
 
-template <>
-struct VariantInternalAccessor<EulerOrder> {
-	static _FORCE_INLINE_ EulerOrder get(const Variant *v) { return EulerOrder(*VariantInternal::get_int(v)); }
-	static _FORCE_INLINE_ void set(Variant *v, EulerOrder p_value) { *VariantInternal::get_int(v) = (int64_t)p_value; }
+template <class T>
+struct VariantInternalAccessor<const T *> {
+	static _FORCE_INLINE_ const T *get(const Variant *v) { return static_cast<const T *>(*VariantInternal::get_object(v)); }
+	static _FORCE_INLINE_ void set(Variant *v, const T *p_value) { VariantInternal::object_assign(v, p_value); }
 };
 
 template <>
-struct VariantInternalAccessor<ObjectID> {
-	static _FORCE_INLINE_ ObjectID get(const Variant *v) { return ObjectID(*VariantInternal::get_int(v)); }
-	static _FORCE_INLINE_ void set(Variant *v, ObjectID p_value) { *VariantInternal::get_int(v) = p_value; }
+struct VariantInternalAccessor<IPAddress> {
+	static _FORCE_INLINE_ IPAddress get(const Variant *v) { return IPAddress(*VariantInternal::get_string(v)); }
+	static _FORCE_INLINE_ void set(Variant *v, IPAddress p_value) { *VariantInternal::get_string(v) = p_value; }
 };
 
 template <>

+ 1 - 1
doc/classes/AnimationNodeStateMachinePlayback.xml

@@ -48,7 +48,7 @@
 			</description>
 		</method>
 		<method name="get_travel_path" qualifiers="const">
-			<return type="PackedStringArray" />
+			<return type="StringName[]" />
 			<description>
 				Returns the current travel path as computed internally by the A* algorithm.
 			</description>

+ 1 - 1
doc/classes/Geometry3D.xml

@@ -88,7 +88,7 @@
 			<return type="PackedVector3Array" />
 			<param index="0" name="from" type="Vector3" />
 			<param index="1" name="to" type="Vector3" />
-			<param index="2" name="planes" type="Array" />
+			<param index="2" name="planes" type="Plane[]" />
 			<description>
 				Given a convex hull defined though the [Plane]s in the array [param planes], tests if the segment ([param from], [param to]) intersects with that hull. If an intersection is found, returns a [PackedVector3Array] containing the point the intersection and the hull's normal. Otherwise, returns an empty array.
 			</description>

+ 1 - 1
doc/classes/Object.xml

@@ -597,7 +597,7 @@
 			</description>
 		</method>
 		<method name="get_meta_list" qualifiers="const">
-			<return type="PackedStringArray" />
+			<return type="StringName[]" />
 			<description>
 				Returns the object's metadata entry names as a [PackedStringArray].
 			</description>

+ 1 - 1
doc/classes/RDShaderFile.xml

@@ -14,7 +14,7 @@
 			</description>
 		</method>
 		<method name="get_version_list" qualifiers="const">
-			<return type="PackedStringArray" />
+			<return type="StringName[]" />
 			<description>
 			</description>
 		</method>

+ 1 - 1
doc/classes/RenderingDevice.xml

@@ -152,7 +152,7 @@
 			<param index="6" name="clear_depth" type="float" default="1.0" />
 			<param index="7" name="clear_stencil" type="int" default="0" />
 			<param index="8" name="region" type="Rect2" default="Rect2(0, 0, 0, 0)" />
-			<param index="9" name="storage_textures" type="Array" default="[]" />
+			<param index="9" name="storage_textures" type="RID[]" default="[]" />
 			<description>
 			</description>
 		</method>

+ 1 - 1
doc/classes/RenderingServer.xml

@@ -1419,7 +1419,7 @@
 			</description>
 		</method>
 		<method name="global_shader_parameter_get_list" qualifiers="const">
-			<return type="PackedStringArray" />
+			<return type="StringName[]" />
 			<description>
 			</description>
 		</method>

+ 1 - 1
doc/classes/SurfaceTool.xml

@@ -45,7 +45,7 @@
 			<param index="2" name="colors" type="PackedColorArray" default="PackedColorArray()" />
 			<param index="3" name="uv2s" type="PackedVector2Array" default="PackedVector2Array()" />
 			<param index="4" name="normals" type="PackedVector3Array" default="PackedVector3Array()" />
-			<param index="5" name="tangents" type="Array" default="[]" />
+			<param index="5" name="tangents" type="Plane[]" default="[]" />
 			<description>
 				Inserts a triangle fan made of array data into [Mesh] being constructed.
 				Requires the primitive type be set to [constant Mesh.PRIMITIVE_TRIANGLES].

+ 1 - 1
editor/plugins/shader_file_editor_plugin.cpp

@@ -124,7 +124,7 @@ void ShaderFileEditor::_update_options() {
 	int c = versions->get_current();
 	//remember current
 	versions->clear();
-	Vector<StringName> version_list = shader_file->get_version_list();
+	TypedArray<StringName> version_list = shader_file->get_version_list();
 
 	if (c >= version_list.size()) {
 		c = version_list.size() - 1;

+ 5 - 1
scene/animation/animation_node_state_machine.cpp

@@ -305,6 +305,10 @@ Vector<StringName> AnimationNodeStateMachinePlayback::get_travel_path() const {
 	return path;
 }
 
+TypedArray<StringName> AnimationNodeStateMachinePlayback::_get_travel_path() const {
+	return Variant(get_travel_path()).operator Array();
+}
+
 float AnimationNodeStateMachinePlayback::get_current_play_pos() const {
 	return pos_current;
 }
@@ -1180,7 +1184,7 @@ void AnimationNodeStateMachinePlayback::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_current_play_position"), &AnimationNodeStateMachinePlayback::get_current_play_pos);
 	ClassDB::bind_method(D_METHOD("get_current_length"), &AnimationNodeStateMachinePlayback::get_current_length);
 	ClassDB::bind_method(D_METHOD("get_fading_from_node"), &AnimationNodeStateMachinePlayback::get_fading_from_node);
-	ClassDB::bind_method(D_METHOD("get_travel_path"), &AnimationNodeStateMachinePlayback::get_travel_path);
+	ClassDB::bind_method(D_METHOD("get_travel_path"), &AnimationNodeStateMachinePlayback::_get_travel_path);
 }
 
 AnimationNodeStateMachinePlayback::AnimationNodeStateMachinePlayback() {

+ 2 - 0
scene/animation/animation_node_state_machine.h

@@ -314,6 +314,8 @@ class AnimationNodeStateMachinePlayback : public Resource {
 	Ref<AnimationNodeStateMachineTransition> _get_group_start_transition() const;
 	Ref<AnimationNodeStateMachineTransition> _get_group_end_transition() const;
 
+	TypedArray<StringName> _get_travel_path() const;
+
 protected:
 	static void _bind_methods();
 

+ 5 - 1
scene/resources/mesh.cpp

@@ -499,6 +499,10 @@ void Mesh::generate_debug_mesh_indices(Vector<Vector3> &r_points) {
 	}
 }
 
+Vector<Vector3> Mesh::_get_faces() const {
+	return Variant(get_faces());
+}
+
 Vector<Face3> Mesh::get_faces() const {
 	Ref<TriangleMesh> tm = generate_triangle_mesh();
 	if (tm.is_valid()) {
@@ -793,6 +797,7 @@ void Mesh::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_lightmap_size_hint", "size"), &Mesh::set_lightmap_size_hint);
 	ClassDB::bind_method(D_METHOD("get_lightmap_size_hint"), &Mesh::get_lightmap_size_hint);
 	ClassDB::bind_method(D_METHOD("get_aabb"), &Mesh::get_aabb);
+	ClassDB::bind_method(D_METHOD("get_faces"), &Mesh::_get_faces);
 
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "lightmap_size_hint"), "set_lightmap_size_hint", "get_lightmap_size_hint");
 
@@ -2245,7 +2250,6 @@ void ArrayMesh::_bind_methods() {
 	ClassDB::set_method_flags(get_class_static(), _scs_create("regen_normal_maps"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
 	ClassDB::bind_method(D_METHOD("lightmap_unwrap", "transform", "texel_size"), &ArrayMesh::lightmap_unwrap);
 	ClassDB::set_method_flags(get_class_static(), _scs_create("lightmap_unwrap"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
-	ClassDB::bind_method(D_METHOD("get_faces"), &ArrayMesh::get_faces);
 	ClassDB::bind_method(D_METHOD("generate_triangle_mesh"), &ArrayMesh::generate_triangle_mesh);
 
 	ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &ArrayMesh::set_custom_aabb);

+ 2 - 0
scene/resources/mesh.h

@@ -50,6 +50,8 @@ class Mesh : public Resource {
 	mutable Vector<Vector3> debug_lines;
 	Size2i lightmap_size_hint;
 
+	Vector<Vector3> _get_faces() const;
+
 public:
 	enum PrimitiveType {
 		PRIMITIVE_POINTS = RenderingServer::PRIMITIVE_POINTS,

+ 5 - 1
scene/resources/surface_tool.cpp

@@ -374,6 +374,10 @@ void SurfaceTool::set_smooth_group(uint32_t p_group) {
 	last_smooth_group = p_group;
 }
 
+void SurfaceTool::_add_triangle_fan(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uvs, const Vector<Color> &p_colors, const Vector<Vector2> &p_uv2s, const Vector<Vector3> &p_normals, const TypedArray<Plane> &p_tangents) {
+	add_triangle_fan(p_vertices, p_uv2s, p_colors, p_uv2s, p_normals, Variant(p_tangents));
+}
+
 void SurfaceTool::add_triangle_fan(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uvs, const Vector<Color> &p_colors, const Vector<Vector2> &p_uv2s, const Vector<Vector3> &p_normals, const Vector<Plane> &p_tangents) {
 	ERR_FAIL_COND(!begun);
 	ERR_FAIL_COND(primitive != Mesh::PRIMITIVE_TRIANGLES);
@@ -1335,7 +1339,7 @@ void SurfaceTool::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_custom", "channel_index", "custom_color"), &SurfaceTool::set_custom);
 	ClassDB::bind_method(D_METHOD("set_smooth_group", "index"), &SurfaceTool::set_smooth_group);
 
-	ClassDB::bind_method(D_METHOD("add_triangle_fan", "vertices", "uvs", "colors", "uv2s", "normals", "tangents"), &SurfaceTool::add_triangle_fan, DEFVAL(Vector<Vector2>()), DEFVAL(Vector<Color>()), DEFVAL(Vector<Vector2>()), DEFVAL(Vector<Vector3>()), DEFVAL(Vector<Plane>()));
+	ClassDB::bind_method(D_METHOD("add_triangle_fan", "vertices", "uvs", "colors", "uv2s", "normals", "tangents"), &SurfaceTool::_add_triangle_fan, DEFVAL(Vector<Vector2>()), DEFVAL(Vector<Color>()), DEFVAL(Vector<Vector2>()), DEFVAL(Vector<Vector3>()), DEFVAL(TypedArray<Plane>()));
 
 	ClassDB::bind_method(D_METHOD("add_index", "index"), &SurfaceTool::add_index);
 

+ 2 - 0
scene/resources/surface_tool.h

@@ -167,6 +167,8 @@ private:
 	static void mikktSetTSpaceDefault(const SMikkTSpaceContext *pContext, const float fvTangent[], const float fvBiTangent[], const float fMagS, const float fMagT,
 			const tbool bIsOrientationPreserving, const int iFace, const int iVert);
 
+	void _add_triangle_fan(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uvs = Vector<Vector2>(), const Vector<Color> &p_colors = Vector<Color>(), const Vector<Vector2> &p_uv2s = Vector<Vector2>(), const Vector<Vector3> &p_normals = Vector<Vector3>(), const TypedArray<Plane> &p_tangents = TypedArray<Plane>());
+
 protected:
 	static void _bind_methods();
 

+ 9 - 1
servers/rendering/rendering_device.cpp

@@ -334,6 +334,14 @@ RID RenderingDevice::_compute_pipeline_create(RID p_shader, const TypedArray<RDP
 	return compute_pipeline_create(p_shader, _get_spec_constants(p_specialization_constants));
 }
 
+RenderingDevice::DrawListID RenderingDevice::_draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const TypedArray<RID> &p_storage_textures) {
+	Vector<RID> stextures;
+	for (int i = 0; i < p_storage_textures.size(); i++) {
+		stextures.push_back(p_storage_textures[i]);
+	}
+	return draw_list_begin(p_framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, stextures);
+}
+
 Vector<int64_t> RenderingDevice::_draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const TypedArray<RID> &p_storage_textures) {
 	Vector<DrawListID> splits;
 	splits.resize(p_splits);
@@ -760,7 +768,7 @@ void RenderingDevice::_bind_methods() {
 
 	ClassDB::bind_method(D_METHOD("draw_list_begin_for_screen", "screen", "clear_color"), &RenderingDevice::draw_list_begin_for_screen, DEFVAL(DisplayServer::MAIN_WINDOW_ID), DEFVAL(Color()));
 
-	ClassDB::bind_method(D_METHOD("draw_list_begin", "framebuffer", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "storage_textures"), &RenderingDevice::draw_list_begin, DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()), DEFVAL(TypedArray<RID>()));
+	ClassDB::bind_method(D_METHOD("draw_list_begin", "framebuffer", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "storage_textures"), &RenderingDevice::_draw_list_begin, DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()), DEFVAL(TypedArray<RID>()));
 	ClassDB::bind_method(D_METHOD("draw_list_begin_split", "framebuffer", "splits", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "storage_textures"), &RenderingDevice::_draw_list_begin_split, DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()), DEFVAL(TypedArray<RID>()));
 
 	ClassDB::bind_method(D_METHOD("draw_list_set_blend_constants", "draw_list", "color"), &RenderingDevice::draw_list_set_blend_constants);

+ 1 - 0
servers/rendering/rendering_device.h

@@ -1329,6 +1329,7 @@ protected:
 	RID _render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, BitField<PipelineDynamicStateFlags> p_dynamic_state_flags, uint32_t p_for_render_pass, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants);
 	RID _compute_pipeline_create(RID p_shader, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants);
 
+	DrawListID _draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const TypedArray<RID> &p_storage_textures = TypedArray<RID>());
 	Vector<int64_t> _draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const TypedArray<RID> &p_storage_textures = TypedArray<RID>());
 	void _draw_list_set_push_constant(DrawListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size);
 	void _compute_list_set_push_constant(ComputeListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size);

+ 8 - 3
servers/rendering/rendering_device_binds.h

@@ -349,13 +349,18 @@ public:
 		return versions[p_version]->get_stages();
 	}
 
-	Vector<StringName> get_version_list() const {
+	TypedArray<StringName> get_version_list() const {
 		Vector<StringName> vnames;
 		for (const KeyValue<StringName, Ref<RDShaderSPIRV>> &E : versions) {
 			vnames.push_back(E.key);
 		}
 		vnames.sort_custom<StringName::AlphCompare>();
-		return vnames;
+		TypedArray<StringName> ret;
+		ret.resize(vnames.size());
+		for (int i = 0; i < vnames.size(); i++) {
+			ret[i] = vnames[i];
+		}
+		return ret;
 	}
 
 	void set_base_error(const String &p_error) {
@@ -395,7 +400,7 @@ public:
 
 protected:
 	Dictionary _get_versions() const {
-		Vector<StringName> vnames = get_version_list();
+		TypedArray<StringName> vnames = get_version_list();
 		Dictionary ret;
 		for (int i = 0; i < vnames.size(); i++) {
 			ret[vnames[i]] = versions[vnames[i]];

+ 11 - 1
servers/rendering_server.cpp

@@ -2716,7 +2716,7 @@ void RenderingServer::_bind_methods() {
 
 	ClassDB::bind_method(D_METHOD("global_shader_parameter_add", "name", "type", "default_value"), &RenderingServer::global_shader_parameter_add);
 	ClassDB::bind_method(D_METHOD("global_shader_parameter_remove", "name"), &RenderingServer::global_shader_parameter_remove);
-	ClassDB::bind_method(D_METHOD("global_shader_parameter_get_list"), &RenderingServer::global_shader_parameter_get_list);
+	ClassDB::bind_method(D_METHOD("global_shader_parameter_get_list"), &RenderingServer::_global_shader_parameter_get_list);
 	ClassDB::bind_method(D_METHOD("global_shader_parameter_set", "name", "value"), &RenderingServer::global_shader_parameter_set);
 	ClassDB::bind_method(D_METHOD("global_shader_parameter_set_override", "name", "value"), &RenderingServer::global_shader_parameter_set_override);
 	ClassDB::bind_method(D_METHOD("global_shader_parameter_get", "name"), &RenderingServer::global_shader_parameter_get);
@@ -2855,6 +2855,16 @@ RenderingServer::RenderingServer() {
 	singleton = this;
 }
 
+TypedArray<StringName> RenderingServer::_global_shader_parameter_get_list() const {
+	TypedArray<StringName> gsp;
+	Vector<StringName> gsp_sn = global_shader_parameter_get_list();
+	gsp.resize(gsp_sn.size());
+	for (int i = 0; i < gsp_sn.size(); i++) {
+		gsp[i] = gsp_sn[i];
+	}
+	return gsp;
+}
+
 void RenderingServer::init() {
 	GLOBAL_DEF_RST_NOVAL_BASIC("rendering/textures/vram_compression/import_s3tc_bptc", OS::get_singleton()->get_preferred_texture_format() == OS::PREFERRED_TEXTURE_FORMAT_S3TC_BPTC);
 	GLOBAL_DEF_RST_NOVAL_BASIC("rendering/textures/vram_compression/import_etc2_astc", OS::get_singleton()->get_preferred_texture_format() == OS::PREFERRED_TEXTURE_FORMAT_ETC2_ASTC);

+ 2 - 0
servers/rendering_server.h

@@ -57,6 +57,8 @@ class RenderingServer : public Object {
 	const Vector2 SMALL_VEC2 = Vector2(CMP_EPSILON, CMP_EPSILON);
 	const Vector3 SMALL_VEC3 = Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON);
 
+	virtual TypedArray<StringName> _global_shader_parameter_get_list() const;
+
 protected:
 	RID _make_test_cube();
 	void _free_internal_rids();